You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

86 lines
2.0 KiB

2 years ago
package lfu
import (
"cache"
"container/heap"
)
// lfu
// @Description:LFU即最少使用也就是淘汰缓存中访问频率最低的记录。
// LFU 认为,如果数据过去被访问多次,那么将来被访问的频率也更高。
// LFU 的实现需要维护一个按照访问次数排序的队列,每次访问,访问次数加 1队列重新排序淘汰时选择访问次数最少的即可
// 利用最小堆属性对访问次数排序实现
2 years ago
type lfu struct {
// 缓存最大容量
maxBytes int
// 当一个 entry 从缓存中移除时调用该回调函数,默认为 nil
onEvicted func(key string, value any)
//已使用的字节数只包括值key 不算
usedBytes int
queue *queue
cache map[string]*entry
}
func New(maxBytes int, onEvicted func(key string, value any)) cache.Cache {
q := make(queue, 0, 1024)
return &lfu{
maxBytes: maxBytes,
onEvicted: onEvicted,
queue: &q,
cache: make(map[string]*entry),
}
}
func (l *lfu) Set(key string, value any) {
if e, ok := l.cache[key]; ok {
l.usedBytes = l.usedBytes - cache.CalcLen(e.value) + cache.CalcLen(value)
l.queue.update(e, value, e.weight+1)
} else {
en := &entry{key: key, value: value}
//利用堆特性实现排序
heap.Push(l.queue, en)
l.cache[key] = en
l.usedBytes += en.Len()
if l.maxBytes > 0 && l.usedBytes > l.maxBytes {
l.removeElement(heap.Pop(l.queue))
2 years ago
}
}
}
func (l *lfu) Get(Key string) any {
if e, ok := l.cache[Key]; ok {
l.queue.update(e, e.value, e.weight+1)
return e.value
}
return nil
}
func (l *lfu) Del(Key string) {
if e, ok := l.cache[Key]; ok {
heap.Remove(l.queue, e.index)
}
}
func (l *lfu) DelOldest() {
if l.queue.Len() == 0 {
return
}
l.removeElement(heap.Pop(l.queue))
2 years ago
}
func (l *lfu) Len() int {
return l.queue.Len()
2 years ago
}
func (l *lfu) removeElement(x any) {
if x == nil {
return
}
en := x.(*entry)
delete(l.cache, en.key)
l.usedBytes -= en.Len()
if l.onEvicted != nil {
l.onEvicted(en.key, en.value)
}
2 years ago
}