replace is size-aware

This commit is contained in:
Karl Seguin 2014-11-21 15:45:11 +07:00
parent 41ccfbb39a
commit 78e597cdae
6 changed files with 72 additions and 9 deletions

View file

@ -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 {

View file

@ -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.

View file

@ -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

View file

@ -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)
}

View file

@ -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.

View file

@ -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))
}