Implemented map functions + caching@
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
package pokecache
|
||||
|
||||
import (
|
||||
"time"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type cacheEntry struct {
|
||||
createdAt time.Time
|
||||
val []byte
|
||||
}
|
||||
|
||||
type Cache struct {
|
||||
PokeCache map[string]cacheEntry
|
||||
Interval time.Duration
|
||||
Mu sync.Mutex
|
||||
}
|
||||
|
||||
func (c *Cache) Add(key string, val []byte) {
|
||||
newEntry := cacheEntry{
|
||||
createdAt: time.Now(),
|
||||
val: val,
|
||||
}
|
||||
c.Mu.Lock()
|
||||
defer c.Mu.Unlock()
|
||||
c.PokeCache[key] = newEntry
|
||||
}
|
||||
|
||||
func (c *Cache) Get(key string) ([]byte, bool) {
|
||||
c.Mu.Lock()
|
||||
|
||||
defer c.Mu.Unlock()
|
||||
cache, exists := c.PokeCache[key]
|
||||
if !exists {
|
||||
return nil, false
|
||||
}
|
||||
return cache.val, true
|
||||
}
|
||||
|
||||
func (c *Cache) reapLoop() {
|
||||
ticker := time.NewTicker(c.Interval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for range ticker.C {
|
||||
c.Mu.Lock()
|
||||
for k, v := range c.PokeCache {
|
||||
if time.Since(v.createdAt) > c.Interval {
|
||||
delete(c.PokeCache, k)
|
||||
}
|
||||
}
|
||||
c.Mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func NewCache(interval time.Duration) *Cache {
|
||||
newCache := Cache{
|
||||
PokeCache: map[string]cacheEntry{},
|
||||
Interval: interval,
|
||||
Mu: sync.Mutex{},
|
||||
}
|
||||
go newCache.reapLoop()
|
||||
return &newCache
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package pokecache
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
|
||||
func TestAddGet(t *testing.T) {
|
||||
const interval = 5 * time.Second
|
||||
cases := []struct {
|
||||
key string
|
||||
val []byte
|
||||
}{
|
||||
{
|
||||
key: "https://example.com",
|
||||
val: []byte("testdata"),
|
||||
},
|
||||
{
|
||||
key: "https://example.com/path",
|
||||
val: []byte("moretestdata"),
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
t.Run(fmt.Sprintf("Test case %v", i), func(t *testing.T) {
|
||||
cache := NewCache(interval)
|
||||
cache.Add(c.key, c.val)
|
||||
val, ok := cache.Get(c.key)
|
||||
if !ok {
|
||||
t.Errorf("expected to find key")
|
||||
return
|
||||
}
|
||||
if string(val) != string(c.val) {
|
||||
t.Errorf("expected to find value")
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetNonexistent(t *testing.T) {
|
||||
const interval = 2 * time.Second
|
||||
cache := NewCache(interval)
|
||||
value, ok := cache.Get("http://does.not.exist/")
|
||||
if ok || (value != nil) {
|
||||
t.Errorf("expected cache miss")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReapLoop(t *testing.T) {
|
||||
const baseTime = 5 * time.Millisecond
|
||||
const waitTime = baseTime + 5*time.Millisecond
|
||||
cache := NewCache(baseTime)
|
||||
cache.Add("https://example.com", []byte("testdata"))
|
||||
|
||||
_, ok := cache.Get("https://example.com")
|
||||
if !ok {
|
||||
t.Errorf("expected to find key")
|
||||
return
|
||||
}
|
||||
|
||||
time.Sleep(waitTime)
|
||||
|
||||
_, ok = cache.Get("https://example.com")
|
||||
if ok {
|
||||
t.Errorf("expected to not find key")
|
||||
return
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user