From 59cc448441abf4c55b2d3fdb69855a3f5218dcda Mon Sep 17 00:00:00 2001 From: Jaime Martinez Date: Tue, 13 Oct 2020 11:33:45 +1100 Subject: [PATCH] Delete expired items before setting Check if an item exists and it has expired before setting so that onEvicted is actually called. Fixes #48. Add test and split func Use nanoseconds instead --- cache.go | 15 +++++++++++++++ cache_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/cache.go b/cache.go index db88d2f..e7c9c06 100644 --- a/cache.go +++ b/cache.go @@ -57,6 +57,10 @@ func (c *cache) Set(k string, x interface{}, d time.Duration) { if d > 0 { e = time.Now().Add(d).UnixNano() } + + // delete before setting and call onEvicted + c.deleteIfExpired(k) + c.mu.Lock() c.items[k] = Item{ Object: x, @@ -922,6 +926,17 @@ func (c *cache) delete(k string) (interface{}, bool) { return nil, false } +func (c *cache) deleteIfExpired(k string) { + c.mu.Lock() + i, ok := c.items[k] + c.mu.Unlock() + + if ok && i.Expired() { + // delete if expired so .onEvicted is called + c.Delete(k) + } +} + type keyAndValue struct { key string value interface{} diff --git a/cache_test.go b/cache_test.go index de3e9d6..af7fff2 100644 --- a/cache_test.go +++ b/cache_test.go @@ -1247,6 +1247,39 @@ func TestOnEvicted(t *testing.T) { } } +func TestOnEvictedCalledBeforeSet(t *testing.T) { + tc := New(DefaultExpiration, 0) + expiry := 1 * time.Nanosecond + + works := false + tc.OnEvicted(func(k string, v interface{}) { + if k == "foo" && v.(int) == 3 { + + works = true + } + tc.Set("bar", 4, DefaultExpiration) + }) + + tc.Set("foo", 3, expiry) + if tc.onEvicted == nil { + t.Fatal("tc.onEvicted is nil") + } + + // ensure item expires + time.Sleep(expiry) + + // calling Set again should evict expired item + tc.Set("foo", 3, DefaultExpiration) + + x, _ := tc.Get("bar") + if !works { + t.Fatal("works bool not true") + } + if x.(int) != 4 { + t.Error("bar was not 4") + } +} + func TestCacheSerialization(t *testing.T) { tc := New(DefaultExpiration, 0) testFillAndSerialize(t, tc)