// 接口 type Cache interface { Set(key string, value interface{}) Get(key string) interface{} Del(key string) DelOldest() Len() int UsedBytes() int }
type Value interface { Len() int }
// 链表中存储的节点值 type entry struct { key string value interface{} }
// 计算value的实际占用大小 funcCalcLen(value interface{})int { var n int switch v := value.(type) { case Value: n = v.Len() casestring: if runtime.GOARCH == "amd64" { n = 16 + len(v) } else { n = 8 + len(v) } casebool, uint8, int8: n = 1 caseint16, uint16: n = 2 caseint32, uint32, float32: n = 4 caseint64, uint64, float64: n = 8 caseint, uint: if runtime.GOARCH == "amd64" { n = 8 } else { n = 4 } casecomplex64: n = 8 casecomplex128: n = 16 default: panic(fmt.Sprintf("%T is not implement cache.Value", value)) }
// Set 设置或修改缓存值 func(f *lru)Set(key string, value interface{}) { // 如果缓存命中,则直接修改值 if e, ok := f.cache[key]; ok { // 表示对应的缓存修改过,处于最新的状态,因此需要放置到链表尾部防止被淘汰 f.ll.MoveToBack(e) // 链表中存储的节点值 en := e.Value.(*entry) f.usedBytes = f.usedBytes - CalcLen(en.value) + CalcLen(value) en.value = value return }
en := &entry{key: key, value: value} // 在环形双向链表尾部创建节点,复杂度为 O(1) e := f.ll.PushBack(en) f.cache[key] = e f.usedBytes += CalcLen(value)
// 如果缓存溢出,则自动删除老的缓存 // 这里使用 for 来检测使用还会超出范围 // 这是因为如果某次缓存一个非常大的对象,那么又可能会淘汰多个旧的对象 for f.maxBytes > 0 && f.usedBytes > f.maxBytes { f.DelOldest() } }
// Get 返回缓存值 entry.value func(f *lru)Get(key string)interface{} { if e, ok := f.cache[key]; ok { // 这里很关键,对于LRU缓存淘汰算法而言,表示将最近访问过的缓存对象设置为最新状态,防止被淘汰 f.ll.MoveToBack(e) return e.Value.(*entry).value } returnnil }
// Del 主动删除缓存 func(f *lru)Del(key string) { if e, ok := f.cache[key]; ok { f.removeElement(e) } }