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)
|
||
}
|
||
}
|