zrepl/pruning/retentiongrid/retentiongrid.go

101 lines
2.3 KiB
Go
Raw Normal View History

2018-08-26 19:20:08 +02:00
package retentiongrid
2017-06-21 20:29:20 +02:00
import (
"sort"
"time"
)
2018-09-24 17:30:03 +02:00
type Interval interface {
2018-08-26 19:20:08 +02:00
Length() time.Duration
KeepCount() int
2017-06-21 20:29:20 +02:00
}
const RetentionGridKeepCountAll int = -1
2018-09-24 17:30:03 +02:00
type Grid struct {
intervals []Interval
2017-06-21 20:29:20 +02:00
}
2018-08-26 19:20:08 +02:00
//A point inside the grid, i.e. a thing the grid can decide to remove
2018-09-24 17:30:03 +02:00
type Entry interface {
2017-06-21 20:29:20 +02:00
Date() time.Time
2018-09-24 17:30:03 +02:00
LessThan(b Entry) bool
2017-06-21 20:29:20 +02:00
}
2018-09-24 17:30:03 +02:00
func dateInInterval(date, startDateInterval time.Time, i Interval) bool {
2018-08-26 19:20:08 +02:00
return date.After(startDateInterval) && date.Before(startDateInterval.Add(i.Length()))
2017-06-21 20:29:20 +02:00
}
2018-09-24 17:30:03 +02:00
func NewGrid(l []Interval) *Grid {
2017-06-21 20:29:20 +02:00
// TODO Maybe check for ascending interval lengths here, although the algorithm
// itself doesn't care about that.
2018-09-24 17:30:03 +02:00
return &Grid{l}
2017-06-21 20:29:20 +02:00
}
2018-09-24 17:30:03 +02:00
// Partition a list of RetentionGridEntries into the Grid,
2017-06-21 20:29:20 +02:00
// relative to a given start date `now`.
//
2018-09-24 17:30:03 +02:00
// The `keepCount` oldest entries per `retentiongrid.Interval` are kept (`keep`),
2017-06-21 20:29:20 +02:00
// the others are removed (`remove`).
//
// Entries that are younger than `now` are always kept.
// Those that are older than the earliest beginning of an interval are removed.
2018-09-24 17:30:03 +02:00
func (g Grid) FitEntries(now time.Time, entries []Entry) (keep, remove []Entry) {
2017-06-21 20:29:20 +02:00
type bucket struct {
2018-09-24 17:30:03 +02:00
entries []Entry
2017-06-21 20:29:20 +02:00
}
buckets := make([]bucket, len(g.intervals))
2018-09-24 17:30:03 +02:00
keep = make([]Entry, 0)
remove = make([]Entry, 0)
2017-06-21 20:29:20 +02:00
oldestIntervalStart := now
for i := range g.intervals {
2018-08-26 19:20:08 +02:00
oldestIntervalStart = oldestIntervalStart.Add(-g.intervals[i].Length())
2017-06-21 20:29:20 +02:00
}
for ei := 0; ei < len(entries); ei++ {
e := entries[ei]
date := e.Date()
if date == now || date.After(now) {
keep = append(keep, e)
continue
} else if date.Before(oldestIntervalStart) {
remove = append(remove, e)
continue
}
iStartTime := now
for i := 0; i < len(g.intervals); i++ {
2018-08-26 19:20:08 +02:00
iStartTime = iStartTime.Add(-g.intervals[i].Length())
2017-06-21 20:29:20 +02:00
if date == iStartTime || dateInInterval(date, iStartTime, g.intervals[i]) {
buckets[i].entries = append(buckets[i].entries, e)
}
}
}
for bi, b := range buckets {
2018-08-26 19:20:08 +02:00
interval := g.intervals[bi]
2017-06-21 20:29:20 +02:00
sort.SliceStable(b.entries, func(i, j int) bool {
return b.entries[i].LessThan((b.entries[j]))
})
i := 0
2018-08-26 19:20:08 +02:00
for ; (interval.KeepCount() == RetentionGridKeepCountAll || i < interval.KeepCount()) && i < len(b.entries); i++ {
2017-06-21 20:29:20 +02:00
keep = append(keep, b.entries[i])
}
for ; i < len(b.entries); i++ {
remove = append(remove, b.entries[i])
}
}
return
}