diff --git a/bucket.go b/bucket.go index cf896c6..4f65dd0 100644 --- a/bucket.go +++ b/bucket.go @@ -23,9 +23,9 @@ func (b *bucket) get(key string) *Item { return b.lookup[key] } -func (b *bucket) set(key string, value interface{}, duration time.Duration) (*Item, *Item) { +func (b *bucket) set(key string, value interface{}, duration time.Duration, track bool) (*Item, *Item) { expires := time.Now().Add(duration).UnixNano() - item := newItem(key, value, expires) + item := newItem(key, value, expires, track) b.Lock() existing := b.lookup[key] b.lookup[key] = item diff --git a/bucket_test.go b/bucket_test.go index e41b8cf..19266b2 100644 --- a/bucket_test.go +++ b/bucket_test.go @@ -1,9 +1,10 @@ package ccache import ( - . "github.com/karlseguin/expect" "testing" "time" + + . "github.com/karlseguin/expect" ) type BucketTests struct { @@ -32,7 +33,7 @@ func (_ *BucketTests) DeleteItemFromBucket() { func (_ *BucketTests) SetsANewBucketItem() { bucket := testBucket() - item, existing := bucket.set("spice", TestValue("flow"), time.Minute) + item, existing := bucket.set("spice", TestValue("flow"), time.Minute, false) assertValue(item, "flow") item = bucket.get("spice") assertValue(item, "flow") @@ -41,7 +42,7 @@ func (_ *BucketTests) SetsANewBucketItem() { func (_ *BucketTests) SetsAnExistingItem() { bucket := testBucket() - item, existing := bucket.set("power", TestValue("9001"), time.Minute) + item, existing := bucket.set("power", TestValue("9001"), time.Minute, false) assertValue(item, "9001") item = bucket.get("power") assertValue(item, "9001") diff --git a/cache.go b/cache.go index e9d1924..5dffcf1 100644 --- a/cache.go +++ b/cache.go @@ -98,9 +98,15 @@ func (c *Cache) TrackingGet(key string) TrackedItem { return item } +// Used when the cache was created with the Track() configuration option. +// Sets the item, and returns a tracked reference to it. +func (c *Cache) TrackingSet(key string, value interface{}, duration time.Duration) TrackedItem { + return c.set(key, value, duration, true) +} + // Set the value in the cache for the specified duration func (c *Cache) Set(key string, value interface{}, duration time.Duration) { - c.set(key, value, duration) + c.set(key, value, duration, false) } // Replace the value if it exists, does not set if it doesn't. @@ -127,7 +133,7 @@ func (c *Cache) Fetch(key string, duration time.Duration, fetch func() (interfac if err != nil { return nil, err } - return c.set(key, value, duration), nil + return c.set(key, value, duration, false), nil } // Remove the item from the cache, return true if the item was present, false otherwise. @@ -182,8 +188,8 @@ func (c *Cache) deleteItem(bucket *bucket, item *Item) { c.deletables <- item } -func (c *Cache) set(key string, value interface{}, duration time.Duration) *Item { - item, existing := c.bucket(key).set(key, value, duration) +func (c *Cache) set(key string, value interface{}, duration time.Duration, track bool) *Item { + item, existing := c.bucket(key).set(key, value, duration, track) if existing != nil { c.deletables <- existing } diff --git a/cache_test.go b/cache_test.go index e128240..f3efa74 100644 --- a/cache_test.go +++ b/cache_test.go @@ -140,18 +140,21 @@ func (_ CacheTests) PromotedItemsDontGetPruned() { } func (_ CacheTests) TrackerDoesNotCleanupHeldInstance() { - cache := New(Configure().ItemsToPrune(10).Track()) - for i := 0; i < 10; i++ { + cache := New(Configure().ItemsToPrune(11).Track()) + item0 := cache.TrackingSet("0", 0, time.Minute) + for i := 1; i < 11; i++ { cache.Set(strconv.Itoa(i), i, time.Minute) } - item := cache.TrackingGet("0") + item1 := cache.TrackingGet("1") time.Sleep(time.Millisecond * 10) gcCache(cache) Expect(cache.Get("0").Value()).To.Equal(0) - Expect(cache.Get("1")).To.Equal(nil) - item.Release() + Expect(cache.Get("1").Value()).To.Equal(1) + item0.Release() + item1.Release() gcCache(cache) Expect(cache.Get("0")).To.Equal(nil) + Expect(cache.Get("1")).To.Equal(nil) } func (_ CacheTests) RemovesOldestItemWhenFull() { diff --git a/configuration_test.go b/configuration_test.go index d589c61..07c30a7 100644 --- a/configuration_test.go +++ b/configuration_test.go @@ -1,8 +1,9 @@ package ccache import ( - . "github.com/karlseguin/expect" "testing" + + . "github.com/karlseguin/expect" ) type ConfigurationTests struct{} diff --git a/item.go b/item.go index bb7c04f..0226129 100644 --- a/item.go +++ b/item.go @@ -52,18 +52,22 @@ type Item struct { element *list.Element } -func newItem(key string, value interface{}, expires int64) *Item { +func newItem(key string, value interface{}, expires int64, track bool) *Item { size := int64(1) if sized, ok := value.(Sized); ok { size = sized.Size() } - return &Item{ + item := &Item{ key: key, value: value, promotions: 0, size: size, expires: expires, } + if track { + item.refCount = 1 + } + return item } func (i *Item) shouldPromote(getsPerPromote int32) bool { diff --git a/layeredbucket.go b/layeredbucket.go index a0514e0..d3d2a0a 100644 --- a/layeredbucket.go +++ b/layeredbucket.go @@ -46,7 +46,7 @@ func (b *layeredBucket) set(primary, secondary string, value interface{}, durati b.buckets[primary] = bkt } b.Unlock() - item, existing := bkt.set(secondary, value, duration) + item, existing := bkt.set(secondary, value, duration, false) item.group = primary return item, existing } diff --git a/secondarycache.go b/secondarycache.go index f901fde..cd322c2 100644 --- a/secondarycache.go +++ b/secondarycache.go @@ -16,7 +16,7 @@ func (s *SecondaryCache) Get(secondary string) *Item { // Set the secondary key to a value. // The semantics are the same as for LayeredCache.Set func (s *SecondaryCache) Set(secondary string, value interface{}, duration time.Duration) *Item { - item, existing := s.bucket.set(secondary, value, duration) + item, existing := s.bucket.set(secondary, value, duration, false) if existing != nil { s.pCache.deletables <- existing } diff --git a/secondarycache_test.go b/secondarycache_test.go index fa1f891..09adbc5 100644 --- a/secondarycache_test.go +++ b/secondarycache_test.go @@ -1,10 +1,11 @@ package ccache import ( - . "github.com/karlseguin/expect" "strconv" "testing" "time" + + . "github.com/karlseguin/expect" ) type SecondaryCacheTests struct{}