mirror of
https://github.com/zrepl/zrepl.git
synced 2024-12-23 07:28:57 +01:00
start pruning reimplementation in cmd/pruning subpackage
This commit is contained in:
parent
b4ea5f56b2
commit
ecd9db4ac6
17
cmd/pruning/keep_helpers.go
Normal file
17
cmd/pruning/keep_helpers.go
Normal 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
|
||||
}
|
22
cmd/pruning/keep_helpers_test.go
Normal file
22
cmd/pruning/keep_helpers_test.go
Normal 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())
|
||||
|
||||
}
|
32
cmd/pruning/keep_last_n.go
Normal file
32
cmd/pruning/keep_last_n.go
Normal 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]
|
||||
}
|
33
cmd/pruning/keep_prefix.go
Normal file
33
cmd/pruning/keep_prefix.go
Normal 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
39
cmd/pruning/pruning.go
Normal 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
|
||||
}
|
88
cmd/pruning/pruning_test.go
Normal file
88
cmd/pruning/pruning_test.go
Normal 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)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user