-
Notifications
You must be signed in to change notification settings - Fork 0
/
golru.go
122 lines (106 loc) · 2.29 KB
/
golru.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
115
116
117
118
119
120
121
122
// A simple LRU cache for storing documents ([]byte). When the size maximum is reached, items are evicted
// with an approximated LRU (least recently used) policy. This data structure is goroutine-safe (it has a lock around all
// operations).
package golru
import (
"math"
"sync"
)
const (
DefaultLRUSamples int = 5
)
type (
item struct {
index uint64
value []byte
}
Cache struct {
sync.Mutex
Capacity int
index uint64
samples int
table map[string]*item
}
)
// Creates a new Cache with a maximum size of items and the number of samples used to evict the LRU entries.
// If samples <= 0, DefaultLRUSamples is used. 5 by default.
func New(capacity, samples int) *Cache {
if samples <= 0 {
samples = DefaultLRUSamples
}
return &Cache{
Capacity: capacity,
index: 0,
samples: samples,
table: make(map[string]*item, capacity+2),
}
}
// Returns the total number of entries in the cache
func (c *Cache) Len() int {
c.Lock()
defer c.Unlock()
return len(c.table)
}
// Insert some {key, document} into the cache. If the key already exists it would be overwritten.
func (c *Cache) Set(key string, document []byte) {
c.Lock()
defer func() {
c.index++
c.Unlock()
}()
c.table[key] = &item{c.index, document}
c.trim()
}
// Removes all the entries in the cache
func (c *Cache) Flush() {
c.Lock()
defer c.Unlock()
for k := range c.table {
delete(c.table, k)
}
c.index = 0
}
// Get retrieves a value from the cache, it would return nil is the entry is not present
func (c *Cache) Get(key string) []byte {
c.Lock()
defer func() {
c.index++
c.Unlock()
}()
if elt, ok := c.table[key]; ok == true {
elt.index = c.index
return elt.value
} else {
return nil
}
}
// Delete the document indicated by the key, if it is present.
func (c *Cache) Del(key string) {
c.Lock()
defer c.Unlock()
delete(c.table, key)
}
func (c *Cache) trim() {
toremove := len(c.table) - c.Capacity
if toremove == 1 {
var (
keyToRemove string = ""
min uint64 = math.MaxUint64
i int = 0
iterations int = toremove * c.samples
)
for key, value := range c.table {
if value.index < min {
min = value.index
keyToRemove = key
}
i++
if i >= iterations {
break
}
}
if keyToRemove != "" {
delete(c.table, keyToRemove)
}
}
}