perf(cache): Get 方法读锁优先,double-check 升级写锁
将 FileCache.Get 的全局写锁改为读锁优先,仅在需要修改状态 (过期删除、CachedAt 迁移)时升级为写锁并 double-check, 减少读路径的锁竞争。近似 LRU 场景下 Get 不再更新访问时间。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
0cf943fede
commit
308529d568
45
internal/cache/file_cache.go
vendored
45
internal/cache/file_cache.go
vendored
@ -88,31 +88,54 @@ func NewFileCache(maxEntries, maxSize int64, inactive time.Duration) *FileCache
|
|||||||
// - *FileEntry: 缓存条目,包含文件内容和元数据
|
// - *FileEntry: 缓存条目,包含文件内容和元数据
|
||||||
// - bool: 是否找到有效缓存
|
// - bool: 是否找到有效缓存
|
||||||
func (c *FileCache) Get(path string) (*FileEntry, bool) {
|
func (c *FileCache) Get(path string) (*FileEntry, bool) {
|
||||||
c.mu.Lock()
|
c.mu.RLock()
|
||||||
|
|
||||||
entry, ok := c.entries[path]
|
entry, ok := c.entries[path]
|
||||||
if !ok {
|
if !ok {
|
||||||
c.mu.Unlock()
|
c.mu.RUnlock()
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否过期
|
// 只读判断:检查是否过期
|
||||||
if time.Since(entry.LastAccess) > c.inactive {
|
if time.Since(entry.LastAccess) > c.inactive {
|
||||||
c.removeEntry(entry)
|
c.mu.RUnlock()
|
||||||
|
// 升级为写锁,double-check entry 仍存在且仍过期
|
||||||
|
c.mu.Lock()
|
||||||
|
if entry, ok = c.entries[path]; ok && time.Since(entry.LastAccess) > c.inactive {
|
||||||
|
c.removeEntry(entry)
|
||||||
|
}
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 迁移处理: CachedAt 为零值时视为刚刚缓存(旧条目)
|
// 只读判断:CachedAt 是否需要迁移
|
||||||
// 在锁内执行,确保并发安全
|
needMigrate := entry.CachedAt.IsZero()
|
||||||
if entry.CachedAt.IsZero() {
|
|
||||||
|
c.mu.RUnlock()
|
||||||
|
|
||||||
|
if needMigrate {
|
||||||
|
// 升级为写锁,double-check entry 仍存在
|
||||||
|
c.mu.Lock()
|
||||||
|
entry, ok = c.entries[path]
|
||||||
|
if !ok {
|
||||||
|
c.mu.Unlock()
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
// double-check 过期(RUnlock 和 Lock 之间可能已过期)
|
||||||
|
if time.Since(entry.LastAccess) > c.inactive {
|
||||||
|
c.removeEntry(entry)
|
||||||
|
c.mu.Unlock()
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
entry.CachedAt = time.Now()
|
entry.CachedAt = time.Now()
|
||||||
|
entry.LastAccess = time.Now()
|
||||||
|
c.lruList.MoveToFront(entry.element)
|
||||||
|
c.mu.Unlock()
|
||||||
|
return entry, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新访问时间并移到 LRU 链表头部
|
// 近似 LRU: 不更新 LastAccess/LRU 位置,直接返回
|
||||||
entry.LastAccess = time.Now()
|
// 精确 LRU 由 Set/Delete/evict 操作保证
|
||||||
c.lruList.MoveToFront(entry.element)
|
|
||||||
c.mu.Unlock()
|
|
||||||
return entry, true
|
return entry, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user