|
|
@ -82,12 +82,7 @@ func (c *Cache) Del(key string) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Cache) Get(key string) (interface{}, bool) {
|
|
|
|
func (c *Cache) Get(key string) (interface{}, bool) {
|
|
|
|
c.lock.Lock()
|
|
|
|
value, ok := c.doGet(key)
|
|
|
|
value, ok := c.data[key]
|
|
|
|
|
|
|
|
if ok {
|
|
|
|
|
|
|
|
c.lruCache.add(key)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
c.lock.Unlock()
|
|
|
|
|
|
|
|
if ok {
|
|
|
|
if ok {
|
|
|
|
c.stats.IncrementHit()
|
|
|
|
c.stats.IncrementHit()
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
@ -113,12 +108,25 @@ func (c *Cache) Set(key string, value interface{}) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Cache) Take(key string, fetch func() (interface{}, error)) (interface{}, error) {
|
|
|
|
func (c *Cache) Take(key string, fetch func() (interface{}, error)) (interface{}, error) {
|
|
|
|
val, fresh, err := c.barrier.DoEx(key, func() (interface{}, error) {
|
|
|
|
if val, ok := c.doGet(key); ok {
|
|
|
|
|
|
|
|
c.stats.IncrementHit()
|
|
|
|
|
|
|
|
return val, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var fresh bool
|
|
|
|
|
|
|
|
val, err := c.barrier.Do(key, func() (interface{}, error) {
|
|
|
|
|
|
|
|
// because O(1) on map search in memory, and fetch is an IO query
|
|
|
|
|
|
|
|
// so we do double check, cache might be taken by another call
|
|
|
|
|
|
|
|
if val, ok := c.doGet(key); ok {
|
|
|
|
|
|
|
|
return val, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
v, e := fetch()
|
|
|
|
v, e := fetch()
|
|
|
|
if e != nil {
|
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
return nil, e
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fresh = true
|
|
|
|
c.Set(key, v)
|
|
|
|
c.Set(key, v)
|
|
|
|
return v, nil
|
|
|
|
return v, nil
|
|
|
|
})
|
|
|
|
})
|
|
|
@ -137,6 +145,18 @@ func (c *Cache) Take(key string, fetch func() (interface{}, error)) (interface{}
|
|
|
|
return val, nil
|
|
|
|
return val, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Cache) doGet(key string) (interface{}, bool) {
|
|
|
|
|
|
|
|
c.lock.Lock()
|
|
|
|
|
|
|
|
defer c.lock.Unlock()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
value, ok := c.data[key]
|
|
|
|
|
|
|
|
if ok {
|
|
|
|
|
|
|
|
c.lruCache.add(key)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return value, ok
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (c *Cache) onEvict(key string) {
|
|
|
|
func (c *Cache) onEvict(key string) {
|
|
|
|
// already locked
|
|
|
|
// already locked
|
|
|
|
delete(c.data, key)
|
|
|
|
delete(c.data, key)
|
|
|
|