DNS resolver LRU cache used []string slice for access ordering: - moveToFrontLocked: O(n) linear scan + slice重组 per cache update - storeCache held exclusive write lock during entire O(n) operation, blocking all concurrent reads Replace with container/list + map[string]*list.Element: - storeCache: O(1) MoveToFront via list.Element pointer - evictLRULocked: O(1) Back() + Remove() - DeleteCacheEntry: O(1) instead of O(n) scan This matches the LRU pattern already used by FileCache and FileInfoCache. Write lock duration reduced from O(n) to O(1), significantly reducing read contention under mixed workloads.
106 lines
2.3 KiB
Go
106 lines
2.3 KiB
Go
// Package resolver 提供 DNS 解析功能,支持缓存和后台刷新。
|
||
//
|
||
// 该文件包含 DNS 缓存相关的实现。
|
||
//
|
||
// 作者:xfy
|
||
package resolver
|
||
|
||
import (
|
||
"container/list"
|
||
"time"
|
||
)
|
||
|
||
// CacheStats 返回缓存统计信息。
|
||
type CacheStats struct {
|
||
Hits int64 // 缓存命中次数
|
||
Misses int64 // 缓存未命中次数
|
||
Entries int // 当前缓存条目数
|
||
Expired int // 过期条目数
|
||
}
|
||
|
||
// GetCacheStats 返回当前缓存统计信息。
|
||
// 这是一个辅助函数,用于测试和监控。
|
||
func (r *DNSResolver) GetCacheStats() CacheStats {
|
||
hits := r.hits.Load()
|
||
misses := r.misses.Load()
|
||
|
||
// 统计缓存条目
|
||
var entries, expired int
|
||
now := time.Now()
|
||
r.mu.RLock()
|
||
for _, entry := range r.cache {
|
||
entries++
|
||
entry.mu.RLock()
|
||
if now.After(entry.ExpiresAt) {
|
||
expired++
|
||
}
|
||
entry.mu.RUnlock()
|
||
}
|
||
r.mu.RUnlock()
|
||
|
||
return CacheStats{
|
||
Hits: hits,
|
||
Misses: misses,
|
||
Entries: entries,
|
||
Expired: expired,
|
||
}
|
||
}
|
||
|
||
// GetCacheEntry 获取指定主机的缓存条目(用于测试)。
|
||
func (r *DNSResolver) GetCacheEntry(host string) (*DNSCacheEntry, bool) {
|
||
r.mu.RLock()
|
||
entry, ok := r.cache[host]
|
||
r.mu.RUnlock()
|
||
if !ok {
|
||
return nil, false
|
||
}
|
||
return entry, true
|
||
}
|
||
|
||
// DeleteCacheEntry 删除指定主机的缓存条目。
|
||
func (r *DNSResolver) DeleteCacheEntry(host string) {
|
||
r.mu.Lock()
|
||
defer r.mu.Unlock()
|
||
delete(r.cache, host)
|
||
if elem, ok := r.lruIndex[host]; ok {
|
||
r.lruList.Remove(elem)
|
||
delete(r.lruIndex, host)
|
||
}
|
||
delete(r.refreshHosts, host)
|
||
}
|
||
|
||
// ClearCache 清空所有缓存。
|
||
func (r *DNSResolver) ClearCache() {
|
||
r.mu.Lock()
|
||
r.cache = make(map[string]*DNSCacheEntry)
|
||
r.lruList = list.New()
|
||
r.lruIndex = make(map[string]*list.Element)
|
||
r.refreshHosts = make(map[string]struct{})
|
||
r.mu.Unlock()
|
||
}
|
||
|
||
// GetHitRate 返回缓存命中率。
|
||
func (r *DNSResolver) GetHitRate() float64 {
|
||
hits := r.hits.Load()
|
||
misses := r.misses.Load()
|
||
total := hits + misses
|
||
if total == 0 {
|
||
return 0
|
||
}
|
||
return float64(hits) / float64(total)
|
||
}
|
||
|
||
// IsCached 检查指定主机是否在缓存中且未过期。
|
||
func (r *DNSResolver) IsCached(host string) bool {
|
||
r.mu.RLock()
|
||
entry, ok := r.cache[host]
|
||
r.mu.RUnlock()
|
||
if !ok {
|
||
return false
|
||
}
|
||
entry.mu.RLock()
|
||
expiresAt := entry.ExpiresAt
|
||
entry.mu.RUnlock()
|
||
return time.Now().Before(expiresAt)
|
||
}
|