Adding support for OnDelete callback function

OnDelete will receive an item that is being processed for deletion to support calling cleanup function specific to the item stored
This commit is contained in:
Alexej Kubarev 2018-07-16 18:20:17 +02:00
parent 72059a01e9
commit 7421e2d7b4
No known key found for this signature in database
GPG key ID: EB7FF167F615F3BB
5 changed files with 66 additions and 1 deletions

View file

@ -186,6 +186,9 @@ func (c *Cache) doDelete(item *Item) {
item.promotions = -2 item.promotions = -2
} else { } else {
c.size -= item.size c.size -= item.size
if c.onDelete != nil {
c.onDelete(item)
}
c.list.Remove(item.element) c.list.Remove(item.element)
} }
} }

View file

@ -23,6 +23,28 @@ func (_ CacheTests) DeletesAValue() {
Expect(cache.Get("worm").Value()).To.Equal("sand") Expect(cache.Get("worm").Value()).To.Equal("sand")
} }
func (_ CacheTests) OnDeleteCallbackCalled() {
onDeleteFnCalled := false
onDeleteFn := func(item *Item) {
if item.key == "spice" {
onDeleteFnCalled = true
}
}
cache := New(Configure().OnDelete(onDeleteFn))
cache.Set("spice", "flow", time.Minute)
cache.Set("worm", "sand", time.Minute)
time.Sleep(time.Millisecond * 10) // Run once to init
cache.Delete("spice")
time.Sleep(time.Millisecond * 10) // Wait for worker to pick up deleted items
Expect(cache.Get("spice")).To.Equal(nil)
Expect(cache.Get("worm").Value()).To.Equal("sand")
Expect(onDeleteFnCalled).To.Equal(true)
}
func (_ CacheTests) FetchesExpiredItems() { func (_ CacheTests) FetchesExpiredItems() {
cache := New(Configure()) cache := New(Configure())
fn := func() (interface{}, error) { return "moo-moo", nil } fn := func() (interface{}, error) { return "moo-moo", nil }

View file

@ -8,6 +8,7 @@ type Configuration struct {
promoteBuffer int promoteBuffer int
getsPerPromote int32 getsPerPromote int32
tracking bool tracking bool
onDelete func(item *Item)
} }
// Creates a configuration object with sensible defaults // Creates a configuration object with sensible defaults
@ -92,3 +93,11 @@ func (c *Configuration) Track() *Configuration {
c.tracking = true c.tracking = true
return c return c
} }
// OnDelete allows setting a callback function to react to ideam deletion.
// This typically allows to do a cleanup of resources, such as calling a Close() on
// cached object that require some kind of tear-down.
func (c *Configuration) OnDelete(callback func(item *Item)) *Configuration {
c.onDelete = callback
return c
}

View file

@ -195,6 +195,9 @@ func (c *LayeredCache) worker() {
item.promotions = -2 item.promotions = -2
} else { } else {
c.size -= item.size c.size -= item.size
if c.onDelete != nil {
c.onDelete(item)
}
c.list.Remove(item.element) c.list.Remove(item.element)
} }
} }

View file

@ -1,10 +1,11 @@
package ccache package ccache
import ( import (
. "github.com/karlseguin/expect"
"strconv" "strconv"
"testing" "testing"
"time" "time"
. "github.com/karlseguin/expect"
) )
type LayeredCacheTests struct{} type LayeredCacheTests struct{}
@ -65,6 +66,33 @@ func (_ *LayeredCacheTests) DeletesAValue() {
Expect(cache.Get("leto", "sister").Value()).To.Equal("ghanima") Expect(cache.Get("leto", "sister").Value()).To.Equal("ghanima")
} }
func (_ *LayeredCacheTests) OnDeleteCallbackCalled() {
onDeleteFnCalled := false
onDeleteFn := func(item *Item) {
if item.group == "spice" && item.key == "flow" {
onDeleteFnCalled = true
}
}
cache := Layered(Configure().OnDelete(onDeleteFn))
cache.Set("spice", "flow", "value-a", time.Minute)
cache.Set("spice", "must", "value-b", time.Minute)
cache.Set("leto", "sister", "ghanima", time.Minute)
time.Sleep(time.Millisecond * 10) // Run once to init
cache.Delete("spice", "flow")
time.Sleep(time.Millisecond * 10) // Wait for worker to pick up deleted items
Expect(cache.Get("spice", "flow")).To.Equal(nil)
Expect(cache.Get("spice", "must").Value()).To.Equal("value-b")
Expect(cache.Get("spice", "worm")).To.Equal(nil)
Expect(cache.Get("leto", "sister").Value()).To.Equal("ghanima")
Expect(onDeleteFnCalled).To.Equal(true)
}
func (_ *LayeredCacheTests) DeletesALayer() { func (_ *LayeredCacheTests) DeletesALayer() {
cache := newLayered() cache := newLayered()
cache.Set("spice", "flow", "value-a", time.Minute) cache.Set("spice", "flow", "value-a", time.Minute)