...
1 package lru
2
3 import (
4 "sync"
5
6 "github.com/hashicorp/golang-lru/simplelru"
7 )
8
9
10
11
12
13
14
15
16
17 type ARCCache struct {
18 size int
19 p int
20
21 t1 simplelru.LRUCache
22 b1 simplelru.LRUCache
23
24 t2 simplelru.LRUCache
25 b2 simplelru.LRUCache
26
27 lock sync.RWMutex
28 }
29
30
31 func NewARC(size int) (*ARCCache, error) {
32
33 b1, err := simplelru.NewLRU(size, nil)
34 if err != nil {
35 return nil, err
36 }
37 b2, err := simplelru.NewLRU(size, nil)
38 if err != nil {
39 return nil, err
40 }
41 t1, err := simplelru.NewLRU(size, nil)
42 if err != nil {
43 return nil, err
44 }
45 t2, err := simplelru.NewLRU(size, nil)
46 if err != nil {
47 return nil, err
48 }
49
50
51 c := &ARCCache{
52 size: size,
53 p: 0,
54 t1: t1,
55 b1: b1,
56 t2: t2,
57 b2: b2,
58 }
59 return c, nil
60 }
61
62
63 func (c *ARCCache) Get(key interface{}) (value interface{}, ok bool) {
64 c.lock.Lock()
65 defer c.lock.Unlock()
66
67
68
69 if val, ok := c.t1.Peek(key); ok {
70 c.t1.Remove(key)
71 c.t2.Add(key, val)
72 return val, ok
73 }
74
75
76 if val, ok := c.t2.Get(key); ok {
77 return val, ok
78 }
79
80
81 return nil, false
82 }
83
84
85 func (c *ARCCache) Add(key, value interface{}) {
86 c.lock.Lock()
87 defer c.lock.Unlock()
88
89
90
91 if c.t1.Contains(key) {
92 c.t1.Remove(key)
93 c.t2.Add(key, value)
94 return
95 }
96
97
98 if c.t2.Contains(key) {
99 c.t2.Add(key, value)
100 return
101 }
102
103
104
105 if c.b1.Contains(key) {
106
107 delta := 1
108 b1Len := c.b1.Len()
109 b2Len := c.b2.Len()
110 if b2Len > b1Len {
111 delta = b2Len / b1Len
112 }
113 if c.p+delta >= c.size {
114 c.p = c.size
115 } else {
116 c.p += delta
117 }
118
119
120 if c.t1.Len()+c.t2.Len() >= c.size {
121 c.replace(false)
122 }
123
124
125 c.b1.Remove(key)
126
127
128 c.t2.Add(key, value)
129 return
130 }
131
132
133
134 if c.b2.Contains(key) {
135
136 delta := 1
137 b1Len := c.b1.Len()
138 b2Len := c.b2.Len()
139 if b1Len > b2Len {
140 delta = b1Len / b2Len
141 }
142 if delta >= c.p {
143 c.p = 0
144 } else {
145 c.p -= delta
146 }
147
148
149 if c.t1.Len()+c.t2.Len() >= c.size {
150 c.replace(true)
151 }
152
153
154 c.b2.Remove(key)
155
156
157 c.t2.Add(key, value)
158 return
159 }
160
161
162 if c.t1.Len()+c.t2.Len() >= c.size {
163 c.replace(false)
164 }
165
166
167 if c.b1.Len() > c.size-c.p {
168 c.b1.RemoveOldest()
169 }
170 if c.b2.Len() > c.p {
171 c.b2.RemoveOldest()
172 }
173
174
175 c.t1.Add(key, value)
176 }
177
178
179
180 func (c *ARCCache) replace(b2ContainsKey bool) {
181 t1Len := c.t1.Len()
182 if t1Len > 0 && (t1Len > c.p || (t1Len == c.p && b2ContainsKey)) {
183 k, _, ok := c.t1.RemoveOldest()
184 if ok {
185 c.b1.Add(k, nil)
186 }
187 } else {
188 k, _, ok := c.t2.RemoveOldest()
189 if ok {
190 c.b2.Add(k, nil)
191 }
192 }
193 }
194
195
196 func (c *ARCCache) Len() int {
197 c.lock.RLock()
198 defer c.lock.RUnlock()
199 return c.t1.Len() + c.t2.Len()
200 }
201
202
203 func (c *ARCCache) Keys() []interface{} {
204 c.lock.RLock()
205 defer c.lock.RUnlock()
206 k1 := c.t1.Keys()
207 k2 := c.t2.Keys()
208 return append(k1, k2...)
209 }
210
211
212 func (c *ARCCache) Remove(key interface{}) {
213 c.lock.Lock()
214 defer c.lock.Unlock()
215 if c.t1.Remove(key) {
216 return
217 }
218 if c.t2.Remove(key) {
219 return
220 }
221 if c.b1.Remove(key) {
222 return
223 }
224 if c.b2.Remove(key) {
225 return
226 }
227 }
228
229
230 func (c *ARCCache) Purge() {
231 c.lock.Lock()
232 defer c.lock.Unlock()
233 c.t1.Purge()
234 c.t2.Purge()
235 c.b1.Purge()
236 c.b2.Purge()
237 }
238
239
240
241 func (c *ARCCache) Contains(key interface{}) bool {
242 c.lock.RLock()
243 defer c.lock.RUnlock()
244 return c.t1.Contains(key) || c.t2.Contains(key)
245 }
246
247
248
249 func (c *ARCCache) Peek(key interface{}) (value interface{}, ok bool) {
250 c.lock.RLock()
251 defer c.lock.RUnlock()
252 if val, ok := c.t1.Peek(key); ok {
253 return val, ok
254 }
255 return c.t2.Peek(key)
256 }
257
View as plain text