172 lines
3.4 KiB
Go
172 lines
3.4 KiB
Go
|
|
package cache
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"sync"
|
|||
|
|
"time"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
const (
|
|||
|
|
// maxItems 是L1Cache的最大条目数
|
|||
|
|
// 超过此限制后将淘汰最久未使用的条目
|
|||
|
|
maxItems = 10000
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// CacheItem 缓存项
|
|||
|
|
type CacheItem struct {
|
|||
|
|
Value interface{}
|
|||
|
|
Expiration int64
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Expired 判断缓存项是否过期
|
|||
|
|
func (item *CacheItem) Expired() bool {
|
|||
|
|
return item.Expiration > 0 && time.Now().UnixNano() > item.Expiration
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// L1Cache L1本地缓存(支持LRU淘汰策略)
|
|||
|
|
type L1Cache struct {
|
|||
|
|
items map[string]*CacheItem
|
|||
|
|
mu sync.RWMutex
|
|||
|
|
// accessOrder 记录key的访问顺序,用于LRU淘汰
|
|||
|
|
// 第一个是最久未使用的,最后一个是最近使用的
|
|||
|
|
accessOrder []string
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// NewL1Cache 创建L1缓存
|
|||
|
|
func NewL1Cache() *L1Cache {
|
|||
|
|
return &L1Cache{
|
|||
|
|
items: make(map[string]*CacheItem),
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Set 设置缓存
|
|||
|
|
func (c *L1Cache) Set(key string, value interface{}, ttl time.Duration) {
|
|||
|
|
c.mu.Lock()
|
|||
|
|
defer c.mu.Unlock()
|
|||
|
|
|
|||
|
|
var expiration int64
|
|||
|
|
if ttl > 0 {
|
|||
|
|
expiration = time.Now().Add(ttl).UnixNano()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果key已存在,更新访问顺序
|
|||
|
|
if _, exists := c.items[key]; exists {
|
|||
|
|
c.items[key] = &CacheItem{
|
|||
|
|
Value: value,
|
|||
|
|
Expiration: expiration,
|
|||
|
|
}
|
|||
|
|
c.updateAccessOrder(key)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查是否超过最大容量,进行LRU淘汰
|
|||
|
|
if len(c.items) >= maxItems {
|
|||
|
|
c.evictLRU()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
c.items[key] = &CacheItem{
|
|||
|
|
Value: value,
|
|||
|
|
Expiration: expiration,
|
|||
|
|
}
|
|||
|
|
c.accessOrder = append(c.accessOrder, key)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// evictLRU 淘汰最久未使用的条目
|
|||
|
|
func (c *L1Cache) evictLRU() {
|
|||
|
|
if len(c.accessOrder) == 0 {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
// 淘汰最久未使用的(第一个)
|
|||
|
|
oldest := c.accessOrder[0]
|
|||
|
|
delete(c.items, oldest)
|
|||
|
|
c.accessOrder = c.accessOrder[1:]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// removeFromAccessOrder 从访问顺序中移除key
|
|||
|
|
func (c *L1Cache) removeFromAccessOrder(key string) {
|
|||
|
|
for i, k := range c.accessOrder {
|
|||
|
|
if k == key {
|
|||
|
|
c.accessOrder = append(c.accessOrder[:i], c.accessOrder[i+1:]...)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// updateAccessOrder 更新访问顺序,将key移到最后(最近使用)
|
|||
|
|
func (c *L1Cache) updateAccessOrder(key string) {
|
|||
|
|
for i, k := range c.accessOrder {
|
|||
|
|
if k == key {
|
|||
|
|
// 移除当前位置
|
|||
|
|
c.accessOrder = append(c.accessOrder[:i], c.accessOrder[i+1:]...)
|
|||
|
|
// 添加到末尾
|
|||
|
|
c.accessOrder = append(c.accessOrder, key)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Get 获取缓存
|
|||
|
|
func (c *L1Cache) Get(key string) (interface{}, bool) {
|
|||
|
|
c.mu.Lock()
|
|||
|
|
defer c.mu.Unlock()
|
|||
|
|
|
|||
|
|
item, ok := c.items[key]
|
|||
|
|
if !ok {
|
|||
|
|
return nil, false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if item.Expired() {
|
|||
|
|
delete(c.items, key)
|
|||
|
|
c.removeFromAccessOrder(key)
|
|||
|
|
return nil, false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 更新访问顺序
|
|||
|
|
c.updateAccessOrder(key)
|
|||
|
|
|
|||
|
|
return item.Value, true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Delete 删除缓存
|
|||
|
|
func (c *L1Cache) Delete(key string) {
|
|||
|
|
c.mu.Lock()
|
|||
|
|
defer c.mu.Unlock()
|
|||
|
|
|
|||
|
|
delete(c.items, key)
|
|||
|
|
c.removeFromAccessOrder(key)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Clear 清空缓存
|
|||
|
|
func (c *L1Cache) Clear() {
|
|||
|
|
c.mu.Lock()
|
|||
|
|
defer c.mu.Unlock()
|
|||
|
|
|
|||
|
|
c.items = make(map[string]*CacheItem)
|
|||
|
|
c.accessOrder = make([]string, 0)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Size 获取缓存大小
|
|||
|
|
func (c *L1Cache) Size() int {
|
|||
|
|
c.mu.RLock()
|
|||
|
|
defer c.mu.RUnlock()
|
|||
|
|
|
|||
|
|
return len(c.items)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Cleanup 清理过期缓存
|
|||
|
|
func (c *L1Cache) Cleanup() {
|
|||
|
|
c.mu.Lock()
|
|||
|
|
defer c.mu.Unlock()
|
|||
|
|
|
|||
|
|
now := time.Now().UnixNano()
|
|||
|
|
keysToDelete := make([]string, 0)
|
|||
|
|
for key, item := range c.items {
|
|||
|
|
if item.Expiration > 0 && now > item.Expiration {
|
|||
|
|
keysToDelete = append(keysToDelete, key)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
for _, key := range keysToDelete {
|
|||
|
|
delete(c.items, key)
|
|||
|
|
c.removeFromAccessOrder(key)
|
|||
|
|
}
|
|||
|
|
}
|