Skip to content

Commit 38560f5

Browse files
committed
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 Call onEvicted if item existed before setting Call onEvicted if item.Expired
1 parent 46f4078 commit 38560f5

File tree

2 files changed

+46
-0
lines changed

2 files changed

+46
-0
lines changed

cache.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,27 @@ func (c *cache) Set(k string, x interface{}, d time.Duration) {
5757
if d > 0 {
5858
e = time.Now().Add(d).UnixNano()
5959
}
60+
61+
var item Item
62+
var evicted bool
63+
6064
c.mu.Lock()
65+
if c.onEvicted != nil {
66+
item, evicted = c.items[k]
67+
}
68+
6169
c.items[k] = Item{
6270
Object: x,
6371
Expiration: e,
6472
}
6573
// TODO: Calls to mu.Unlock are currently not deferred because defer
6674
// adds ~200 ns (as of go1.)
6775
c.mu.Unlock()
76+
77+
// try to call onEvicted if key existed before but it was expired before cleanup
78+
if evicted && item.Expired() {
79+
c.onEvicted(k, item.Object)
80+
}
6881
}
6982

7083
func (c *cache) set(k string, x interface{}, d time.Duration) {

cache_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,39 @@ func TestOnEvicted(t *testing.T) {
12471247
}
12481248
}
12491249

1250+
func TestOnEvictedCalledBeforeSet(t *testing.T) {
1251+
tc := New(DefaultExpiration, 0)
1252+
expiry := 1 * time.Nanosecond
1253+
1254+
works := false
1255+
tc.OnEvicted(func(k string, v interface{}) {
1256+
if k == "foo" && v.(int) == 3 {
1257+
1258+
works = true
1259+
}
1260+
tc.Set("bar", 4, DefaultExpiration)
1261+
})
1262+
1263+
tc.Set("foo", 3, expiry)
1264+
if tc.onEvicted == nil {
1265+
t.Fatal("tc.onEvicted is nil")
1266+
}
1267+
1268+
// ensure item expires
1269+
time.Sleep(expiry)
1270+
1271+
// calling Set again should evict expired item
1272+
tc.Set("foo", 3, DefaultExpiration)
1273+
1274+
x, _ := tc.Get("bar")
1275+
if !works {
1276+
t.Fatal("works bool not true")
1277+
}
1278+
if x.(int) != 4 {
1279+
t.Error("bar was not 4")
1280+
}
1281+
}
1282+
12501283
func TestCacheSerialization(t *testing.T) {
12511284
tc := New(DefaultExpiration, 0)
12521285
testFillAndSerialize(t, tc)

0 commit comments

Comments
 (0)