[#292] pruning: grid: add all snapshots that do not match the regex to the rule's destroy list

Before this patch, multiple grids with disjoint regexes would result in
no snapshots being destroyed at all.

fixes #292
This commit is contained in:
Christian Schwarz 2020-08-29 17:29:08 +02:00
parent bcf6ff1c08
commit 3a4e841c73
3 changed files with 43 additions and 7 deletions

View File

@ -99,17 +99,21 @@ func (a retentionGridAdaptor) LessThan(b retentiongrid.Entry) bool {
// Prune filters snapshots with the retention grid. // Prune filters snapshots with the retention grid.
func (p *KeepGrid) KeepRule(snaps []Snapshot) (destroyList []Snapshot) { func (p *KeepGrid) KeepRule(snaps []Snapshot) (destroyList []Snapshot) {
snaps = filterSnapList(snaps, func(snapshot Snapshot) bool { matching, notMatching := partitionSnapList(snaps, func(snapshot Snapshot) bool {
return p.re.MatchString(snapshot.Name()) return p.re.MatchString(snapshot.Name())
}) })
if len(snaps) == 0 {
return nil // snaps that don't match the regex are not kept by this rule
destroyList = append(destroyList, notMatching...)
if len(matching) == 0 {
return destroyList
} }
// Build adaptors for retention grid // Build adaptors for retention grid
adaptors := make([]retentiongrid.Entry, 0) adaptors := make([]retentiongrid.Entry, 0)
for i := range snaps { for i := range matching {
adaptors = append(adaptors, retentionGridAdaptor{snaps[i]}) adaptors = append(adaptors, retentionGridAdaptor{matching[i]})
} }
// determine 'now' edge // determine 'now' edge
@ -122,9 +126,8 @@ func (p *KeepGrid) KeepRule(snaps []Snapshot) (destroyList []Snapshot) {
_, removea := p.retentionGrid.FitEntries(now, adaptors) _, removea := p.retentionGrid.FitEntries(now, adaptors)
// Revert adaptors // Revert adaptors
destroyList = make([]Snapshot, len(removea))
for i := range removea { for i := range removea {
destroyList[i] = removea[i].(retentionGridAdaptor).Snapshot destroyList = append(destroyList, removea[i].(retentionGridAdaptor).Snapshot)
} }
return destroyList return destroyList
} }

View File

@ -10,6 +10,17 @@ func filterSnapList(snaps []Snapshot, predicate func(Snapshot) bool) []Snapshot
return r return r
} }
func partitionSnapList(snaps []Snapshot, predicate func(Snapshot) bool) (sTrue, sFalse []Snapshot) {
for i := range snaps {
if predicate(snaps[i]) {
sTrue = append(sTrue, snaps[i])
} else {
sFalse = append(sFalse, snaps[i])
}
}
return
}
func shallowCopySnapList(snaps []Snapshot) []Snapshot { func shallowCopySnapList(snaps []Snapshot) []Snapshot {
c := make([]Snapshot, len(snaps)) c := make([]Snapshot, len(snaps))
copy(c, snaps) copy(c, snaps)

View File

@ -75,6 +75,10 @@ func TestPruneSnapshots(t *testing.T) {
}, },
} }
reltime := func(secs int64) time.Time {
return time.Unix(secs, 0)
}
tcs := map[string]testCase{ tcs := map[string]testCase{
"simple": { "simple": {
inputs: inputs["s1"], inputs: inputs["s1"],
@ -121,6 +125,24 @@ func TestPruneSnapshots(t *testing.T) {
}, },
expDestroy: map[string]bool{}, expDestroy: map[string]bool{},
}, },
"multiple_grids_with_disjoint_regexes": {
inputs: []Snapshot{
stubSnap{"p1_a", false, reltime(4)},
stubSnap{"p2_a", false, reltime(5)},
stubSnap{"p1_b", false, reltime(14)},
stubSnap{"p2_b", false, reltime(15)},
stubSnap{"p1_c", false, reltime(29)},
stubSnap{"p2_c", false, reltime(30)},
},
rules: []KeepRule{
MustNewKeepGrid("^p1_", `1x10s | 1x10s`),
MustNewKeepGrid("^p2_", `1x10s | 1x10s`),
},
expDestroy: map[string]bool{
"p1_a": true,
"p2_a": true,
},
},
} }
testTable(tcs, t) testTable(tcs, t)