77 lines
1.1 KiB
Go
77 lines
1.1 KiB
Go
package pokecache
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"sync"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
type cacheEntry struct {
|
||
|
|
val []byte
|
||
|
|
createdAt time.Time
|
||
|
|
}
|
||
|
|
|
||
|
|
type Cache struct {
|
||
|
|
entries map[string]cacheEntry
|
||
|
|
lock sync.Mutex
|
||
|
|
done chan struct{}
|
||
|
|
once sync.Once
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewCache(interval time.Duration) *Cache {
|
||
|
|
c := Cache{
|
||
|
|
entries: map[string]cacheEntry{},
|
||
|
|
done: make(chan struct{}),
|
||
|
|
}
|
||
|
|
|
||
|
|
go c.runReapLoop(interval)
|
||
|
|
|
||
|
|
return &c
|
||
|
|
}
|
||
|
|
|
||
|
|
func (c *Cache) runReapLoop(interval time.Duration) {
|
||
|
|
ticker := time.NewTicker(interval)
|
||
|
|
defer ticker.Stop()
|
||
|
|
|
||
|
|
for {
|
||
|
|
select {
|
||
|
|
case <-ticker.C:
|
||
|
|
c.lock.Lock()
|
||
|
|
|
||
|
|
for k, v := range c.entries {
|
||
|
|
if time.Since(v.createdAt) > interval {
|
||
|
|
delete(c.entries, k)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
c.lock.Unlock()
|
||
|
|
case <-c.done:
|
||
|
|
return
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (c *Cache) Add(key string, value []byte) {
|
||
|
|
c.lock.Lock()
|
||
|
|
defer c.lock.Unlock()
|
||
|
|
|
||
|
|
c.entries[key] = cacheEntry{
|
||
|
|
val: value,
|
||
|
|
createdAt: time.Now(),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (c *Cache) Get(key string) ([]byte, bool) {
|
||
|
|
c.lock.Lock()
|
||
|
|
defer c.lock.Unlock()
|
||
|
|
|
||
|
|
v, ok := c.entries[key]
|
||
|
|
|
||
|
|
return v.val, ok
|
||
|
|
}
|
||
|
|
|
||
|
|
func (c *Cache) Stop() {
|
||
|
|
c.once.Do(func() {
|
||
|
|
close(c.done)
|
||
|
|
})
|
||
|
|
}
|