Skip to content

Commit

Permalink
Merge 4003e6e into 46a3a44
Browse files Browse the repository at this point in the history
  • Loading branch information
trapajim authored May 20, 2019
2 parents 46a3a44 + 4003e6e commit e5c08a9
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 14 deletions.
121 changes: 117 additions & 4 deletions cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,10 @@ func TestCallbacks(t *testing.T) {
var m sync.Mutex
addedKey := ""
removedKey := ""
calledAddedItem := false
calledRemoveItem := false
expired := false
calledExpired := false

// setup a cache with AddedItem & SetAboutToDelete handlers configured
table := Cache("testCallbacks")
Expand All @@ -306,12 +309,22 @@ func TestCallbacks(t *testing.T) {
addedKey = item.Key().(string)
m.Unlock()
})
table.SetAddedItemCallback(func(item *CacheItem) {
m.Lock()
calledAddedItem = true
m.Unlock()
})
table.SetAboutToDeleteItemCallback(func(item *CacheItem) {
m.Lock()
removedKey = item.Key().(string)
m.Unlock()
})

table.SetAboutToDeleteItemCallback(func(item *CacheItem) {
m.Lock()
calledRemoveItem = true
m.Unlock()
})
// add an item to the cache and setup its AboutToExpire handler
i := table.Add(k, 500*time.Millisecond, v)
i.SetAboutToExpireCallback(func(key interface{}) {
Expand All @@ -320,22 +333,122 @@ func TestCallbacks(t *testing.T) {
m.Unlock()
})

i.SetAboutToExpireCallback(func(key interface{}) {
m.Lock()
calledExpired = true
m.Unlock()
})

// verify the AddedItem handler works
time.Sleep(250 * time.Millisecond)
m.Lock()
if addedKey != k {
if addedKey == k && !calledAddedItem {
t.Error("AddedItem callback not working")
}
m.Unlock()

// verify the AboutToDelete handler works
time.Sleep(500 * time.Millisecond)
m.Lock()
if removedKey != k {
if removedKey == k && !calledRemoveItem {
t.Error("AboutToDeleteItem callback not working:" + k + "_" + removedKey)
}
// verify the AboutToExpire handler works
if !expired {
if expired && !calledExpired {
t.Error("AboutToExpire callback not working")
}
m.Unlock()

}

func TestCallbackQueue(t *testing.T) {

var m sync.Mutex
addedKey := ""
addedkeyCallback2 := ""
secondCallbackResult := "second"
removedKey := ""
removedKeyCallback := ""
expired := false
calledExpired := false
// setup a cache with AddedItem & SetAboutToDelete handlers configured
table := Cache("testCallbacks")

// test callback queue
table.AddAddedItemCallback(func(item *CacheItem) {
m.Lock()
addedKey = item.Key().(string)
m.Unlock()
})
table.AddAddedItemCallback(func(item *CacheItem) {
m.Lock()
addedkeyCallback2 = secondCallbackResult
m.Unlock()
})

table.AddAboutToDeleteItemCallback(func(item *CacheItem) {
m.Lock()
removedKey = item.Key().(string)
m.Unlock()
})

table.AddAboutToDeleteItemCallback(func(item *CacheItem) {
m.Lock()
removedKeyCallback = secondCallbackResult
m.Unlock()
})

i := table.Add(k, 500*time.Millisecond, v)
i.AddAboutToExpireCallback(func(key interface{}) {
m.Lock()
expired = true
m.Unlock()
})

i.AddAboutToExpireCallback(func(key interface{}) {
m.Lock()
calledExpired = true
m.Unlock()
})
time.Sleep(250 * time.Millisecond)
m.Lock()
if addedKey != k && addedkeyCallback2 != secondCallbackResult {
t.Error("AddedItem callback queue not working")
}
m.Unlock()
time.Sleep(500 * time.Millisecond)
m.Lock()
if removedKey != k && removedKeyCallback != secondCallbackResult {
t.Error("Item removed callback queue not working")
}
m.Unlock()
// test removeing of the callbacks
table.RemoveAddedItemCallbacks()
table.RemoveAboutToDeleteItemCallback()
secondItemKey := "itemKey02"
expired = false
i = table.Add(secondItemKey, 500*time.Millisecond, v)
i.SetAboutToExpireCallback(func(key interface{}) {
m.Lock()
expired = true
m.Unlock()
})
i.RemoveAboutToExpireCallback()
//verify if the callbacks were removed
time.Sleep(250 * time.Millisecond)
m.Lock()
if addedKey == secondItemKey {
t.Error("AddedItemCallbacks were not removed")
}
m.Unlock()

// verify the AboutToDelete handler works
time.Sleep(500 * time.Millisecond)
m.Lock()
if removedKey == secondItemKey {
t.Error("AboutToDeleteItem not removed")
}
// verify the AboutToExpire handler works
if !expired && !calledExpired {
t.Error("AboutToExpire callback not working")
}
m.Unlock()
Expand Down
21 changes: 19 additions & 2 deletions cacheitem.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type CacheItem struct {
accessCount int64

// Callback method triggered right before removing the item from the cache
aboutToExpire func(key interface{})
aboutToExpire []func(key interface{})
}

// NewCacheItem returns a newly created CacheItem.
Expand Down Expand Up @@ -102,7 +102,24 @@ func (item *CacheItem) Data() interface{} {
// SetAboutToExpireCallback configures a callback, which will be called right
// before the item is about to be removed from the cache.
func (item *CacheItem) SetAboutToExpireCallback(f func(interface{})) {
if len(item.aboutToExpire) > 0 {
item.RemoveAboutToExpireCallback()
}
item.Lock()
defer item.Unlock()
item.aboutToExpire = append(item.aboutToExpire, f)
}

// AddAboutToExpireCallback appends a new callback to the AboutToExpire queue
func (item *CacheItem) AddAboutToExpireCallback(f func(interface{})) {
item.Lock()
defer item.Unlock()
item.aboutToExpire = append(item.aboutToExpire, f)
}

// RemoveAboutToExpireCallback empties the about to expire callback queue
func (item *CacheItem) RemoveAboutToExpireCallback() {
item.Lock()
defer item.Unlock()
item.aboutToExpire = f
item.aboutToExpire = nil
}
54 changes: 47 additions & 7 deletions cachetable.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ type CacheTable struct {
// Callback method triggered when trying to load a non-existing key.
loadData func(key interface{}, args ...interface{}) *CacheItem
// Callback method triggered when adding a new item to the cache.
addedItem func(item *CacheItem)
addedItem []func(item *CacheItem)
// Callback method triggered before deleting an item from the cache.
aboutToDeleteItem func(item *CacheItem)
aboutToDeleteItem []func(item *CacheItem)
}

// Count returns how many items are currently stored in the cache.
Expand Down Expand Up @@ -68,17 +68,51 @@ func (table *CacheTable) SetDataLoader(f func(interface{}, ...interface{}) *Cach
// SetAddedItemCallback configures a callback, which will be called every time
// a new item is added to the cache.
func (table *CacheTable) SetAddedItemCallback(f func(*CacheItem)) {
if len(table.addedItem) > 0 {
table.RemoveAddedItemCallbacks()
}
table.Lock()
defer table.Unlock()
table.addedItem = append(table.addedItem, f)
}

//AddAddedItemCallback appends a new callback to the addedItem queue
func (table *CacheTable) AddAddedItemCallback(f func(*CacheItem)) {
table.Lock()
defer table.Unlock()
table.addedItem = f
table.addedItem = append(table.addedItem, f)
}

// RemoveAddedItemCallbacks empties the added item callback queue
func (table *CacheTable) RemoveAddedItemCallbacks() {
table.Lock()
defer table.Unlock()
table.addedItem = nil
}

// SetAboutToDeleteItemCallback configures a callback, which will be called
// every time an item is about to be removed from the cache.
func (table *CacheTable) SetAboutToDeleteItemCallback(f func(*CacheItem)) {
if len(table.aboutToDeleteItem) > 0 {
table.RemoveAboutToDeleteItemCallback()
}
table.Lock()
defer table.Unlock()
table.aboutToDeleteItem = f
table.aboutToDeleteItem = append(table.aboutToDeleteItem, f)
}

// AddAboutToDeleteItemCallback appends a new callback to the AboutToDeleteItem queue
func (table *CacheTable) AddAboutToDeleteItemCallback(f func(*CacheItem)) {
table.Lock()
defer table.Unlock()
table.aboutToDeleteItem = append(table.aboutToDeleteItem, f)
}

// RemoveAboutToDeleteItemCallback empties the about to delete item callback queue
func (table *CacheTable) RemoveAboutToDeleteItemCallback() {
table.Lock()
defer table.Unlock()
table.aboutToDeleteItem = nil
}

// SetLogger sets the logger to be used by this cache table.
Expand Down Expand Up @@ -148,7 +182,9 @@ func (table *CacheTable) addInternal(item *CacheItem) {

// Trigger callback after adding an item to cache.
if addedItem != nil {
addedItem(item)
for _, callback := range addedItem {
callback(item)
}
}

// If we haven't set up any expiration check timer or found a more imminent item.
Expand Down Expand Up @@ -184,13 +220,17 @@ func (table *CacheTable) deleteInternal(key interface{}) (*CacheItem, error) {

// Trigger callbacks before deleting an item from cache.
if aboutToDeleteItem != nil {
aboutToDeleteItem(r)
for _, callback := range aboutToDeleteItem {
callback(r)
}
}

r.RLock()
defer r.RUnlock()
if r.aboutToExpire != nil {
r.aboutToExpire(key)
for _, callback := range r.aboutToExpire {
callback(key)
}
}

table.Lock()
Expand Down
6 changes: 5 additions & 1 deletion examples/callbacks/callbacks.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ func main() {
// This callback will be triggered every time a new item
// gets added to the cache.
cache.SetAddedItemCallback(func(entry *cache2go.CacheItem) {
fmt.Println("Added:", entry.Key(), entry.Data(), entry.CreatedOn())
fmt.Println("Added Callback 1:", entry.Key(), entry.Data(), entry.CreatedOn())
})
cache.AddAddedItemCallback(func(entry *cache2go.CacheItem) {
fmt.Println("Added Callback 2:", entry.Key(), entry.Data(), entry.CreatedOn())
})
// This callback will be triggered every time an item
// is about to be removed from the cache.
Expand All @@ -35,6 +38,7 @@ func main() {
// Deleting the item will execute the AboutToDeleteItem callback.
cache.Delete("someKey")

cache.RemoveAddedItemCallbacks()
// Caching a new item that expires in 3 seconds
res = cache.Add("anotherKey", 3*time.Second, "This is another test")

Expand Down

0 comments on commit e5c08a9

Please sign in to comment.