From c11107bf02b70ad672e370d15a1f314d89a9ed9a Mon Sep 17 00:00:00 2001 From: Giuseppe Date: Mon, 30 Nov 2015 09:06:51 +0100 Subject: [PATCH 01/14] introduction of bst --- cache.go | 40 ++++++++++++++++++++++++++++++---------- sharded.go | 2 ++ 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/cache.go b/cache.go index 61040b8..f2dc311 100644 --- a/cache.go +++ b/cache.go @@ -1,6 +1,7 @@ package cache import ( + "github.com/petar/GoLLRB/llrb" "encoding/gob" "fmt" "io" @@ -13,8 +14,13 @@ import ( var emptyTime = time.Time{} type Item struct { - Object interface{} - Expiration time.Time + Object interface{} + Expiration time.Time + Key string +} + +func (item Item) Less(than llrb.Item) bool { + return item.Expiration.Before(than.(Item).Expiration) } // Returns true if the item has expired. @@ -40,11 +46,12 @@ type Cache struct { } type cache struct { - defaultExpiration time.Duration - items map[string]Item - mu sync.RWMutex - onEvicted func(string, interface{}) - janitor *janitor + defaultExpiration time.Duration + items map[string]Item + mu sync.RWMutex + onEvicted func(string, interface{}) + janitor *janitor + sortedItems *llrb.LLRB } // Add an item to the cache, replacing any existing item. If the duration is 0 @@ -66,10 +73,18 @@ func (c *cache) set(k string, x interface{}, d time.Duration) { if d > 0 { e = time.Now().Add(d) } - c.items[k] = Item{ - Object: x, - Expiration: e, + item := Item{ + Object: x, + Expiration: e, + Key : k, } + //if an item with the same key exists in the cache, remove it from the bst + old, found := c.items[k] + if found { + c.sortedItems.Delete(old) + c.sortedItems.InsertNoReplace(item) + } + c.items[k] = item } // Add an item to the cache only if an item doesn't already exist for the given @@ -1041,6 +1056,11 @@ func newCache(de time.Duration, m map[string]Item) *cache { func newCacheWithJanitor(de time.Duration, ci time.Duration, m map[string]Item) *Cache { c := newCache(de, m) + c.sortedItems = llrb.New() + //we can probably do bulk insertion here to speed it up + for _, item := range m { + c.sortedItems.InsertNoReplace(item) + } // This trick ensures that the janitor goroutine (which--granted it // was enabled--is running DeleteExpired on c forever) does not keep // the returned C object from being garbage collected. When it is diff --git a/sharded.go b/sharded.go index bcc0538..be5ab6d 100644 --- a/sharded.go +++ b/sharded.go @@ -8,6 +8,7 @@ import ( "os" "runtime" "time" + "github.com/petar/GoLLRB/llrb" ) // This is an experimental and unexported (for now) attempt at making a cache @@ -172,6 +173,7 @@ func newShardedCache(n int, de time.Duration) *shardedCache { c := &cache{ defaultExpiration: de, items: map[string]Item{}, + sortedItems: llrb.New(), } sc.cs[i] = c } From 9e28bbffcf4f61125b04fa236ffd6801dc7b9755 Mon Sep 17 00:00:00 2001 From: Giuseppe Date: Tue, 1 Dec 2015 09:07:03 +0100 Subject: [PATCH 02/14] added delete on bst --- cache.go | 66 +++++++++++++++++++++++++++------------------------ cache_test.go | 15 ++++++++++++ 2 files changed, 50 insertions(+), 31 deletions(-) diff --git a/cache.go b/cache.go index f2dc311..1e526a7 100644 --- a/cache.go +++ b/cache.go @@ -65,25 +65,25 @@ func (c *cache) Set(k string, x interface{}, d time.Duration) { c.mu.Unlock() } -func (c *cache) set(k string, x interface{}, d time.Duration) { - e := emptyTime +func (c *cache) set(k string, x interface{}, d time.Duration) { + item := Item{ + Object: x, + Key : k, + } if d == DefaultExpiration { d = c.defaultExpiration } if d > 0 { - e = time.Now().Add(d) - } - item := Item{ - Object: x, - Expiration: e, - Key : k, - } - //if an item with the same key exists in the cache, remove it from the bst - old, found := c.items[k] - if found { - c.sortedItems.Delete(old) - c.sortedItems.InsertNoReplace(item) - } + item.Expiration = time.Now().Add(d) + //if an item with the same key exists in the cache, remove it from the bst + old, found := c.items[k] + if found { + c.sortedItems.Delete(old) + c.sortedItems.InsertNoReplace(item) + } + } else { + item.Expiration = emptyTime + } c.items[k] = item } @@ -144,6 +144,9 @@ func (c *cache) Increment(k string, n int64) error { c.mu.Unlock() return fmt.Errorf("Item %s not found", k) } + if v.Expiration != emptyTime { + c.sortedItems.Delete(v) + } switch v.Object.(type) { case int: v.Object = v.Object.(int) + int(n) @@ -176,6 +179,9 @@ func (c *cache) Increment(k string, n int64) error { return fmt.Errorf("The value for %s is not an integer", k) } c.items[k] = v + if v.Expiration != emptyTime { + c.sortedItems.InsertNoReplace(v) + } c.mu.Unlock() return nil } @@ -875,27 +881,25 @@ func (c *cache) delete(k string) (interface{}, bool) { return nil, false } -type keyAndValue struct { - key string - value interface{} -} - // Delete all expired items from the cache. func (c *cache) DeleteExpired() { - var evictedItems []keyAndValue + var evictedItems []Item c.mu.Lock() - for k, v := range c.items { - if v.Expired() { - ov, evicted := c.delete(k) - if evicted { - evictedItems = append(evictedItems, keyAndValue{k, ov}) - } - } - } - c.mu.Unlock() + c.sortedItems.DescendLessOrEqual(Item{Expiration: time.Now()}, func(i llrb.Item) bool { + v := i.(Item) + c.delete(v.Key) + evictedItems = append(evictedItems, v) + return true + }) for _, v := range evictedItems { - c.onEvicted(v.key, v.value) + c.sortedItems.Delete(v) } + c.mu.Unlock() + for _, v := range evictedItems { + if c.onEvicted != nil { + c.onEvicted(v.Key, v.Object) + } + } } // Sets an (optional) function that is called with the key and value when an diff --git a/cache_test.go b/cache_test.go index f998d43..01c6fb4 100644 --- a/cache_test.go +++ b/cache_test.go @@ -1615,3 +1615,18 @@ func BenchmarkDeleteExpired(b *testing.B) { tc.DeleteExpired() } } + +func BenchmarkLargeCache(b *testing.B) { + b.StopTimer() + tc := New(200 * time.Millisecond, 50 * time.Millisecond) + //tc.mu.Lock() + for i := 0; i < 100000; i++ { + tc.set(strconv.Itoa(i), "bar", DefaultExpiration) + } + //tc.mu.Unlock() + tc.DeleteExpired() + b.StartTimer() + for i := 100000; i <100000 + b.N; i++ { + tc.set(strconv.Itoa(i), "bar", DefaultExpiration) + } +} From 63991427871ebd11ba924b3747c6bf129c72ee1e Mon Sep 17 00:00:00 2001 From: Giuseppe Date: Tue, 1 Dec 2015 09:12:35 +0100 Subject: [PATCH 03/14] added large cache test --- cache_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/cache_test.go b/cache_test.go index f998d43..fd9ccb5 100644 --- a/cache_test.go +++ b/cache_test.go @@ -1615,3 +1615,18 @@ func BenchmarkDeleteExpired(b *testing.B) { tc.DeleteExpired() } } + +func BenchmarkLargeCache(b *testing.B) { + b.StopTimer() + tc := New(200 * time.Millisecond, 50 * time.Millisecond) + //tc.mu.Lock() + for i := 0; i < 100000; i++ { + tc.Set(strconv.Itoa(i), "bar", DefaultExpiration) + } + //tc.mu.Unlock() + tc.DeleteExpired() + b.StartTimer() + for i := 100000; i <100000 + b.N; i++ { + tc.Set(strconv.Itoa(i), "bar", DefaultExpiration) + } +} From bee3326f4b83855a1ef9b506ee25989c6ca92352 Mon Sep 17 00:00:00 2001 From: Giuseppe Date: Tue, 1 Dec 2015 09:38:36 +0100 Subject: [PATCH 04/14] modif test --- cache_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cache_test.go b/cache_test.go index 01c6fb4..ab6a547 100644 --- a/cache_test.go +++ b/cache_test.go @@ -1618,15 +1618,15 @@ func BenchmarkDeleteExpired(b *testing.B) { func BenchmarkLargeCache(b *testing.B) { b.StopTimer() - tc := New(200 * time.Millisecond, 50 * time.Millisecond) + tc := New(100 * time.Millisecond, 1 * time.Millisecond) //tc.mu.Lock() - for i := 0; i < 100000; i++ { - tc.set(strconv.Itoa(i), "bar", DefaultExpiration) + for i := 0; i < 1000000; i++ { + tc.Set(strconv.Itoa(i), "bar", DefaultExpiration) } //tc.mu.Unlock() tc.DeleteExpired() b.StartTimer() - for i := 100000; i <100000 + b.N; i++ { - tc.set(strconv.Itoa(i), "bar", DefaultExpiration) + for i := 1000000; i <1000000 + b.N; i++ { + tc.Set(strconv.Itoa(i), "bar", DefaultExpiration) } } From 2491a50c66c880504a7eb9be37305b53d3c5bf57 Mon Sep 17 00:00:00 2001 From: Giuseppe Date: Tue, 1 Dec 2015 18:38:44 +0100 Subject: [PATCH 05/14] modified test --- cache_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cache_test.go b/cache_test.go index fd9ccb5..ab6a547 100644 --- a/cache_test.go +++ b/cache_test.go @@ -1618,15 +1618,15 @@ func BenchmarkDeleteExpired(b *testing.B) { func BenchmarkLargeCache(b *testing.B) { b.StopTimer() - tc := New(200 * time.Millisecond, 50 * time.Millisecond) + tc := New(100 * time.Millisecond, 1 * time.Millisecond) //tc.mu.Lock() - for i := 0; i < 100000; i++ { + for i := 0; i < 1000000; i++ { tc.Set(strconv.Itoa(i), "bar", DefaultExpiration) } //tc.mu.Unlock() tc.DeleteExpired() b.StartTimer() - for i := 100000; i <100000 + b.N; i++ { + for i := 1000000; i <1000000 + b.N; i++ { tc.Set(strconv.Itoa(i), "bar", DefaultExpiration) } } From be7efe5287392ae2526d420a8e74bbf55f2aa26f Mon Sep 17 00:00:00 2001 From: Giuseppe Date: Tue, 1 Dec 2015 22:02:17 +0100 Subject: [PATCH 06/14] modified test --- cache_test.go | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/cache_test.go b/cache_test.go index 1456c58..4333af4 100644 --- a/cache_test.go +++ b/cache_test.go @@ -1650,15 +1650,41 @@ func BenchmarkDeleteExpiredLoop(b *testing.B) { func BenchmarkLargeCache(b *testing.B) { b.StopTimer() - tc := New(100 * time.Millisecond, 1 * time.Millisecond) - //tc.mu.Lock() - for i := 0; i < 1000000; i++ { - tc.Set(strconv.Itoa(i), "bar", DefaultExpiration) - } - //tc.mu.Unlock() - tc.DeleteExpired() + tc := New(100*time.Millisecond, 5*time.Millisecond) b.StartTimer() - for i := 1000000; i <1000000 + b.N; i++ { + b.N = 10000000 + for i := 0; i < b.N; i++ { tc.Set(strconv.Itoa(i), "bar", DefaultExpiration) } } + +/* +func BenchmarkLargeCache(b *testing.B) { + b.StopTimer() + tc := New(1*time.Millisecond, 0*time.Millisecond) + M := 1000000 + start := time.Now().UnixNano() + for i := 0; i < M; i++ { + tc.Set(strconv.Itoa(i), "bar", DefaultExpiration) + } + elapsed := (time.Now().UnixNano() - start)/1000000 + interval := elapsed/100 + b.Logf("Time to insert %d items: %d milliseconds", M, elapsed) + b.Logf("Interval: %d milliseconds", interval) + + tc = New(time.Duration(elapsed)*time.Millisecond, 0*time.Millisecond) + for i := 0; i < M; i++ { + tc.Set(strconv.Itoa(i), "bar", DefaultExpiration) + } + b.Logf("Cache size: %d", tc.ItemCount()) + items := tc.cache.items + tc = NewFrom(time.Duration(elapsed)*time.Millisecond, time.Duration(interval)*time.Millisecond, items) + + b.StartTimer() + for i := M; i Date: Tue, 1 Dec 2015 22:08:24 +0100 Subject: [PATCH 07/14] changed test --- cache_test.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/cache_test.go b/cache_test.go index 3406997..d02ad84 100644 --- a/cache_test.go +++ b/cache_test.go @@ -1648,6 +1648,17 @@ func BenchmarkDeleteExpiredLoop(b *testing.B) { } } +func BenchmarkLargeCache(b *testing.B) { + b.StopTimer() + tc := New(100*time.Millisecond, 1*time.Millisecond) + b.StartTimer() + b.N = 1000000 + for i := 0; i < b.N; i++ { + tc.Set(strconv.Itoa(i), "bar", DefaultExpiration) + } +} + +/* func BenchmarkLargeCache(b *testing.B) { b.StopTimer() tc := New(time.Second, 10*time.Millisecond) @@ -1657,11 +1668,11 @@ func BenchmarkLargeCache(b *testing.B) { tc.Set(strconv.Itoa(i), "bar", DefaultExpiration) i++ } - /* + for i := 0; i < 1000000; i++ { tc.Set(strconv.Itoa(i), "bar", DefaultExpiration) } - */ + tc.DeleteExpired() b.Logf("Cache size: %d", tc.ItemCount()) b.StartTimer() @@ -1669,3 +1680,4 @@ func BenchmarkLargeCache(b *testing.B) { tc.Set(strconv.Itoa(i), "bar", DefaultExpiration) } } +*/ From 7f1016551c924aa7e44dae4c2836ec7beb602ab8 Mon Sep 17 00:00:00 2001 From: Giuseppe Date: Tue, 1 Dec 2015 22:31:59 +0100 Subject: [PATCH 08/14] modified test --- cache_test.go | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/cache_test.go b/cache_test.go index 4333af4..8586253 100644 --- a/cache_test.go +++ b/cache_test.go @@ -1648,16 +1648,41 @@ func BenchmarkDeleteExpiredLoop(b *testing.B) { } } -func BenchmarkLargeCache(b *testing.B) { +func BenchmarkLargeCache01(b *testing.B) { + benchmarkLargeCache(b, 100000) +} + +func BenchmarkLargeCache02(b *testing.B) { + benchmarkLargeCache(b, 200000) +} + +func BenchmarkLargeCache05(b *testing.B) { + benchmarkLargeCache(b, 500000) +} + +func BenchmarkLargeCache10(b *testing.B) { + benchmarkLargeCache(b, 1000000) +} + +func BenchmarkLargeCache20(b *testing.B) { + benchmarkLargeCache(b, 2000000) +} + +func BenchmarkLargeCache50(b *testing.B) { + benchmarkLargeCache(b, 5000000) +} + +func benchmarkLargeCache(b *testing.B, nano int) { b.StopTimer() - tc := New(100*time.Millisecond, 5*time.Millisecond) + tc := New(100*time.Millisecond, time.Duration(nano)*time.Nanosecond) b.StartTimer() - b.N = 10000000 + b.N = 1000000 for i := 0; i < b.N; i++ { tc.Set(strconv.Itoa(i), "bar", DefaultExpiration) } } + /* func BenchmarkLargeCache(b *testing.B) { b.StopTimer() From 810668b922d7040d55526bf78a0505c576ca5806 Mon Sep 17 00:00:00 2001 From: Giuseppe Date: Tue, 1 Dec 2015 22:37:05 +0100 Subject: [PATCH 09/14] modified test --- cache_test.go | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/cache_test.go b/cache_test.go index d02ad84..3579fcc 100644 --- a/cache_test.go +++ b/cache_test.go @@ -1648,9 +1648,33 @@ func BenchmarkDeleteExpiredLoop(b *testing.B) { } } -func BenchmarkLargeCache(b *testing.B) { +func BenchmarkLargeCache01(b *testing.B) { + benchmarkLargeCache(b, 100000) +} + +func BenchmarkLargeCache02(b *testing.B) { + benchmarkLargeCache(b, 200000) +} + +func BenchmarkLargeCache05(b *testing.B) { + benchmarkLargeCache(b, 500000) +} + +func BenchmarkLargeCache10(b *testing.B) { + benchmarkLargeCache(b, 1000000) +} + +func BenchmarkLargeCache20(b *testing.B) { + benchmarkLargeCache(b, 2000000) +} + +func BenchmarkLargeCache50(b *testing.B) { + benchmarkLargeCache(b, 5000000) +} + +func benchmarkLargeCache(b *testing.B, nano int) { b.StopTimer() - tc := New(100*time.Millisecond, 1*time.Millisecond) + tc := New(100*time.Millisecond, time.Duration(nano)*time.Nanosecond) b.StartTimer() b.N = 1000000 for i := 0; i < b.N; i++ { From 4c8dd8263a384a68f9d50d0b80c01585814baf89 Mon Sep 17 00:00:00 2001 From: Giuseppe Date: Thu, 3 Dec 2015 01:56:49 +0100 Subject: [PATCH 10/14] fixed a bug in set --- cache.go | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/cache.go b/cache.go index 25792d5..50824a7 100644 --- a/cache.go +++ b/cache.go @@ -19,7 +19,6 @@ type Item struct { } func (item Item) Less(than llrb.Item) bool { - //return item.Expiration.Before(than.(Item).Expiration) return item.Expiration < than.(Item).Expiration } @@ -76,10 +75,8 @@ func (c *cache) set(k string, x interface{}, d time.Duration) { } if d > 0 { item.Expiration = time.Now().Add(d).UnixNano() - //if an item with the same key exists in the cache, remove it from the bst - old, found := c.items[k] - if found { - c.sortedItems.Delete(old) + _, found := c.items[k] + if !found { c.sortedItems.InsertNoReplace(item) } } @@ -162,9 +159,6 @@ func (c *cache) Increment(k string, n int64) error { c.mu.Unlock() return fmt.Errorf("Item %s not found", k) } - if v.Expiration != 0 { - c.sortedItems.Delete(v) - } switch v.Object.(type) { case int: v.Object = v.Object.(int) + int(n) @@ -197,9 +191,6 @@ func (c *cache) Increment(k string, n int64) error { return fmt.Errorf("The value for %s is not an integer", k) } c.items[k] = v - if v.Expiration != 0 { - c.sortedItems.InsertNoReplace(v) - } c.mu.Unlock() return nil } From 97de98b0f13fbfd2d8247008f3524614a7cfe2ab Mon Sep 17 00:00:00 2001 From: Giuseppe Date: Sat, 5 Dec 2015 14:19:03 +0100 Subject: [PATCH 11/14] fixed few bugs --- cache.go | 94 +++++++++++++++++++++++++++++++++++---------------- cache_test.go | 8 +++++ 2 files changed, 73 insertions(+), 29 deletions(-) diff --git a/cache.go b/cache.go index 50824a7..26844ee 100644 --- a/cache.go +++ b/cache.go @@ -15,11 +15,15 @@ import ( type Item struct { Object interface{} Expiration int64 +} + +type Node struct { + Expiration int64 Key string } -func (item Item) Less(than llrb.Item) bool { - return item.Expiration < than.(Item).Expiration +func (node Node) Less(than llrb.Item) bool { + return node.Expiration < than.(Node).Expiration } @@ -66,23 +70,41 @@ func (c *cache) Set(k string, x interface{}, d time.Duration) { } func (c *cache) set(k string, x interface{}, d time.Duration) { - item := Item{ - Object: x, - Key : k, - } + item := Item{Object: x,} if d == DefaultExpiration { d = c.defaultExpiration } if d > 0 { item.Expiration = time.Now().Add(d).UnixNano() - _, found := c.items[k] - if !found { - c.sortedItems.InsertNoReplace(item) + old, found := c.items[k] + if found && old.Expiration != item.Expiration{ + c.deleteFromBst(Node{Expiration: old.Expiration, Key: k}) + c.sortedItems.InsertNoReplace(Node{Expiration: item.Expiration, Key: k}) + } else if !found { + c.sortedItems.InsertNoReplace(Node{Expiration: item.Expiration, Key: k}) } } c.items[k] = item } +func (c *cache) deleteFromBst (node Node) { + //delete nodes from the tree with the same expiration + //until the required one is found + var toReinsert []Node + for del := c.sortedItems.Delete(node); del != nil; { + delNode := del.(Node) + if delNode.Key == node.Key { + break + } else { + toReinsert = append (toReinsert, delNode) + } + } + //reinsert the nodes in the tree, with modified expiration + for _, delNode := range toReinsert { + c.sortedItems.InsertNoReplace(delNode) + } +} + // Add an item to the cache only if an item doesn't already exist for the given // key, or if the existing item has expired. Returns an error otherwise. @@ -880,34 +902,49 @@ func (c *cache) Delete(k string) { } func (c *cache) delete(k string) (interface{}, bool) { - if c.onEvicted != nil { - if v, found := c.items[k]; found { - delete(c.items, k) + if v, found := c.items[k]; found { + delete(c.items, k) + c.deleteFromBst(Node{Expiration: v.Expiration, Key: k}) + if c.onEvicted != nil { return v.Object, true + } else { + return nil, false } } - delete(c.items, k) return nil, false } + +type keyAndValue struct { + key string + value interface{} +} + // Delete all expired items from the cache. func (c *cache) DeleteExpired() { - var evictedItems []Item + var evictedNodes []Node + var evictedItems []keyAndValue c.mu.Lock() - c.sortedItems.DescendLessOrEqual(Item{Expiration: time.Now().UnixNano()}, func(i llrb.Item) bool { - v := i.(Item) - c.delete(v.Key) - evictedItems = append(evictedItems, v) + c.sortedItems.DescendLessOrEqual(Node{Expiration: time.Now().UnixNano()}, func(i llrb.Item) bool { + v := i.(Node) + k := v.Key + item, found := c.items[k] + if !found { + panic("Item in tree but not in map!!") + } + delete(c.items, k) + evictedItems = append(evictedItems, keyAndValue{k, item.Object}) + evictedNodes = append(evictedNodes, v) return true }) - for _, v := range evictedItems { + for _, v := range evictedNodes { c.sortedItems.Delete(v) } c.mu.Unlock() - for _, v := range evictedItems { - if c.onEvicted != nil { - c.onEvicted(v.Key, v.Object) - } + if c.onEvicted != nil { + for _, n := range evictedItems { + c.onEvicted(n.key, n.value) + } } } @@ -976,10 +1013,10 @@ func (c *cache) Load(r io.Reader) error { ov, found := c.items[k] if !found || ov.Expired() { c.items[k] = v - if found { - c.sortedItems.Delete(ov) + if !found { + c.sortedItems.InsertNoReplace(Node{Expiration: v.Expiration, Key: k}) } - c.sortedItems.InsertNoReplace(v) + } } @@ -1073,9 +1110,8 @@ func newCache(de time.Duration, m map[string]Item) *cache { items: m, } c.sortedItems = llrb.New() - //we can probably do bulk insertion here to speed it up - for _, item := range m { - c.sortedItems.InsertNoReplace(item) + for k, item := range m { + c.sortedItems.InsertNoReplace(Node{Key: k, Expiration: item.Expiration}) } return c } diff --git a/cache_test.go b/cache_test.go index f9b7a96..67de7e7 100644 --- a/cache_test.go +++ b/cache_test.go @@ -1680,5 +1680,13 @@ func benchmarkLargeCache(b *testing.B, nano int) { for i := 0; i < b.N; i++ { tc.Set(strconv.Itoa(i), "bar", DefaultExpiration) } + b.StopTimer() + tc.DeleteExpired() + now := time.Now().UnixNano() + for _, item := range tc.Items() { + if item.Expiration < now { + b.Fatalf("some items have not been correctly evicted") + } + } } From 3969366c627be53413118b3680db8b9b40dcf3c7 Mon Sep 17 00:00:00 2001 From: Giuseppe Date: Sat, 5 Dec 2015 14:45:05 +0100 Subject: [PATCH 12/14] fixed formatting --- cache.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cache.go b/cache.go index 26844ee..4da5092 100644 --- a/cache.go +++ b/cache.go @@ -13,13 +13,13 @@ import ( type Item struct { - Object interface{} - Expiration int64 + Object interface{} + Expiration int64 } type Node struct { - Expiration int64 - Key string + Expiration int64 + Key string } func (node Node) Less(than llrb.Item) bool { @@ -50,12 +50,12 @@ type Cache struct { } type cache struct { - defaultExpiration time.Duration - items map[string]Item - mu sync.RWMutex - onEvicted func(string, interface{}) - janitor *janitor - sortedItems *llrb.LLRB + defaultExpiration time.Duration + items map[string]Item + mu sync.RWMutex + onEvicted func(string, interface{}) + janitor *janitor + sortedItems *llrb.LLRB } // Add an item to the cache, replacing any existing item. If the duration is 0 From 05f1124e1e0e66917eb3eec6a91b69db66a16049 Mon Sep 17 00:00:00 2001 From: Giuseppe Date: Sat, 5 Dec 2015 14:53:44 +0100 Subject: [PATCH 13/14] revised formatting --- cache.go | 13 ++----------- sharded.go | 2 +- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/cache.go b/cache.go index 4da5092..51afcb1 100644 --- a/cache.go +++ b/cache.go @@ -11,7 +11,6 @@ import ( "time" ) - type Item struct { Object interface{} Expiration int64 @@ -26,7 +25,6 @@ func (node Node) Less(than llrb.Item) bool { return node.Expiration < than.(Node).Expiration } - // Returns true if the item has expired. func (item Item) Expired() bool { if item.Expiration == 0 { @@ -907,14 +905,11 @@ func (c *cache) delete(k string) (interface{}, bool) { c.deleteFromBst(Node{Expiration: v.Expiration, Key: k}) if c.onEvicted != nil { return v.Object, true - } else { - return nil, false } } return nil, false } - type keyAndValue struct { key string value interface{} @@ -948,8 +943,6 @@ func (c *cache) DeleteExpired() { } } - - // Sets an (optional) function that is called with the key and value when an // item is evicted from the cache. (Including when it is deleted manually, but // not when it is overwritten.) Set to nil to disable. @@ -1015,10 +1008,8 @@ func (c *cache) Load(r io.Reader) error { c.items[k] = v if !found { c.sortedItems.InsertNoReplace(Node{Expiration: v.Expiration, Key: k}) - } - - } - + } + } } } return err diff --git a/sharded.go b/sharded.go index be5ab6d..e69e980 100644 --- a/sharded.go +++ b/sharded.go @@ -173,7 +173,7 @@ func newShardedCache(n int, de time.Duration) *shardedCache { c := &cache{ defaultExpiration: de, items: map[string]Item{}, - sortedItems: llrb.New(), + sortedItems: llrb.New(), } sc.cs[i] = c } From f648931821208e809058c73301086cebb15df2e3 Mon Sep 17 00:00:00 2001 From: Giuseppe Date: Sat, 5 Dec 2015 15:00:25 +0100 Subject: [PATCH 14/14] revised formatting --- cache.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cache.go b/cache.go index 51afcb1..b82a96b 100644 --- a/cache.go +++ b/cache.go @@ -103,7 +103,6 @@ func (c *cache) deleteFromBst (node Node) { } } - // Add an item to the cache only if an item doesn't already exist for the given // key, or if the existing item has expired. Returns an error otherwise. func (c *cache) Add(k string, x interface{}, d time.Duration) error {