|
|
|
|
package fifo
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"cache"
|
|
|
|
|
"container/list"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 先进先出缓存
|
|
|
|
|
*/
|
|
|
|
|
type fifo struct {
|
|
|
|
|
// 缓存最大容量
|
|
|
|
|
maxBytes int
|
|
|
|
|
// 当一个 entry 从缓存中移除时调用该回调函数,默认为 nil
|
|
|
|
|
onEvicted func(key string, value any)
|
|
|
|
|
//已使用的字节数,只包括值,key 不算
|
|
|
|
|
usedBytes int
|
|
|
|
|
//缓存容器,存放entry
|
|
|
|
|
ll *list.List
|
|
|
|
|
//指针容器
|
|
|
|
|
cache map[string]*list.Element
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func New(maxBytes int, onEvicted func(key string, value any)) cache.Cache {
|
|
|
|
|
return &fifo{
|
|
|
|
|
maxBytes: maxBytes,
|
|
|
|
|
onEvicted: onEvicted,
|
|
|
|
|
ll: list.New(),
|
|
|
|
|
cache: make(map[string]*list.Element),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set 往 Cache 尾部增加一个元素(如果已经存在,则放入尾部,并修改值)
|
|
|
|
|
func (f *fifo) Set(key string, value any) {
|
|
|
|
|
//元素存在
|
|
|
|
|
if e, ok := f.cache[key]; ok {
|
|
|
|
|
f.ll.MoveToBack(e)
|
|
|
|
|
en := e.Value.(*entry)
|
|
|
|
|
f.usedBytes = f.usedBytes - cache.CalcLen(en.value) + cache.CalcLen(value)
|
|
|
|
|
en.value = value
|
|
|
|
|
} else {
|
|
|
|
|
en := &entry{key, value}
|
|
|
|
|
e := f.ll.PushBack(en)
|
|
|
|
|
f.cache[key] = e
|
|
|
|
|
f.usedBytes += en.Len()
|
|
|
|
|
//元素容量校验
|
|
|
|
|
if f.CheckOverFlow() {
|
|
|
|
|
f.DelOldest()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CheckOverFlow 校验容量是否溢出
|
|
|
|
|
func (f *fifo) CheckOverFlow() bool {
|
|
|
|
|
return f.maxBytes > 0 && f.usedBytes > f.maxBytes
|
|
|
|
|
}
|
|
|
|
|
func (f *fifo) Get(key string) any {
|
|
|
|
|
if e, ok := f.cache[key]; ok {
|
|
|
|
|
return e.Value.(*entry).value
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
func (f *fifo) Del(key string) {
|
|
|
|
|
if e, ok := f.cache[key]; ok {
|
|
|
|
|
f.removeElement(e)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
func (f *fifo) DelOldest() {
|
|
|
|
|
//删除列表头部元素
|
|
|
|
|
f.removeElement(f.ll.Front())
|
|
|
|
|
}
|
|
|
|
|
func (f *fifo) Len() int {
|
|
|
|
|
return f.ll.Len()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// removeElement 删除元素
|
|
|
|
|
func (f *fifo) removeElement(e *list.Element) {
|
|
|
|
|
if e == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
f.ll.Remove(e)
|
|
|
|
|
en := e.Value.(*entry)
|
|
|
|
|
f.usedBytes -= en.Len()
|
|
|
|
|
delete(f.cache, en.key)
|
|
|
|
|
if f.onEvicted != nil {
|
|
|
|
|
f.onEvicted(en.key, en.value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type entry struct {
|
|
|
|
|
key string
|
|
|
|
|
value any
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *entry) Len() int {
|
|
|
|
|
return cache.CalcLen(e.value)
|
|
|
|
|
}
|