138 lines
3.4 KiB
Go
138 lines
3.4 KiB
Go
package state
|
|
|
|
import (
|
|
"sort"
|
|
"time"
|
|
)
|
|
|
|
type PruneCandidate struct {
|
|
Path string
|
|
UpdatedAt time.Time
|
|
Owner *OwnerScope
|
|
}
|
|
|
|
type PrunePlanOptions struct {
|
|
Now time.Time
|
|
OlderThan *time.Duration
|
|
KeepLatest *int
|
|
}
|
|
|
|
type PrunePlan struct {
|
|
Pruned []PruneCandidate
|
|
Preserved []PruneCandidate
|
|
}
|
|
|
|
func SingleOwnerPruneCandidates(s DistributorState) []PruneCandidate {
|
|
candidates := make([]PruneCandidate, 0, len(s.Outputs))
|
|
for _, output := range s.Outputs {
|
|
candidates = append(candidates, PruneCandidate{
|
|
Path: output.Path,
|
|
UpdatedAt: output.UpdatedAt,
|
|
})
|
|
}
|
|
return candidates
|
|
}
|
|
|
|
func SharedRootPruneCandidates(s SharedRootState, scope OwnerScope) []PruneCandidate {
|
|
candidates := make([]PruneCandidate, 0, len(s.Outputs))
|
|
for _, output := range s.Outputs {
|
|
if output.Owner != scope {
|
|
continue
|
|
}
|
|
owner := output.Owner
|
|
candidates = append(candidates, PruneCandidate{
|
|
Path: output.Path,
|
|
UpdatedAt: output.UpdatedAt,
|
|
Owner: &owner,
|
|
})
|
|
}
|
|
return candidates
|
|
}
|
|
|
|
func CatalogPruneCandidates(s CatalogState, scope OwnerScope) []PruneCandidate {
|
|
candidates := make([]PruneCandidate, 0, len(s.Outputs))
|
|
for _, output := range s.Outputs {
|
|
if output.PipelineID != scope.PipelineID || output.DestinationID != scope.DestinationID {
|
|
continue
|
|
}
|
|
owner := scope
|
|
candidates = append(candidates, PruneCandidate{
|
|
Path: output.Path,
|
|
UpdatedAt: output.UpdatedAt,
|
|
Owner: &owner,
|
|
})
|
|
}
|
|
return candidates
|
|
}
|
|
|
|
func PlanPrune(candidates []PruneCandidate, options PrunePlanOptions) PrunePlan {
|
|
ordered := append([]PruneCandidate(nil), candidates...)
|
|
sortPruneCandidatesNewestFirst(ordered)
|
|
if options.OlderThan == nil && options.KeepLatest == nil {
|
|
return PrunePlan{
|
|
Pruned: []PruneCandidate{},
|
|
Preserved: ordered,
|
|
}
|
|
}
|
|
|
|
preservedByPath := make(map[string]struct{})
|
|
if options.KeepLatest != nil {
|
|
keep := *options.KeepLatest
|
|
if keep < 0 {
|
|
keep = 0
|
|
}
|
|
if keep > len(ordered) {
|
|
keep = len(ordered)
|
|
}
|
|
for _, candidate := range ordered[:keep] {
|
|
preservedByPath[candidate.Path] = struct{}{}
|
|
}
|
|
}
|
|
|
|
plan := PrunePlan{
|
|
Pruned: []PruneCandidate{},
|
|
Preserved: []PruneCandidate{},
|
|
}
|
|
cutoff := time.Time{}
|
|
if options.OlderThan != nil {
|
|
now := options.Now.UTC()
|
|
if now.IsZero() {
|
|
now = time.Now().UTC()
|
|
}
|
|
cutoff = now.Add(-*options.OlderThan)
|
|
}
|
|
|
|
for _, candidate := range ordered {
|
|
if _, preserved := preservedByPath[candidate.Path]; preserved {
|
|
plan.Preserved = append(plan.Preserved, candidate)
|
|
continue
|
|
}
|
|
if options.OlderThan == nil || candidate.UpdatedAt.Before(cutoff) {
|
|
plan.Pruned = append(plan.Pruned, candidate)
|
|
continue
|
|
}
|
|
plan.Preserved = append(plan.Preserved, candidate)
|
|
}
|
|
sortPruneCandidatesOldestFirst(plan.Pruned)
|
|
sortPruneCandidatesNewestFirst(plan.Preserved)
|
|
return plan
|
|
}
|
|
|
|
func sortPruneCandidatesNewestFirst(candidates []PruneCandidate) {
|
|
sort.Slice(candidates, func(i, j int) bool {
|
|
if !candidates[i].UpdatedAt.Equal(candidates[j].UpdatedAt) {
|
|
return candidates[i].UpdatedAt.After(candidates[j].UpdatedAt)
|
|
}
|
|
return candidates[i].Path < candidates[j].Path
|
|
})
|
|
}
|
|
|
|
func sortPruneCandidatesOldestFirst(candidates []PruneCandidate) {
|
|
sort.Slice(candidates, func(i, j int) bool {
|
|
if !candidates[i].UpdatedAt.Equal(candidates[j].UpdatedAt) {
|
|
return candidates[i].UpdatedAt.Before(candidates[j].UpdatedAt)
|
|
}
|
|
return candidates[i].Path < candidates[j].Path
|
|
})
|
|
}
|