Shinwayy / internal /cache /response_cache_memory.go
Shinway Deploy
track binary files with git-lfs
db492de
Raw
History Blame Contribute Delete
2.64 kB
package cache
import (
"container/list"
"context"
"sync"
"time"
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
)
type lruEntry struct {
key string
response *CachedResponse
expiresAt time.Time
}
type memoryResponseCache struct {
cfg config.ResponseCacheConfig
mu sync.RWMutex
items map[string]*list.Element
eviction *list.List
stats responseCacheStats
}
func newMemoryResponseCache(cfg config.ResponseCacheConfig) *memoryResponseCache {
maxEntries := cfg.MaxMemoryEntries
if maxEntries <= 0 {
maxEntries = 1000
}
return &memoryResponseCache{
cfg: cfg,
items: make(map[string]*list.Element, maxEntries),
eviction: list.New(),
}
}
func (m *memoryResponseCache) Get(_ context.Context, key string) (*CachedResponse, bool) {
m.mu.RLock()
elem, ok := m.items[key]
m.mu.RUnlock()
if !ok {
m.stats.recordMiss()
return nil, false
}
entry := elem.Value.(*lruEntry)
if time.Now().After(entry.expiresAt) {
// Lazy expiry
m.mu.Lock()
m.removeElement(elem)
m.mu.Unlock()
m.stats.recordMiss()
return nil, false
}
// Move to front (most recently used)
m.mu.Lock()
m.eviction.MoveToFront(elem)
m.mu.Unlock()
m.stats.recordHit()
return entry.response, true
}
func (m *memoryResponseCache) Set(_ context.Context, key string, resp *CachedResponse, ttl time.Duration) error {
m.mu.Lock()
defer m.mu.Unlock()
// Update existing
if elem, ok := m.items[key]; ok {
entry := elem.Value.(*lruEntry)
entry.response = resp
entry.expiresAt = time.Now().Add(ttl)
m.eviction.MoveToFront(elem)
return nil
}
maxEntries := m.cfg.MaxMemoryEntries
if maxEntries <= 0 {
maxEntries = 1000
}
// Evict if at capacity
for len(m.items) >= maxEntries && m.eviction.Len() > 0 {
back := m.eviction.Back()
if back != nil {
m.removeElement(back)
}
}
// Add new
entry := &lruEntry{
key: key,
response: resp,
expiresAt: time.Now().Add(ttl),
}
elem := m.eviction.PushFront(entry)
m.items[key] = elem
return nil
}
func (m *memoryResponseCache) Delete(_ context.Context, _ string) error {
m.mu.Lock()
defer m.mu.Unlock()
m.items = make(map[string]*list.Element)
m.eviction.Init()
return nil
}
func (m *memoryResponseCache) Stats() CacheStats {
m.mu.RLock()
size := int64(len(m.items))
m.mu.RUnlock()
return CacheStats{
Hits: m.stats.hits.Load(),
Misses: m.stats.misses.Load(),
Size: size,
}
}
func (m *memoryResponseCache) Close() error {
return nil
}
func (m *memoryResponseCache) removeElement(elem *list.Element) {
entry := elem.Value.(*lruEntry)
delete(m.items, entry.key)
m.eviction.Remove(elem)
}