replace is size-aware
This commit is contained in:
parent
41ccfbb39a
commit
78e597cdae
17
bucket.go
17
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 {
|
||||
|
|
6
cache.go
6
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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue