Add alternate key support to ConcurrentLfu#740
Conversation
…ests Agent-Logs-Url: https://github.com/bitfaster/BitFaster.Caching/sessions/f81e23bb-93f9-4dfb-8a8b-2f0a994f2805 Co-authored-by: bitfaster <12851828+bitfaster@users.noreply.github.com>
| { | ||
| if (this.Alternate.TryGetValue(key, out var node)) | ||
| { | ||
| if (!this.Lfu.policy.IsExpired(node)) |
There was a problem hiding this comment.
@copilot extract this into a private class level method to avoid duplicating the code. Inline the new method to make it fast.
There was a problem hiding this comment.
Extracted into TryUpdateValue with [MethodImpl(MethodImplOptions.AggressiveInlining)], shared by both TryUpdate and AlternateLookup.TryUpdate. Addressed in 289e1a8.
| { | ||
| if (this.Alternate.TryGetValue(key, out var node)) | ||
| { | ||
| lock (node) |
There was a problem hiding this comment.
@copilot extract this into a private class level method to avoid code duplication. Inline the new method to make it fast.
There was a problem hiding this comment.
Extracted into GetOrDiscard with [MethodImpl(MethodImplOptions.AggressiveInlining)], shared by both TryGetImpl and AlternateLookup.TryGet — following the same pattern as ConcurrentLruCore. The TryUpdateValue extraction from the previous commit already addressed the TryUpdate duplication at this line. Addressed in 0748af8.
Agent-Logs-Url: https://github.com/bitfaster/BitFaster.Caching/sessions/d601b667-bb4f-4958-916d-1a51ea33a82b Co-authored-by: bitfaster <12851828+bitfaster@users.noreply.github.com>
…uplication Agent-Logs-Url: https://github.com/bitfaster/BitFaster.Caching/sessions/88ec01ea-6213-4c7d-97ee-a4805d80d0ac Co-authored-by: bitfaster <12851828+bitfaster@users.noreply.github.com>
|
Bench is always quite variable for LFU, any change here appears to be noise. Before:
After
|
| { | ||
| string key = (i + 1).ToString(); | ||
| alternate.TryRemove(key.AsSpan(), out _, out _); | ||
| alternate.GetOrAdd(key.AsSpan(), static keySpan => keySpan.ToString()); |
…AddOrUpdate scenario Agent-Logs-Url: https://github.com/bitfaster/BitFaster.Caching/sessions/de1c6dd4-b745-491a-940f-e2e7f24ee099 Co-authored-by: bitfaster <12851828+bitfaster@users.noreply.github.com>
|
@copilot Add tests to |
…LfuTests Agent-Logs-Url: https://github.com/bitfaster/BitFaster.Caching/sessions/ee42e470-1a4e-468f-80c0-201b7009f508 Co-authored-by: bitfaster <12851828+bitfaster@users.noreply.github.com>
Added 4 tests to |
This adds a net9-only API for alternate lookups on
ConcurrentLfuandConcurrentTLfu, following the same template established in PR #739 forConcurrentLru.Alternate lookup API
GetAlternateLookup<TAlternateKey>()andTryGetAlternateLookup<TAlternateKey>()toConcurrentLfuCore.ConcurrentLfu<K,V>andConcurrentTLfu<K,V>wrapper classes.AlternateLookup<TAlternateKey>inner struct with:TryGet— performs alternate-key dictionary lookup with read buffer tracking, drain scheduling, and expiry handlingTryRemove— removes by alternate key, marks node as removed, and triggers write bufferTryUpdate— locks node and updates value with write buffer schedulingAddOrUpdate— update-or-add loop with cached primary key materializationGetOrAdd— get-or-add loop converting alternate key viaIAlternateEqualityComparer.Create()GetOrAdd<TArg>— same with factory argumentConcurrentDictionary alternate lookup integration
ConcurrentDictionary<K,N>.GetAlternateLookup<TAlternateKey>()on net9 for alternate-key operations without materializing the primary key on hits.AddOrUpdateretries to avoid repeated alternate-key materialization under contention.Code deduplication
GetOrDiscardprivate method with[MethodImpl(MethodImplOptions.AggressiveInlining)]for TryGet node processing, used by bothTryGetImplandAlternateLookup.TryGet.TryUpdateValueprivate method with[MethodImpl(MethodImplOptions.AggressiveInlining)]for value mutation, used by bothTryUpdateandAlternateLookup.TryUpdate.Compatibility guardrails
Throw.IncompatibleComparer().NET9_0_OR_GREATERso the public surface remains unchanged on earlier targets.Tests
ConcurrentLfuAlternateLookupTests.cs): 6 focused tests covering compatible/incompatible comparer, TryGet, TryRemove, TryUpdate, AddOrUpdate, and GetOrAdd.ConcurrentTLfuTests.cs): 4 tests coveringGetAlternateLookupandTryGetAlternateLookupfor both compatible and incompatible comparers.ConcurrentLfuSoakTests.cs): 3 concurrent soak tests ×10 iterations each for GetOrAdd, GetOrAdd, and TryRemove+AddOrUpdate withReadOnlySpan<char>/StringComparer.Ordinal.Example
⌨️ Start Copilot coding agent tasks without leaving your editor — available in VS Code, Visual Studio, JetBrains IDEs and Eclipse.