init
This commit is contained in:
273
vendor/github.com/bluele/gcache/simple.go
generated
vendored
Normal file
273
vendor/github.com/bluele/gcache/simple.go
generated
vendored
Normal file
@ -0,0 +1,273 @@
|
||||
package gcache
|
||||
|
||||
import "time"
|
||||
|
||||
// SimpleCache has no clear priority for evict cache. It depends on key-value map order.
|
||||
type SimpleCache struct {
|
||||
baseCache
|
||||
items map[interface{}]*simpleItem
|
||||
}
|
||||
|
||||
func newSimpleCache(cb *CacheBuilder) *SimpleCache {
|
||||
c := &SimpleCache{}
|
||||
buildCache(&c.baseCache, cb)
|
||||
|
||||
c.init()
|
||||
c.loadGroup.cache = c
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *SimpleCache) init() {
|
||||
if c.size <= 0 {
|
||||
c.items = make(map[interface{}]*simpleItem)
|
||||
} else {
|
||||
c.items = make(map[interface{}]*simpleItem, c.size)
|
||||
}
|
||||
}
|
||||
|
||||
// Set a new key-value pair
|
||||
func (c *SimpleCache) Set(key, value interface{}) error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
_, err := c.set(key, value)
|
||||
return err
|
||||
}
|
||||
|
||||
// Set a new key-value pair with an expiration time
|
||||
func (c *SimpleCache) SetWithExpire(key, value interface{}, expiration time.Duration) error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
item, err := c.set(key, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t := c.clock.Now().Add(expiration)
|
||||
item.(*simpleItem).expiration = &t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *SimpleCache) set(key, value interface{}) (interface{}, error) {
|
||||
var err error
|
||||
if c.serializeFunc != nil {
|
||||
value, err = c.serializeFunc(key, value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Check for existing item
|
||||
item, ok := c.items[key]
|
||||
if ok {
|
||||
item.value = value
|
||||
} else {
|
||||
// Verify size not exceeded
|
||||
if (len(c.items) >= c.size) && c.size > 0 {
|
||||
c.evict(1)
|
||||
}
|
||||
item = &simpleItem{
|
||||
clock: c.clock,
|
||||
value: value,
|
||||
}
|
||||
c.items[key] = item
|
||||
}
|
||||
|
||||
if c.expiration != nil {
|
||||
t := c.clock.Now().Add(*c.expiration)
|
||||
item.expiration = &t
|
||||
}
|
||||
|
||||
if c.addedFunc != nil {
|
||||
c.addedFunc(key, value)
|
||||
}
|
||||
|
||||
return item, nil
|
||||
}
|
||||
|
||||
// Get a value from cache pool using key if it exists.
|
||||
// If it dose not exists key and has LoaderFunc,
|
||||
// generate a value using `LoaderFunc` method returns value.
|
||||
func (c *SimpleCache) Get(key interface{}) (interface{}, error) {
|
||||
v, err := c.get(key, false)
|
||||
if err == KeyNotFoundError {
|
||||
return c.getWithLoader(key, true)
|
||||
}
|
||||
return v, err
|
||||
}
|
||||
|
||||
// Get a value from cache pool using key if it exists.
|
||||
// If it dose not exists key, returns KeyNotFoundError.
|
||||
// And send a request which refresh value for specified key if cache object has LoaderFunc.
|
||||
func (c *SimpleCache) GetIFPresent(key interface{}) (interface{}, error) {
|
||||
v, err := c.get(key, false)
|
||||
if err == KeyNotFoundError {
|
||||
return c.getWithLoader(key, false)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (c *SimpleCache) get(key interface{}, onLoad bool) (interface{}, error) {
|
||||
v, err := c.getValue(key, onLoad)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if c.deserializeFunc != nil {
|
||||
return c.deserializeFunc(key, v)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (c *SimpleCache) getValue(key interface{}, onLoad bool) (interface{}, error) {
|
||||
c.mu.Lock()
|
||||
item, ok := c.items[key]
|
||||
if ok {
|
||||
if !item.IsExpired(nil) {
|
||||
v := item.value
|
||||
c.mu.Unlock()
|
||||
if !onLoad {
|
||||
c.stats.IncrHitCount()
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
c.remove(key)
|
||||
}
|
||||
c.mu.Unlock()
|
||||
if !onLoad {
|
||||
c.stats.IncrMissCount()
|
||||
}
|
||||
return nil, KeyNotFoundError
|
||||
}
|
||||
|
||||
func (c *SimpleCache) getWithLoader(key interface{}, isWait bool) (interface{}, error) {
|
||||
if c.loaderExpireFunc == nil {
|
||||
return nil, KeyNotFoundError
|
||||
}
|
||||
value, _, err := c.load(key, func(v interface{}, expiration *time.Duration, e error) (interface{}, error) {
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
item, err := c.set(key, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if expiration != nil {
|
||||
t := c.clock.Now().Add(*expiration)
|
||||
item.(*simpleItem).expiration = &t
|
||||
}
|
||||
return v, nil
|
||||
}, isWait)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (c *SimpleCache) evict(count int) {
|
||||
now := c.clock.Now()
|
||||
current := 0
|
||||
for key, item := range c.items {
|
||||
if current >= count {
|
||||
return
|
||||
}
|
||||
if item.expiration == nil || now.After(*item.expiration) {
|
||||
defer c.remove(key)
|
||||
current++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Removes the provided key from the cache.
|
||||
func (c *SimpleCache) Remove(key interface{}) bool {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
return c.remove(key)
|
||||
}
|
||||
|
||||
func (c *SimpleCache) remove(key interface{}) bool {
|
||||
item, ok := c.items[key]
|
||||
if ok {
|
||||
delete(c.items, key)
|
||||
if c.evictedFunc != nil {
|
||||
c.evictedFunc(key, item.value)
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Returns a slice of the keys in the cache.
|
||||
func (c *SimpleCache) keys() []interface{} {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
keys := make([]interface{}, len(c.items))
|
||||
var i = 0
|
||||
for k := range c.items {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
// Returns a slice of the keys in the cache.
|
||||
func (c *SimpleCache) Keys() []interface{} {
|
||||
keys := []interface{}{}
|
||||
for _, k := range c.keys() {
|
||||
_, err := c.GetIFPresent(k)
|
||||
if err == nil {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
// Returns all key-value pairs in the cache.
|
||||
func (c *SimpleCache) GetALL() map[interface{}]interface{} {
|
||||
m := make(map[interface{}]interface{})
|
||||
for _, k := range c.keys() {
|
||||
v, err := c.GetIFPresent(k)
|
||||
if err == nil {
|
||||
m[k] = v
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Returns the number of items in the cache.
|
||||
func (c *SimpleCache) Len() int {
|
||||
return len(c.GetALL())
|
||||
}
|
||||
|
||||
// Completely clear the cache
|
||||
func (c *SimpleCache) Purge() {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
if c.purgeVisitorFunc != nil {
|
||||
for key, item := range c.items {
|
||||
c.purgeVisitorFunc(key, item.value)
|
||||
}
|
||||
}
|
||||
|
||||
c.init()
|
||||
}
|
||||
|
||||
type simpleItem struct {
|
||||
clock Clock
|
||||
value interface{}
|
||||
expiration *time.Time
|
||||
}
|
||||
|
||||
// returns boolean value whether this item is expired or not.
|
||||
func (si *simpleItem) IsExpired(now *time.Time) bool {
|
||||
if si.expiration == nil {
|
||||
return false
|
||||
}
|
||||
if now == nil {
|
||||
t := si.clock.Now()
|
||||
now = &t
|
||||
}
|
||||
return si.expiration.Before(*now)
|
||||
}
|
Reference in New Issue
Block a user