2016-08-19 18:50:52 +00:00
|
|
|
package restic
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
"sort"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ExpirePolicy configures which snapshots should be automatically removed.
|
|
|
|
type ExpirePolicy struct {
|
2017-07-09 07:24:02 +00:00
|
|
|
Last int // keep the last n snapshots
|
|
|
|
Hourly int // keep the last n hourly snapshots
|
|
|
|
Daily int // keep the last n daily snapshots
|
|
|
|
Weekly int // keep the last n weekly snapshots
|
|
|
|
Monthly int // keep the last n monthly snapshots
|
|
|
|
Yearly int // keep the last n yearly snapshots
|
|
|
|
Tags []TagList // keep all snapshots that include at least one of the tag lists.
|
2016-08-19 18:50:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Sum returns the maximum number of snapshots to be kept according to this
|
|
|
|
// policy.
|
|
|
|
func (e ExpirePolicy) Sum() int {
|
2016-08-20 15:51:48 +00:00
|
|
|
return e.Last + e.Hourly + e.Daily + e.Weekly + e.Monthly + e.Yearly
|
|
|
|
}
|
|
|
|
|
|
|
|
// Empty returns true iff no policy has been configured (all values zero).
|
|
|
|
func (e ExpirePolicy) Empty() bool {
|
2016-09-13 18:37:11 +00:00
|
|
|
if len(e.Tags) != 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2016-09-17 10:36:05 +00:00
|
|
|
empty := ExpirePolicy{Tags: e.Tags}
|
2016-09-13 18:37:11 +00:00
|
|
|
return reflect.DeepEqual(e, empty)
|
2016-08-19 18:50:52 +00:00
|
|
|
}
|
|
|
|
|
2016-08-20 13:55:02 +00:00
|
|
|
// ymdh returns an integer in the form YYYYMMDDHH.
|
|
|
|
func ymdh(d time.Time) int {
|
|
|
|
return d.Year()*1000000 + int(d.Month())*10000 + d.Day()*100 + d.Hour()
|
|
|
|
}
|
|
|
|
|
2016-08-19 18:50:52 +00:00
|
|
|
// ymd returns an integer in the form YYYYMMDD.
|
|
|
|
func ymd(d time.Time) int {
|
|
|
|
return d.Year()*10000 + int(d.Month())*100 + d.Day()
|
|
|
|
}
|
|
|
|
|
|
|
|
// yw returns an integer in the form YYYYWW, where WW is the week number.
|
|
|
|
func yw(d time.Time) int {
|
|
|
|
year, week := d.ISOWeek()
|
|
|
|
return year*100 + week
|
|
|
|
}
|
|
|
|
|
|
|
|
// ym returns an integer in the form YYYYMM.
|
|
|
|
func ym(d time.Time) int {
|
|
|
|
return d.Year()*100 + int(d.Month())
|
|
|
|
}
|
|
|
|
|
|
|
|
// y returns the year of d.
|
|
|
|
func y(d time.Time) int {
|
|
|
|
return d.Year()
|
|
|
|
}
|
|
|
|
|
2017-05-15 06:53:59 +00:00
|
|
|
// always returns a unique number for d.
|
2017-05-11 20:26:44 +00:00
|
|
|
func always(d time.Time) int {
|
2017-05-15 06:53:59 +00:00
|
|
|
return int(d.UnixNano())
|
2016-08-19 18:50:52 +00:00
|
|
|
}
|
|
|
|
|
2017-05-11 20:26:44 +00:00
|
|
|
// ApplyPolicy returns the snapshots from list that are to be kept and removed
|
|
|
|
// according to the policy p. list is sorted in the process.
|
2016-08-19 18:50:52 +00:00
|
|
|
func ApplyPolicy(list Snapshots, p ExpirePolicy) (keep, remove Snapshots) {
|
|
|
|
sort.Sort(list)
|
|
|
|
|
2016-08-20 15:51:48 +00:00
|
|
|
if p.Empty() {
|
2016-08-19 18:50:52 +00:00
|
|
|
return list, remove
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(list) == 0 {
|
|
|
|
return list, remove
|
|
|
|
}
|
|
|
|
|
2017-05-11 20:26:44 +00:00
|
|
|
var buckets = [6]struct {
|
|
|
|
Count int
|
|
|
|
bucker func(d time.Time) int
|
|
|
|
Last int
|
|
|
|
}{
|
|
|
|
{p.Last, always, -1},
|
|
|
|
{p.Hourly, ymdh, -1},
|
|
|
|
{p.Daily, ymd, -1},
|
|
|
|
{p.Weekly, yw, -1},
|
|
|
|
{p.Monthly, ym, -1},
|
|
|
|
{p.Yearly, y, -1},
|
2016-08-19 18:50:52 +00:00
|
|
|
}
|
|
|
|
|
2017-05-11 20:26:44 +00:00
|
|
|
for _, cur := range list {
|
2017-05-11 20:38:12 +00:00
|
|
|
var keepSnap bool
|
2017-05-11 20:26:44 +00:00
|
|
|
|
|
|
|
// Tags are handled specially as they are not counted.
|
2017-07-09 07:24:02 +00:00
|
|
|
for _, l := range p.Tags {
|
|
|
|
if cur.HasTags(l) {
|
2017-05-11 20:38:12 +00:00
|
|
|
keepSnap = true
|
2017-05-11 20:26:44 +00:00
|
|
|
}
|
|
|
|
}
|
2017-07-09 07:24:02 +00:00
|
|
|
|
2017-05-11 20:26:44 +00:00
|
|
|
// Now update the other buckets and see if they have some counts left.
|
|
|
|
for i, b := range buckets {
|
|
|
|
if b.Count > 0 {
|
|
|
|
val := b.bucker(cur.Time)
|
|
|
|
if val != b.Last {
|
2017-05-11 20:38:12 +00:00
|
|
|
keepSnap = true
|
2017-05-11 20:26:44 +00:00
|
|
|
buckets[i].Last = val
|
|
|
|
buckets[i].Count--
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-11 20:38:12 +00:00
|
|
|
if keepSnap {
|
2017-05-11 20:26:44 +00:00
|
|
|
keep = append(keep, cur)
|
|
|
|
} else {
|
|
|
|
remove = append(remove, cur)
|
|
|
|
}
|
|
|
|
}
|
2016-08-19 18:50:52 +00:00
|
|
|
|
2017-05-11 20:26:44 +00:00
|
|
|
return keep, remove
|
2016-08-19 18:50:52 +00:00
|
|
|
}
|