diff --git a/cache.go b/cache.go index 998d1db..a9e94f4 100644 --- a/cache.go +++ b/cache.go @@ -16,6 +16,7 @@ type Cache struct { bucketMask uint32 deletables chan *Item promotables chan *Item + donec chan struct{} } // Create a new cache with the specified configuration @@ -26,15 +27,13 @@ func New(config *Configuration) *Cache { Configuration: config, bucketMask: uint32(config.buckets) - 1, buckets: make([]*bucket, config.buckets), - deletables: make(chan *Item, config.deleteBuffer), - promotables: make(chan *Item, config.promoteBuffer), } for i := 0; i < int(config.buckets); i++ { c.buckets[i] = &bucket{ lookup: make(map[string]*Item), } } - go c.worker() + c.restart() return c } @@ -119,6 +118,14 @@ func (c *Cache) Clear() { // is called are likely to panic func (c *Cache) Stop() { close(c.promotables) + <-c.donec +} + +func (c *Cache) restart() { + c.deletables = make(chan *Item, c.deleteBuffer) + c.promotables = make(chan *Item, c.promoteBuffer) + c.donec = make(chan struct{}) + go c.worker() } func (c *Cache) deleteItem(bucket *bucket, item *Item) { @@ -146,6 +153,8 @@ func (c *Cache) promote(item *Item) { } func (c *Cache) worker() { + defer close(c.donec) + for { select { case item, ok := <-c.promotables: diff --git a/cache_test.go b/cache_test.go index d0989fb..552f36c 100644 --- a/cache_test.go +++ b/cache_test.go @@ -41,7 +41,7 @@ func (_ CacheTests) GCsTheOldestItems() { } //let the items get promoted (and added to our list) time.Sleep(time.Millisecond * 10) - cache.gc() + gcCache(cache) Expect(cache.Get("9")).To.Equal(nil) Expect(cache.Get("10").Value()).To.Equal(10) } @@ -54,7 +54,7 @@ func (_ CacheTests) PromotedItemsDontGetPruned() { time.Sleep(time.Millisecond * 10) //run the worker once to init the list cache.Get("9") time.Sleep(time.Millisecond * 10) - cache.gc() + gcCache(cache) Expect(cache.Get("9").Value()).To.Equal(9) Expect(cache.Get("10")).To.Equal(nil) Expect(cache.Get("11").Value()).To.Equal(11) @@ -67,11 +67,11 @@ func (_ CacheTests) TrackerDoesNotCleanupHeldInstance() { } item := cache.TrackingGet("0") time.Sleep(time.Millisecond * 10) - cache.gc() + gcCache(cache) Expect(cache.Get("0").Value()).To.Equal(0) Expect(cache.Get("1")).To.Equal(nil) item.Release() - cache.gc() + gcCache(cache) Expect(cache.Get("0")).To.Equal(nil) } @@ -104,19 +104,19 @@ func (_ CacheTests) SetUpdatesSizeOnDelta() { cache.Set("a", &SizedItem{0, 2}, time.Minute) cache.Set("b", &SizedItem{0, 3}, time.Minute) time.Sleep(time.Millisecond * 5) - Expect(cache.size).To.Equal(int64(5)) + checkSize(cache, 5) cache.Set("b", &SizedItem{0, 3}, time.Minute) time.Sleep(time.Millisecond * 5) - Expect(cache.size).To.Equal(int64(5)) + checkSize(cache, 5) cache.Set("b", &SizedItem{0, 4}, time.Minute) time.Sleep(time.Millisecond * 5) - Expect(cache.size).To.Equal(int64(6)) + checkSize(cache, 6) cache.Set("b", &SizedItem{0, 2}, time.Minute) time.Sleep(time.Millisecond * 5) - Expect(cache.size).To.Equal(int64(4)) + checkSize(cache, 4) cache.Delete("b") time.Sleep(time.Millisecond * 100) - Expect(cache.size).To.Equal(int64(2)) + checkSize(cache, 2) } func (_ CacheTests) ReplaceDoesNotchangeSizeIfNotSet() { @@ -126,7 +126,7 @@ func (_ CacheTests) ReplaceDoesNotchangeSizeIfNotSet() { cache.Set("3", &SizedItem{1, 2}, time.Minute) cache.Replace("4", &SizedItem{1, 2}) time.Sleep(time.Millisecond * 5) - Expect(cache.size).To.Equal(int64(6)) + checkSize(cache, 6) } func (_ CacheTests) ReplaceChangesSize() { @@ -136,15 +136,15 @@ func (_ CacheTests) ReplaceChangesSize() { cache.Replace("2", &SizedItem{1, 2}) time.Sleep(time.Millisecond * 5) - Expect(cache.size).To.Equal(int64(4)) + checkSize(cache, 4) cache.Replace("2", &SizedItem{1, 1}) time.Sleep(time.Millisecond * 5) - Expect(cache.size).To.Equal(int64(3)) + checkSize(cache, 3) cache.Replace("2", &SizedItem{1, 3}) time.Sleep(time.Millisecond * 5) - Expect(cache.size).To.Equal(int64(5)) + checkSize(cache, 5) } type SizedItem struct { @@ -155,3 +155,15 @@ type SizedItem struct { func (s *SizedItem) Size() int64 { return s.s } + +func checkSize(cache *Cache, sz int64) { + cache.Stop() + Expect(cache.size).To.Equal(sz) + cache.restart() +} + +func gcCache(cache *Cache) { + cache.Stop() + cache.gc() + cache.restart() +}