/
lru.go
61 lines (49 loc) · 1.36 KB
/
lru.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package util
import (
"sync"
"time"
lru "github.com/hashicorp/golang-lru"
)
// expirableValue is used to hold value with expiration
type expirableValue struct {
value interface{}
expiresAt time.Time
}
// ExpirableLruCache naive implementation of LRU cache with fixed TTL expiration duration.
// This cache uses a lazy eviction policy, by which the expired entry will be purged when
// it's being looked up.
type ExpirableLruCache struct {
lru *lru.Cache
mu sync.Mutex
ttl time.Duration
}
func NewExpirableLruCache(size int, ttl time.Duration) (*ExpirableLruCache, error) {
cache, err := lru.New(size)
return &ExpirableLruCache{lru: cache, ttl: ttl}, err
}
// Add adds a value to the cache. Returns true if an eviction occurred.
func (c *ExpirableLruCache) Add(key, value interface{}) bool {
c.mu.Lock()
defer c.mu.Unlock()
ev := &expirableValue{
value: value,
expiresAt: time.Now().Add(c.ttl),
}
return c.lru.Add(key, ev)
}
// Get looks up a key's value from the cache. Will purge the entry and return nil
// if the entry expired.
func (c *ExpirableLruCache) Get(key interface{}) (interface{}, bool) {
c.mu.Lock()
defer c.mu.Unlock()
cv, ok := c.lru.Get(key) // not found
if !ok {
return nil, false
}
ev := cv.(*expirableValue)
if ev.expiresAt.Before(time.Now()) { // expired
c.lru.Remove(key)
return nil, false
}
return ev.value, true
}