Allow configuration of tidy functions. Use a closure to decide what entries

to delete. The closure takes a *bolt.Bucket and returns an integer of the
number of entries deleted.
This commit is contained in:
Greg 2018-08-09 18:21:52 -04:00
parent d6f4920507
commit 17beaca380
2 changed files with 84 additions and 20 deletions

View File

@ -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()

27
test/tidy/main.go Normal file
View File

@ -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()
}