-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlru_base.go
114 lines (100 loc) · 2.52 KB
/
lru_base.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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Package go-lru implements an LRU cache.
// It is based on the
// LRU implementation in groupcache:
// https://github.com/golang/groupcache/tree/master/lru
package lru
import (
"container/list"
"time"
)
type cacheBase struct {
Expiry time.Duration
Size int
// OnEvicted optionally specifies a callback function to be
// executed when an entry is purged from the cache.
OnEvicted func(key string, value interface{})
ll *list.List
cache map[string]*list.Element
}
type entry struct {
key string
value interface{}
timeInsert int64
}
func newCacheBase(size int) *cacheBase {
return &cacheBase{Size: size, cache: make(map[string]*list.Element), ll: list.New()}
}
func (c *cacheBase) Add(key string, value interface{}) {
var epochNow int64
if c.Expiry != time.Duration(0) {
epochNow = time.Now().UnixNano() / int64(time.Millisecond)
}
if ee, ok := c.cache[key]; ok {
c.ll.MoveToFront(ee)
ee.Value.(*entry).value = value
ee.Value.(*entry).timeInsert = epochNow
return
}
ele := c.ll.PushFront(&entry{key, value, epochNow})
c.cache[key] = ele
if c.Size != 0 && c.ll.Len() > c.Size {
c.RemoveOldest()
}
return
}
func (c *cacheBase) Get(key string) (value interface{}, ok bool) {
if ele, hit := c.cache[key]; hit {
if c.Expiry != time.Duration(0) {
unixNow := time.Now().UnixNano() / int64(time.Millisecond)
unixExpiry := int64(c.Expiry / time.Millisecond)
if (unixNow - ele.Value.(*entry).timeInsert) > unixExpiry {
c.removeElement(ele)
return nil, false
}
}
c.ll.MoveToFront(ele)
return ele.Value.(*entry).value, true
}
return nil, false
}
// Updates element's value without updating it's "Least-Recently-Used" status
func (c *cacheBase) UpdateElement(key string, value interface{}) {
if ee, ok := c.cache[key]; ok {
ee.Value.(*entry).value = value
return
}
}
func (c *cacheBase) Remove(key string) {
if ele, hit := c.cache[key]; hit {
c.removeElement(ele)
}
}
func (c *cacheBase) RemoveOldest() {
ele := c.ll.Back()
if ele != nil {
c.removeElement(ele)
}
}
func (c *cacheBase) removeElement(e *list.Element) {
c.ll.Remove(e)
kv := e.Value.(*entry)
delete(c.cache, kv.key)
if c.OnEvicted != nil {
c.OnEvicted(kv.key, kv.value)
}
}
// Len returns the number of items in the cache.
func (c *cacheBase) Len() int {
return c.ll.Len()
}
// Clear purges all stored items from the cache.
func (c *cacheBase) Clear() {
for _, e := range c.cache {
kv := e.Value.(*entry)
if c.OnEvicted != nil {
c.OnEvicted(kv.key, kv.value)
}
delete(c.cache, kv.key)
}
c.ll.Init()
}