Files
user-system/internal/cache/l1.go

172 lines
3.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
}
}