1package lru 2 3import ( 4 "sync" 5 6 "github.com/hashicorp/golang-lru/simplelru" 7) 8 9// Cache is a thread-safe fixed size LRU cache. 10type Cache struct { 11 lru simplelru.LRUCache 12 lock sync.RWMutex 13} 14 15// New creates an LRU of the given size. 16func New(size int) (*Cache, error) { 17 return NewWithEvict(size, nil) 18} 19 20// NewWithEvict constructs a fixed size cache with the given eviction 21// callback. 22func NewWithEvict(size int, onEvicted func(key interface{}, value interface{})) (*Cache, error) { 23 lru, err := simplelru.NewLRU(size, simplelru.EvictCallback(onEvicted)) 24 if err != nil { 25 return nil, err 26 } 27 c := &Cache{ 28 lru: lru, 29 } 30 return c, nil 31} 32 33// Purge is used to completely clear the cache. 34func (c *Cache) Purge() { 35 c.lock.Lock() 36 c.lru.Purge() 37 c.lock.Unlock() 38} 39 40// Add adds a value to the cache. Returns true if an eviction occurred. 41func (c *Cache) Add(key, value interface{}) (evicted bool) { 42 c.lock.Lock() 43 evicted = c.lru.Add(key, value) 44 c.lock.Unlock() 45 return evicted 46} 47 48// Get looks up a key's value from the cache. 49func (c *Cache) Get(key interface{}) (value interface{}, ok bool) { 50 c.lock.Lock() 51 value, ok = c.lru.Get(key) 52 c.lock.Unlock() 53 return value, ok 54} 55 56// Contains checks if a key is in the cache, without updating the 57// recent-ness or deleting it for being stale. 58func (c *Cache) Contains(key interface{}) bool { 59 c.lock.RLock() 60 containKey := c.lru.Contains(key) 61 c.lock.RUnlock() 62 return containKey 63} 64 65// Peek returns the key value (or undefined if not found) without updating 66// the "recently used"-ness of the key. 67func (c *Cache) Peek(key interface{}) (value interface{}, ok bool) { 68 c.lock.RLock() 69 value, ok = c.lru.Peek(key) 70 c.lock.RUnlock() 71 return value, ok 72} 73 74// ContainsOrAdd checks if a key is in the cache without updating the 75// recent-ness or deleting it for being stale, and if not, adds the value. 76// Returns whether found and whether an eviction occurred. 77func (c *Cache) ContainsOrAdd(key, value interface{}) (ok, evicted bool) { 78 c.lock.Lock() 79 defer c.lock.Unlock() 80 81 if c.lru.Contains(key) { 82 return true, false 83 } 84 evicted = c.lru.Add(key, value) 85 return false, evicted 86} 87 88// PeekOrAdd checks if a key is in the cache without updating the 89// recent-ness or deleting it for being stale, and if not, adds the value. 90// Returns whether found and whether an eviction occurred. 91func (c *Cache) PeekOrAdd(key, value interface{}) (previous interface{}, ok, evicted bool) { 92 c.lock.Lock() 93 defer c.lock.Unlock() 94 95 previous, ok = c.lru.Peek(key) 96 if ok { 97 return previous, true, false 98 } 99 100 evicted = c.lru.Add(key, value) 101 return nil, false, evicted 102} 103 104// Remove removes the provided key from the cache. 105func (c *Cache) Remove(key interface{}) (present bool) { 106 c.lock.Lock() 107 present = c.lru.Remove(key) 108 c.lock.Unlock() 109 return 110} 111 112// Resize changes the cache size. 113func (c *Cache) Resize(size int) (evicted int) { 114 c.lock.Lock() 115 evicted = c.lru.Resize(size) 116 c.lock.Unlock() 117 return evicted 118} 119 120// RemoveOldest removes the oldest item from the cache. 121func (c *Cache) RemoveOldest() (key interface{}, value interface{}, ok bool) { 122 c.lock.Lock() 123 key, value, ok = c.lru.RemoveOldest() 124 c.lock.Unlock() 125 return 126} 127 128// GetOldest returns the oldest entry 129func (c *Cache) GetOldest() (key interface{}, value interface{}, ok bool) { 130 c.lock.Lock() 131 key, value, ok = c.lru.GetOldest() 132 c.lock.Unlock() 133 return 134} 135 136// Keys returns a slice of the keys in the cache, from oldest to newest. 137func (c *Cache) Keys() []interface{} { 138 c.lock.RLock() 139 keys := c.lru.Keys() 140 c.lock.RUnlock() 141 return keys 142} 143 144// Len returns the number of items in the cache. 145func (c *Cache) Len() int { 146 c.lock.RLock() 147 length := c.lru.Len() 148 c.lock.RUnlock() 149 return length 150} 151