@@ -40,6 +40,7 @@ type Cache struct {
40
40
wg sync.WaitGroup
41
41
mu sync.RWMutex
42
42
onceLoop sync.Once
43
+ loopMu sync.Mutex
43
44
lfuEnabled bool
44
45
list * ringList
45
46
afterEvict EvictionCallback
@@ -52,7 +53,7 @@ type Builder func(*Cache)
52
53
// New creates an empty cache.
53
54
//
54
55
// Cache must be closed after usage has stopped
55
- // to prevent a leaking goroutine .
56
+ // to prevent a leaking resources .
56
57
//
57
58
// It is not safe to close the cache while in use.
58
59
func New () Builder {
@@ -228,15 +229,41 @@ func (c *Cache) Range(f func(key, value interface{}) bool) {
228
229
})
229
230
}
230
231
231
- // Evict a key. After Evict returns, no Get or Fetch will load the key.
232
- func (c * Cache ) Evict (key interface {}) {
233
- c .mu .RLock ()
234
- defer c .mu .RUnlock ()
235
- r , ok := c .records .LoadAndDelete (key )
236
- if ! ok {
237
- return
232
+ // Do calls f sequentially for each key and value present in the cache
233
+ // in order. If f returns false, Do stops the iteration.
234
+ // When LFU is used, the order is from least to most frequently used,
235
+ // otherwise it is the insertion order with eldest first by default.
236
+ //
237
+ // It is not safe to use Do concurrently with any other method
238
+ // except Exists and Get or a deadlock may occur. f is not allowed
239
+ // to modify the cache.
240
+ func (c * Cache ) Do (f func (key , value interface {}) bool ) {
241
+ c .loopMu .Lock ()
242
+ defer c .loopMu .Unlock ()
243
+ c .list .Do (func (key interface {}) bool {
244
+ r , ok := c .records .Load (key )
245
+ if ! ok {
246
+ panic ("evcache: Do used concurrently" )
247
+ }
248
+ v , ok := r .(* record ).Load ()
249
+ if ! ok {
250
+ panic ("evcache: Do used concurrently" )
251
+ }
252
+ return f (key , v )
253
+ })
254
+ }
255
+
256
+ // Pop evicts and returns the oldest key and value. If LFU ordering is
257
+ // enabled, then the least frequently used key and value.
258
+ func (c * Cache ) Pop () (key , value interface {}) {
259
+ for {
260
+ if key = c .list .Pop (); key == nil {
261
+ return nil , nil
262
+ }
263
+ if value , ok := c .LoadAndEvict (key ); ok {
264
+ return key , value
265
+ }
238
266
}
239
- c .finalizeAsync (key , r .(* record ))
240
267
}
241
268
242
269
// LoadAndEvict evicts a key and returns its value.
@@ -251,17 +278,15 @@ func (c *Cache) LoadAndEvict(key interface{}) (interface{}, bool) {
251
278
return c .finalizeSync (key , r .(* record ))
252
279
}
253
280
254
- // Pop evicts and returns the oldest key and value. If LFU ordering is
255
- // enabled, then the least frequently used key and value.
256
- func (c * Cache ) Pop () (key , value interface {}) {
257
- for {
258
- if key = c .list .Pop (); key == nil {
259
- return nil , nil
260
- }
261
- if value , ok := c .LoadAndEvict (key ); ok {
262
- return key , value
263
- }
281
+ // Evict a key and its value from the cache.
282
+ func (c * Cache ) Evict (key interface {}) {
283
+ c .mu .RLock ()
284
+ defer c .mu .RUnlock ()
285
+ r , ok := c .records .LoadAndDelete (key )
286
+ if ! ok {
287
+ return
264
288
}
289
+ c .finalizeAsync (key , r .(* record ))
265
290
}
266
291
267
292
// Flush evicts all keys from the cache.
@@ -367,7 +392,9 @@ func (c *Cache) runLoop() {
367
392
case <- c .stopLoop :
368
393
return
369
394
case now := <- ticker .C :
395
+ c .loopMu .Lock ()
370
396
c .processRecords (now .UnixNano ())
397
+ c .loopMu .Unlock ()
371
398
}
372
399
}
373
400
}()
0 commit comments