first commit

dev
old-tom 2 years ago
commit 2c0951e80a

@ -0,0 +1,18 @@
package cache
type Cache interface {
// Set 设置/添加一个缓存,如果 key 存在,用新值覆盖旧值
Set(key string, value any)
// Get 通过 key 获取一个缓存值
Get(Key string) any
// Del 通过 key 删除一个缓存值
Del(Key string)
// DelOldest 删除最“无用”的一个缓存值
DelOldest()
// Len 获取缓存已存在的记录数
Len() int
}
type Value interface {
Len() int
}

@ -0,0 +1,97 @@
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)
}

@ -0,0 +1,10 @@
package fifo_test
import (
"github.com/matryer/is"
"testing"
)
func TestFifo(t *testing.T) {
is.New()
}

@ -0,0 +1,5 @@
module cache
go 1.21.5
require github.com/matryer/is v1.4.1

@ -0,0 +1,2 @@
github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=

@ -0,0 +1,41 @@
package cache
import (
"fmt"
"runtime"
)
func CalcLen(value any) int {
var n int
switch v := value.(type) {
case Value:
n = v.Len()
case string:
if runtime.GOARCH == "amd64" {
n = 16 + len(v)
} else {
n = 8 + len(v)
}
case bool, uint8, int8:
n = 1
case int16, uint16:
n = 2
case int32, uint32, float32:
n = 4
case int64, uint64, float64:
n = 8
case int, uint:
if runtime.GOARCH == "amd64" {
n = 8
} else {
n = 4
}
case complex64:
n = 8
case complex128:
n = 16
default:
panic(fmt.Sprintf("%T is not implement cache.Value", value))
}
return n
}
Loading…
Cancel
Save