diff --git a/kvmemcache/cache.go b/kvmemcache/cache.go index 9baeb8a..72041e5 100644 --- a/kvmemcache/cache.go +++ b/kvmemcache/cache.go @@ -35,8 +35,9 @@ type Config struct { } type Stats struct { - Hits uint64 - Misses uint64 + Hits uint64 + Misses uint64 + Expired uint64 } func New(conf Config) *Cache { @@ -55,7 +56,6 @@ func (c *Cache) Get(key string) (interface{}, error) { item := c.getItem(key) if item == nil { item = c.loadItemFromSource(key) - } return item.value, item.err } @@ -66,7 +66,7 @@ func (c *Cache) Evict(key string) { c.evictKey(key) } -func (c Cache) GetStats() Stats { +func (c Cache) Stats() Stats { c.lock.Lock() defer c.lock.Unlock() return c.stats diff --git a/kvmemcache/cache_test.go b/kvmemcache/cache_test.go index 1cb901e..593529f 100644 --- a/kvmemcache/cache_test.go +++ b/kvmemcache/cache_test.go @@ -8,7 +8,8 @@ import ( ) func testRunner(c *Cache, t *testing.T, done chan bool) { - for i := 0; i < 2000000; i++ { + rand.Seed(time.Now().UnixNano()) + for i := 0; i < 200001; i++ { x := rand.Int31n(50) if rand.Float64() < 0.01 { x = rand.Int31n(9999) @@ -42,11 +43,12 @@ func testCache(name string, c *Cache, t *testing.T) { <-done } - stats := c.GetStats() + stats := c.Stats() fmt.Println(name) - fmt.Printf(" Hits: %d\n", stats.Hits) - fmt.Printf(" Misses: %d\n", stats.Misses) + fmt.Printf(" Hits: %d\n", stats.Hits) + fmt.Printf(" Misses: %d\n", stats.Misses) + fmt.Printf(" Expired: %d\n", stats.Expired) fmt.Printf(" Hit-rate: %.2f%%\n", 100*float64(stats.Hits)/float64(stats.Hits+stats.Misses)) } @@ -54,10 +56,43 @@ func testCache(name string, c *Cache, t *testing.T) { func TestCache(t *testing.T) { c := New(Config{ MaxSize: 2048, - TTL: time.Second, + TTL: 100 * time.Millisecond, Src: func(key string) (interface{}, error) { return fmt.Sprintf("value for %s", key), nil }, }) testCache("LRUTimeout", c, t) } + +func TestCacheTTL(t *testing.T) { + c := New(Config{ + MaxSize: 2048, + TTL: 100 * time.Millisecond, + Src: func(key string) (interface{}, error) { + return key, nil + }, + }) + + c.Get("a") + c.Get("b") + time.Sleep(50 * time.Millisecond) + c.Get("a") + c.Get("b") + c.Get("c") + + stats := c.Stats() + if stats.Expired != 0 { + t.Fatal(stats.Expired) + } + + time.Sleep(50 * time.Millisecond) + c.Get("a") + c.Get("b") + c.Get("c") + + stats = c.Stats() + if stats.Expired != 2 { + t.Fatal(stats.Expired) + } + +} diff --git a/kvmemcache/internal.go b/kvmemcache/internal.go index 34ffe5f..a1a89d5 100644 --- a/kvmemcache/internal.go +++ b/kvmemcache/internal.go @@ -1,26 +1,28 @@ package kvmemcache -import "time" +import ( + "time" +) func (c *Cache) getItem(key string) *lruItem { c.lock.Lock() defer c.lock.Unlock() - li, ok := c.cache[key] + elem, ok := c.cache[key] if !ok { c.stats.Misses++ return nil } - item := li.Value.(*lruItem) + item := elem.Value.(*lruItem) if c.ttl != 0 && time.Since(item.createdAt) > c.ttl { + c.stats.Expired++ c.evictKey(key) - c.stats.Misses++ return nil } c.stats.Hits++ - c.ll.MoveToFront(li) + c.ll.MoveToFront(elem) return item } @@ -55,9 +57,9 @@ func (c *Cache) putItem(key string, item *lruItem) { c.cache[key] = c.ll.PushFront(item) if c.maxSize > 0 && len(c.cache) > c.maxSize { - li := c.ll.Back() - c.ll.Remove(li) - delete(c.cache, li.Value.(*lruItem).key) + elem := c.ll.Back() + c.ll.Remove(elem) + delete(c.cache, elem.Value.(*lruItem).key) } }