-
Notifications
You must be signed in to change notification settings - Fork 28
refactor: replace filteredServerCache with generic syncutil.TTLCache #7277
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
94205f2
Initial plan
Copilot 9dfed48
refactor: replace filteredServerCache with generic syncutil.TTLCache
Copilot 6637a52
fix: correct assertion arguments in ttl_cache_test.go
Copilot 6997ec3
Potential fix for pull request finding
lpcox c79c843
Potential fix for pull request finding
lpcox 3dae7c9
Potential fix for pull request finding
lpcox 768176d
Merge main into branch: resolve session_util.go conflict by moving tr…
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| package syncutil | ||
|
|
||
| import ( | ||
| "sync" | ||
| "time" | ||
| ) | ||
|
|
||
| // ttlEntry holds a cached value together with its last-used timestamp for LRU | ||
| // tracking. | ||
| type ttlEntry[V any] struct { | ||
| value V | ||
| lastUsed time.Time | ||
| } | ||
|
|
||
| // TTLCache is a thread-safe generic get-or-create cache that combines lazy TTL | ||
| // eviction with an LRU size cap. | ||
| // | ||
| // On every [TTLCache.GetOrCreate] call, all entries whose idle time exceeds the | ||
| // configured TTL are evicted first. If the cache is still at capacity after TTL | ||
| // eviction, the least-recently-used entry is evicted to make room. | ||
| type TTLCache[K comparable, V any] struct { | ||
| mu sync.Mutex | ||
| entries map[K]*ttlEntry[V] | ||
| ttl time.Duration | ||
| maxSize int | ||
| nowFn func() time.Time | ||
| } | ||
|
|
||
| // NewTTLCache creates a new TTLCache with the given entry TTL and maximum size. | ||
| // Entries idle longer than ttl are evicted lazily; when the cache reaches | ||
| // maxSize the least-recently-used entry is evicted on the next GetOrCreate call. | ||
| func NewTTLCache[K comparable, V any](ttl time.Duration, maxSize int) *TTLCache[K, V] { | ||
| return newTTLCacheWithClock[K, V](ttl, maxSize, time.Now) | ||
| } | ||
|
|
||
| // newTTLCacheWithClock creates a TTLCache with an injectable clock function. | ||
| // Intended for use in unit tests only. | ||
| func newTTLCacheWithClock[K comparable, V any](ttl time.Duration, maxSize int, nowFn func() time.Time) *TTLCache[K, V] { | ||
| return &TTLCache[K, V]{ | ||
| entries: make(map[K]*ttlEntry[V]), | ||
| ttl: ttl, | ||
| maxSize: maxSize, | ||
| nowFn: nowFn, | ||
| } | ||
| } | ||
|
|
||
| // GetOrCreate returns the cached value for key. If the key is not present, or | ||
| // has been evicted, create is called to produce a new value which is then | ||
| // stored and returned. | ||
| // | ||
| // On each call, all expired entries are lazily evicted before the lookup. If | ||
| // the cache has reached its capacity after TTL eviction, the LRU entry is | ||
| // removed to make room. | ||
| // | ||
| // create is called while the cache lock is held. | ||
| func (c *TTLCache[K, V]) GetOrCreate(key K, create func() V) V { | ||
| if c.maxSize <= 0 { | ||
| return create() | ||
| } | ||
| now := c.nowFn() | ||
| c.mu.Lock() | ||
| defer c.mu.Unlock() | ||
| // Lazy eviction of expired entries. | ||
| if c.ttl > 0 { | ||
| for k, entry := range c.entries { | ||
| if now.Sub(entry.lastUsed) > c.ttl { | ||
| delete(c.entries, k) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if entry, ok := c.entries[key]; ok { | ||
| entry.lastUsed = now | ||
| return entry.value | ||
| } | ||
|
|
||
| // LRU eviction when still at capacity after TTL sweep. | ||
| if len(c.entries) >= c.maxSize { | ||
| var lruKey K | ||
| var lruTime time.Time | ||
| first := true | ||
| for k, entry := range c.entries { | ||
| if first || entry.lastUsed.Before(lruTime) { | ||
| lruKey = k | ||
| lruTime = entry.lastUsed | ||
| first = false | ||
| } | ||
| } | ||
| if !first { | ||
| delete(c.entries, lruKey) | ||
| } | ||
| } | ||
|
|
||
| v := create() | ||
| c.entries[key] = &ttlEntry[V]{value: v, lastUsed: now} | ||
| return v | ||
| } | ||
|
|
||
| // Len returns the current number of entries held in the cache. | ||
| func (c *TTLCache[K, V]) Len() int { | ||
| c.mu.Lock() | ||
| defer c.mu.Unlock() | ||
| return len(c.entries) | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.