diff --git a/bucket.go b/bucket.go index b0fd8bb..d70b4bb 100644 --- a/bucket.go +++ b/bucket.go @@ -22,13 +22,12 @@ func (b *bucket) set(key string, value interface{}, duration time.Duration) (*It b.Lock() defer b.Unlock() if existing, exists := b.lookup[key]; exists { - s := existing.size existing.value = value existing.expires = expires d := int64(0) if sized, ok := value.(Sized); ok { newSize := sized.Size() - d = newSize - s + d = newSize - existing.size if d != 0 { atomic.StoreInt64(&existing.size, newSize) } @@ -40,15 +39,23 @@ func (b *bucket) set(key string, value interface{}, duration time.Duration) (*It return item, true, int64(item.size) } -func (b *bucket) replace(key string, value interface{}) bool { +func (b *bucket) replace(key string, value interface{}) (bool, int64) { b.Lock() defer b.Unlock() existing, exists := b.lookup[key] if exists == false { - return false + return false, 0 + } + d := int64(0) + if sized, ok := value.(Sized); ok { + newSize := sized.Size() + d = newSize - existing.size + if d != 0 { + atomic.StoreInt64(&existing.size, newSize) + } } existing.value = value - return true + return true, d } func (b *bucket) delete(key string) *Item { diff --git a/cache.go b/cache.go index 5561af8..daf251b 100644 --- a/cache.go +++ b/cache.go @@ -82,7 +82,11 @@ func (c *Cache) Set(key string, value interface{}, duration time.Duration) { // Returns true if the item existed an was replaced, false otherwise. // Replace does not reset item's TTL nor does it alter its position in the LRU func (c *Cache) Replace(key string, value interface{}) bool { - return c.bucket(key).replace(key, value) + exists, d := c.bucket(key).replace(key, value) + if d != 0 { + atomic.AddInt64(&c.size, d) + } + return exists } // Attempts to get the value from the cache and calles fetch on a miss. diff --git a/cache_test.go b/cache_test.go index 088bff2..1bbc5d3 100644 --- a/cache_test.go +++ b/cache_test.go @@ -102,6 +102,30 @@ func (_ CacheTests) SetUpdatesSizeOnDelta() { Expect(cache.size).To.Equal(int64(2)) } +func (_ CacheTests) ReplaceDoesNotchangeSizeIfNotSet() { + cache := New(Configure()) + cache.Set("1", &SizedItem{1, 2}, time.Minute) + cache.Set("2", &SizedItem{1, 2}, time.Minute) + cache.Set("3", &SizedItem{1, 2}, time.Minute) + cache.Replace("4", &SizedItem{1, 2}) + Expect(cache.size).To.Equal(int64(6)) +} + +func (_ CacheTests) ReplaceChangesSize() { + cache := New(Configure()) + cache.Set("1", &SizedItem{1, 2}, time.Minute) + cache.Set("2", &SizedItem{1, 2}, time.Minute) + + cache.Replace("2", &SizedItem{1, 2}) + Expect(cache.size).To.Equal(int64(4)) + + cache.Replace("2", &SizedItem{1, 1}) + Expect(cache.size).To.Equal(int64(3)) + + cache.Replace("2", &SizedItem{1, 3}) + Expect(cache.size).To.Equal(int64(5)) +} + type SizedItem struct { id int s int64 diff --git a/layeredbucket.go b/layeredbucket.go index 73a0ddc..b541c76 100644 --- a/layeredbucket.go +++ b/layeredbucket.go @@ -35,12 +35,12 @@ func (b *layeredBucket) set(primary, secondary string, value interface{}, durati return item, new, d } -func (b *layeredBucket) replace(primary, secondary string, value interface{}) bool { +func (b *layeredBucket) replace(primary, secondary string, value interface{}) (bool, int64) { b.Lock() bucket, exists := b.buckets[primary] b.Unlock() if exists == false { - return false + return false, 0 } return bucket.replace(secondary, value) } diff --git a/layeredcache.go b/layeredcache.go index 77d817c..79f6d20 100644 --- a/layeredcache.go +++ b/layeredcache.go @@ -93,7 +93,11 @@ func (c *LayeredCache) Set(primary, secondary string, value interface{}, duratio // Returns true if the item existed an was replaced, false otherwise. // Replace does not reset item's TTL nor does it alter its position in the LRU func (c *LayeredCache) Replace(primary, secondary string, value interface{}) bool { - return c.bucket(primary).replace(primary, secondary, value) + exists, d := c.bucket(primary).replace(primary, secondary, value) + if d != 0 { + atomic.AddInt64(&c.size, d) + } + return exists } // Attempts to get the value from the cache and calles fetch on a miss. diff --git a/layeredcache_test.go b/layeredcache_test.go index fde1439..67dfa5c 100644 --- a/layeredcache_test.go +++ b/layeredcache_test.go @@ -171,3 +171,27 @@ func (_ LayeredCacheTests) SetUpdatesSizeOnDelta() { time.Sleep(time.Millisecond * 10) Expect(cache.size).To.Equal(int64(5)) } + +func (_ LayeredCacheTests) ReplaceDoesNotchangeSizeIfNotSet() { + cache := Layered(Configure()) + cache.Set("pri", "1", &SizedItem{1, 2}, time.Minute) + cache.Set("pri", "2", &SizedItem{1, 2}, time.Minute) + cache.Set("pri", "3", &SizedItem{1, 2}, time.Minute) + cache.Replace("sec", "3", &SizedItem{1, 2}) + Expect(cache.size).To.Equal(int64(6)) +} + +func (_ LayeredCacheTests) ReplaceChangesSize() { + cache := Layered(Configure()) + cache.Set("pri", "1", &SizedItem{1, 2}, time.Minute) + cache.Set("pri", "2", &SizedItem{1, 2}, time.Minute) + + cache.Replace("pri", "2", &SizedItem{1, 2}) + Expect(cache.size).To.Equal(int64(4)) + + cache.Replace("pri", "2", &SizedItem{1, 1}) + Expect(cache.size).To.Equal(int64(3)) + + cache.Replace("pri", "2", &SizedItem{1, 3}) + Expect(cache.size).To.Equal(int64(5)) +}