type Cache interface { // Set inserts or updates the specified key-value pair. Set(key, value interface{}) error // SetWithExpire inserts or updates the specified key-value pair with an expiration time. SetWithExpire(key, value interface{}, expiration time.Duration) error // Get returns the value for the specified key if it is present in the cache. // If the key is not present in the cache and the cache has LoaderFunc, // invoke the `LoaderFunc` function and inserts the key-value pair in the cache. // If the key is not present in the cache and the cache does not have a LoaderFunc, // return KeyNotFoundError. Get(key interface{}) (interface{}, error) // GetIFPresent returns the value for the specified key if it is present in the cache. // Return KeyNotFoundError if the key is not present. GetIFPresent(key interface{}) (interface{}, error)
// GetAll returns a map containing all key-value pairs in the cache. GetALL(checkExpired bool) map[interface{}]interface{} get(key interface{}, onLoad bool) (interface{}, error) // Remove removes the specified key from the cache if the key is present. // Returns true if the key was present and the key has been deleted. Remove(key interface{}) bool // Purge removes all key-value pairs from the cache. Purge() // Keys returns a slice containing all keys in the cache. Keys(checkExpired bool) []interface{} // Len returns the number of items in the cache. Len(checkExpired bool) int // Has returns true if the key exists in the cache. Has(key interface{}) bool }
type baseCache struct { clock Clock size int loaderExpireFunc LoaderExpireFunc evictedFunc EvictedFunc purgeVisitorFunc PurgeVisitorFunc addedFunc AddedFunc deserializeFunc DeserializeFunc serializeFunc SerializeFunc expiration *time.Duration mu sync.RWMutex loadGroup Group *stats }
type simpleItem struct { clock Clock value interface{} // 这个value的过期时间 expiration *time.Time }
// SimpleCache has no clear priority for evict cache. It depends on key-value map order. type SimpleCache struct { baseCache items map[interface{}]*simpleItem }
// 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 } // 计算这个key的过期时间,并将该时间设置到simpleItem的expiration字段 t := c.clock.Now().Add(expiration) item.(*simpleItem).expiration = &t returnnil }
// simpleCache的核心逻辑函数 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 { returnnil, err } }
// Check for existing item item, ok := c.items[key] // 查看该key是否已经在缓存中,如果有则更新 if ok { item.value = value } else { // 没有的话则要判断当前缓存是否已经满了,满了的话则要驱逐 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 }
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() } returnnil, KeyNotFoundError }
// IsExpired returns boolean value whether this item is expired or not. func(si *simpleItem) IsExpired(now *time.Time) bool { if si.expiration == nil { returnfalse } if now == nil { t := si.clock.Now() now = &t } // 判断是否过期 return si.expiration.Before(*now) }
// a boolean whether reuse the empty current entry // 判断这个链表节点是否要被删除,判断条件是当前节点的freq不等于0并且该节点的map长度为0 removable := isRemovableFreqEntry(currentFreqEntry)
// evict removes the oldest item from the cache.func (c *LRUCache) evict(count int) { for i := 0; i < count; i++ { ent := c.evictList.Back() if ent == nil { return } else { c.removeElement(ent) } } }
type lruItem struct { clock Clock key interface{} value interface{} expiration *time.Time }
// IsExpired returns boolean value whether this item is expired or not.func (it *lruItem) IsExpired(now *time.Time) bool { if it.expiration == nil { returnfalse } if now == nil { t := it.clock.Now() now = &t } return it.expiration.Before(*now) }