Files
cache/cache.go
2024-08-17 12:04:33 +08:00

109 lines
2.3 KiB
Go

package cache
import (
"fmt"
"strconv"
"sync"
"time"
)
type Cache[K comparable, V any] struct {
mu sync.RWMutex
data map[K]*Data[V] // 数据
cSet func(K, Data[V]) // 设置数据回调
cGet func(K, Data[V]) // 获取数据回调
cGetData func(K, Data[V]) // 获取数据内容回调
cGetTTL func(K, Data[V]) // 获取数据剩余时间回调
cDel func(K, Data[V]) // 删除数据回调
cUpData func(K, Data[V]) // 更新数据内容回调
cUpTTL func(K, Data[V]) // 更新数据剩余时间回调
fatal func(error) // 致命错误执行的内容
gc func() // 自动清理过期数据
persist func() // 持久化数据
is64Bit bool // 是否为64位系统
}
type Data[V any] struct {
End time.Time // 过期时间 v.End.IsZero()=true表示永不过期
Val V // 数据
}
// NewCache 创建一个新的缓存实例
// K: 键的类型(可比较) V: 值的类型(允许any)
func NewCache[K comparable, V any]() *Cache[K, V] {
defFunc := func(k K, d Data[V]) {}
c := &Cache[K, V]{
data: make(map[K]*Data[V]),
cSet: defFunc,
cGet: defFunc,
cGetData: defFunc,
cGetTTL: defFunc,
cDel: defFunc,
cUpData: defFunc,
cUpTTL: defFunc,
fatal: func(err error) { fmt.Println(err) },
}
c.gc = c.collection()
c.is64Bit = strconv.IntSize == 64
return c
}
// 自动清理过期数据
func (c *Cache[K, V]) collection() func() {
ticker := time.NewTicker(time.Second)
stopChan := make(chan struct{})
go func() {
for {
select {
case <-stopChan:
return
case <-ticker.C:
now := time.Now()
var dKeys []K
c.mu.RLock()
for k, v := range c.data {
if v.End.IsZero() && v.End.Before(now) {
dKeys = append(dKeys, k)
}
}
c.mu.RUnlock()
// 删除过期数据
if len(dKeys) > 0 {
c.mu.Lock()
for _, k := range dKeys {
if c.cDel != nil {
c.cDel(k, *c.data[k])
}
delete(c.data, k)
}
c.mu.Unlock()
}
}
}
}()
return func() {
ticker.Stop()
stopChan <- struct{}{}
}
}
func (c *Cache[K, V]) SetFatalFunc(f func(error)) {
c.mu.Lock()
defer c.mu.Unlock()
c.fatal = f
}
// Destroy 销毁缓存实例
// 关闭缓存实例
func (c *Cache[K, V]) Destroy() {
c.gc()
if c.persist != nil {
c.persist()
}
return
}