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 }