99 lines
2.5 KiB
Go
99 lines
2.5 KiB
Go
package store
|
|
|
|
import (
|
|
"bytes"
|
|
"sort"
|
|
"time"
|
|
)
|
|
|
|
type RetentionCandidate struct {
|
|
IssueUUID [16]byte
|
|
IssueTime time.Time
|
|
TerminalTime time.Time
|
|
ChargedBytes uint64
|
|
Terminal bool
|
|
}
|
|
|
|
type RetentionSelection struct {
|
|
IssueUUIDs [][16]byte
|
|
ReleasedBytes uint64
|
|
}
|
|
|
|
func SelectWholeCommandEvictions(now time.Time, age time.Duration, bytesNeeded uint64, candidates []RetentionCandidate) RetentionSelection {
|
|
ordered := append([]RetentionCandidate(nil), candidates...)
|
|
sort.Slice(ordered, func(left, right int) bool {
|
|
if ordered[left].IssueTime.Equal(ordered[right].IssueTime) {
|
|
return bytes.Compare(ordered[left].IssueUUID[:], ordered[right].IssueUUID[:]) < 0
|
|
}
|
|
return ordered[left].IssueTime.Before(ordered[right].IssueTime)
|
|
})
|
|
selected := make(map[[16]byte]bool, len(ordered))
|
|
var result RetentionSelection
|
|
selectCandidate := func(candidate RetentionCandidate) {
|
|
if selected[candidate.IssueUUID] {
|
|
return
|
|
}
|
|
selected[candidate.IssueUUID] = true
|
|
result.IssueUUIDs = append(result.IssueUUIDs, candidate.IssueUUID)
|
|
if total, overflow := addChecked(result.ReleasedBytes, candidate.ChargedBytes); overflow {
|
|
result.ReleasedBytes = ^uint64(0)
|
|
} else {
|
|
result.ReleasedBytes = total
|
|
}
|
|
}
|
|
if age > 0 {
|
|
cutoff := now.Add(-age)
|
|
for _, candidate := range ordered {
|
|
if candidate.Terminal && !candidate.TerminalTime.IsZero() && !candidate.TerminalTime.After(cutoff) {
|
|
selectCandidate(candidate)
|
|
}
|
|
}
|
|
}
|
|
for _, candidate := range ordered {
|
|
if result.ReleasedBytes >= bytesNeeded {
|
|
break
|
|
}
|
|
if candidate.Terminal {
|
|
selectCandidate(candidate)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
type OutputSegmentCandidate struct {
|
|
Ordinal uint32
|
|
ChargedBytes uint64
|
|
Sealed bool
|
|
}
|
|
|
|
func SelectOutputRotation(currentBytes, limit uint64, candidates []OutputSegmentCandidate) []uint32 {
|
|
if currentBytes <= limit {
|
|
return nil
|
|
}
|
|
ordered := append([]OutputSegmentCandidate(nil), candidates...)
|
|
sort.Slice(ordered, func(left, right int) bool { return ordered[left].Ordinal < ordered[right].Ordinal })
|
|
var selected []uint32
|
|
for _, candidate := range ordered {
|
|
if currentBytes <= limit {
|
|
break
|
|
}
|
|
if !candidate.Sealed {
|
|
continue
|
|
}
|
|
selected = append(selected, candidate.Ordinal)
|
|
if candidate.ChargedBytes >= currentBytes {
|
|
currentBytes = 0
|
|
} else {
|
|
currentBytes -= candidate.ChargedBytes
|
|
}
|
|
}
|
|
return selected
|
|
}
|
|
|
|
func FIFOEntriesToRemove(current, maximum uint64) uint64 {
|
|
if current <= maximum {
|
|
return 0
|
|
}
|
|
return current - maximum
|
|
}
|