master
jdl 2021-04-02 20:57:08 +02:00
parent 5cab19280e
commit bd37278092
3 changed files with 54 additions and 17 deletions

View File

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

View File

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

View File

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