start pruning reimplementation in cmd/pruning subpackage

This commit is contained in:
Christian Schwarz 2018-08-27 15:09:24 +02:00
parent b4ea5f56b2
commit ecd9db4ac6
6 changed files with 231 additions and 0 deletions

View File

@ -0,0 +1,17 @@
package pruning
func filterSnapList(snaps []Snapshot, predicate func(Snapshot) bool) []Snapshot {
r := make([]Snapshot, 0, len(snaps))
for i := range snaps {
if predicate(snaps[i]) {
r = append(r, snaps[i])
}
}
return r
}
func shallowCopySnapList(snaps []Snapshot) []Snapshot {
c := make([]Snapshot, len(snaps))
copy(c, snaps)
return c
}

View File

@ -0,0 +1,22 @@
package pruning
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestShallowCopySnapList(t *testing.T) {
l1 := []Snapshot{
stubSnap{name: "foo"},
stubSnap{name: "bar"},
}
l2 := shallowCopySnapList(l1)
assert.Equal(t, l1, l2)
l1[0] = stubSnap{name: "baz"}
assert.Equal(t, "baz", l1[0].Name())
assert.Equal(t, "foo", l2[0].Name())
}

View File

@ -0,0 +1,32 @@
package pruning
import (
"github.com/pkg/errors"
"sort"
)
type KeepLastN struct {
n int
}
func NewKeepLastN(n int) (*KeepLastN, error) {
if n <= 0 {
return nil, errors.Errorf("must specify positive number as 'keep last count', got %d", n)
}
return &KeepLastN{n}, nil
}
func (k KeepLastN) KeepRule(snaps []Snapshot) []Snapshot {
if k.n > len(snaps) {
return snaps
}
res := shallowCopySnapList(snaps)
sort.Slice(res, func(i, j int) bool {
return res[i].Date().After(res[j].Date())
})
return res[:k.n]
}

View File

@ -0,0 +1,33 @@
package pruning
import (
"regexp"
)
type KeepRegex struct {
expr *regexp.Regexp
}
var _ KeepRule = &KeepRegex{}
func NewKeepRegex(expr string) (*KeepRegex, error) {
re, err := regexp.Compile(expr)
if err != nil {
return nil, err
}
return &KeepRegex{re}, nil
}
func MustKeepRegex(expr string) *KeepRegex {
k, err := NewKeepRegex(expr)
if err != nil {
panic(err)
}
return k
}
func (k *KeepRegex) KeepRule(snaps []Snapshot) []Snapshot {
return filterSnapList(snaps, func(s Snapshot) bool {
return k.expr.FindStringIndex(s.Name()) == nil
})
}

39
cmd/pruning/pruning.go Normal file
View File

@ -0,0 +1,39 @@
package pruning
import (
"time"
)
type KeepRule interface {
KeepRule(snaps []Snapshot) []Snapshot
}
type Snapshot interface {
Name() string
Replicated() bool
Date() time.Time
}
func PruneSnapshots(snaps []Snapshot, keepRules []KeepRule) []Snapshot {
if len(keepRules) == 0 {
return snaps
}
remCount := make(map[Snapshot]int, len(snaps))
for _, r := range keepRules {
ruleRems := r.KeepRule(snaps)
for _, ruleRem := range ruleRems {
remCount[ruleRem]++
}
}
remove := make([]Snapshot, 0, len(snaps))
for snap, rc := range remCount {
if rc == len(keepRules) {
remove = append(remove, snap)
}
}
return remove
}

View File

@ -0,0 +1,88 @@
package pruning
import (
"github.com/stretchr/testify/assert"
"testing"
"time"
)
type stubSnap struct {
name string
replicated bool
date time.Time
}
func (s stubSnap) Name() string { return s.name }
func (s stubSnap) Replicated() bool { return s.replicated }
func (s stubSnap) Date() time.Time { return s.date }
func TestPruneSnapshots(t *testing.T) {
type testCase struct {
inputs []Snapshot
rules []KeepRule
exp, eff []Snapshot
}
inputs := map[string][]Snapshot{
"s1": []Snapshot{
stubSnap{name: "foo_123"},
stubSnap{name: "foo_456"},
stubSnap{name: "bar_123"},
},
}
tcs := map[string]testCase{
"simple": {
inputs: inputs["s1"],
rules: []KeepRule{
MustKeepRegex("foo_"),
},
exp: []Snapshot{
stubSnap{name: "bar_123"},
},
},
"multipleRules": {
inputs: inputs["s1"],
rules: []KeepRule{
MustKeepRegex("foo_"),
MustKeepRegex("bar_"),
},
exp: []Snapshot{},
},
"onlyThoseRemovedByAllAreRemoved": {
inputs: inputs["s1"],
rules: []KeepRule{
MustKeepRegex("notInS1"), // would remove all
MustKeepRegex("bar_"), // would remove all but bar_, i.e. foo_.*
},
exp: []Snapshot{
stubSnap{name: "foo_123"},
stubSnap{name: "foo_456"},
},
},
"noRulesKeepsAll": {
inputs: inputs["s1"],
rules: []KeepRule{},
exp: inputs["s1"],
},
"noSnaps": {
inputs: []Snapshot{},
rules: []KeepRule{
MustKeepRegex("foo_"),
},
exp: []Snapshot{},
},
}
for name := range tcs {
t.Run(name, func(t *testing.T) {
tc := tcs[name]
tc.eff = PruneSnapshots(tc.inputs, tc.rules)
assert.Equal(t, tc.exp, tc.eff)
})
}
}