diff --git a/persist.go b/persist.go index f8e70bb..f1d8ef4 100644 --- a/persist.go +++ b/persist.go @@ -40,23 +40,41 @@ type Config struct { configured bool MaxVars int DBPath string + Tidy TidyConfig } func Init(x ...Config) { mux.Lock() - c := Config{MaxVars: 64, DBPath: "db"} // default config + c := Config { + configured: true, + MaxVars: 64, // default config + DBPath: "db", + } conf = c if len(x) > 0 { c = x[0] } if c.MaxVars != 0 { conf.MaxVars = c.MaxVars - conf.configured = true } if c.DBPath != "" { conf.DBPath = c.DBPath - conf.configured = true } + + if c.Tidy.Interval == 0 { + conf.Tidy.Interval = 10 * time.Second + } else { + fmt.Println("Setting conf.Tidy.Interval to",c.Tidy.Interval) + conf.Tidy.Interval = c.Tidy.Interval + } + + if c.Tidy.Func == nil { + conf.Tidy.Func = ExpireAfter(24 * time.Hour) + } else { + fmt.Println("Setting conf.Tidy.Func") + conf.Tidy.Func = c.Tidy.Func + } + mux.Unlock() } @@ -274,7 +292,9 @@ func start() { launched = true if conf.configured == false { + mux.Unlock() Init() + mux.Lock() } var err error @@ -423,6 +443,38 @@ func retrieve(name string, ts ...time.Time) ([]byte, time.Time, error) { return ret, t, err } +type TidyFunc func(*bolt.Bucket) int + +type TidyConfig struct { + Interval time.Duration + Func TidyFunc +} + +func ExpireAfter(exp time.Duration) TidyFunc { + if exp > 0 { + exp = -1 * exp + } + fmt.Println("ExpireAfter(",exp,")") + return func(b *bolt.Bucket) int { + stime := time.Now() + etime := stime.Add(exp) + i := 0 + c := b.Cursor() + end,_ := c.Last() // always keep the most recent on + for k,_ := c.First(); time.Since(stime) < 10 * time.Millisecond; k,_ = c.Next() { + if tdecode(k).After(etime) { + return i // entry not expired + } + if reflect.DeepEqual(k,end) { + return i // always keep the most recent entry + } + b.Delete(k) + i++ + } + return i + } +} + func tidyThread() { fmt.Println("tidyThread() starting") lchan := make(chan string) @@ -442,7 +494,7 @@ func tidyThread() { close(lchan) } }() - tick := time.NewTicker(time.Second * 10) + tick := time.NewTicker(conf.Tidy.Interval) for { select { case <-tchan: fmt.Println("closing loaded channel") @@ -457,12 +509,9 @@ func tidyThread() { } } } -const expiration time.Duration = -24 * time.Hour - // discard entries if they are too old. func Tidy(name string) { stime := time.Now() - etime := stime.Add(expiration) mux.Lock() i := 0 db.Update(func(tx *bolt.Tx) error { @@ -471,19 +520,7 @@ func Tidy(name string) { fmt.Println("Can't open bucket for ",name) return nil } - c := b.Cursor() - end,_ := c.Last() // always keep the most recent on - for time.Since(stime) < 10 * time.Millisecond { - k,_ := c.First() - if tdecode(k).After(etime) { - return nil // entry not expired - } - if reflect.DeepEqual(k,end) { - return nil // always keep the most recent entry - } - b.Delete(k) - i++ - } + i = conf.Tidy.Func(b) return nil }) mux.Unlock() diff --git a/test/tidy/main.go b/test/tidy/main.go new file mode 100644 index 0000000..65f4392 --- /dev/null +++ b/test/tidy/main.go @@ -0,0 +1,27 @@ +package main + +import ( + "fmt" + "time" + "gitlab.wow.st/gmp/persist" +) + +func main() { + tc := persist.TidyConfig{ + Interval: 2 * time.Second, + Func:persist.ExpireAfter(-5 * time.Second), + } + persist.Init(persist.Config{Tidy: tc}) + + x := persistInt("x",0) + persist.Commit() + x.Set(2) + persist.Commit() + x.Set(3) + persist.Commit() + fmt.Println(x.History()) + time.Sleep(time.Second * 15) + fmt.Println(x.History()) + persist.Shutdown() +} +