Skip to content

fix: use Clear(key) instead of ClearByKey(key) for exact-key cache removal - #1022

Open
AndersKaae wants to merge 1 commit into
KevinJump:v13/devfrom
AndersKaae:upstream-pr/fix-clearbykey-scan
Open

fix: use Clear(key) instead of ClearByKey(key) for exact-key cache removal#1022
AndersKaae wants to merge 1 commit into
KevinJump:v13/devfrom
AndersKaae:upstream-pr/fix-clearbykey-scan

Conversation

@AndersKaae

Copy link
Copy Markdown

SyncEntityCache.AddName/GetEntity and ContentTypeBaseSerializer's alias cache all call DictionaryAppCache.ClearByKey(exactKey), which does a full scan of every cache entry looking for a prefix match, even though the key passed is always an exact id/guid with no other entry sharing that prefix. DictionaryAppCache already exposes Clear(key), a direct dictionary removal with no scan.

nameCache in particular is shared across an entire Export/Report run and grows by one entry per resolved ancestor name, so the O(n) scan compounds into O(n^2) as the run progresses. Confirmed via CPU profiling (~91% of wall time in the Where/ToArray scan) and an isolated benchmark: 60k cached items, 27.4s vs 27ms (~1000x) for a single clear-and-reinsert.

Left the other 5 ClearByKey call sites (uSyncService_Handlers, SyncHandlerRoot: PrepCaches/CleanCaches) unchanged since those rely on genuine multi-key prefix matching (one is explicitly documented as "a starts with call").

Local fix for LegalDesk V2's uSync migration validation work, moving our real content tree (~440k items) between environments. We'd struggled with this since a support thread in July ("Usync complete issues"), where the Publisher web UI was timing out in minutes on even tiny syncs; we eventually moved to the CLI tool instead (SignalR in the web UI looks like the more likely cause of those particular fast timeouts, separate from this). The CLI then ran into the plain HttpClient 100s timeout on our real-scale Export/Report, and profiling that long-running process is what surfaced this ClearByKey scan as a genuine O(n^2) bottleneck.

Rebased onto current v13/main; builds clean.

…moval

SyncEntityCache.AddName/GetEntity and ContentTypeBaseSerializer's alias
cache all called DictionaryAppCache.ClearByKey(exactKey), which does a full
LINQ scan of every entry in the cache looking for a prefix match, even
though the key passed is always an exact id/guid string with no other
entries sharing that prefix. DictionaryAppCache already exposes Clear(key),
a direct ConcurrentDictionary.TryRemove - O(1), no scan.

nameCache in particular is shared across an entire Export/Report run and
grows by one entry per resolved ancestor name, so ClearByKey's O(n) scan
compounded into genuine O(n^2) cost as the cache grew - confirmed via CPU
profiling (~91% of wall time in the LINQ Where/ToArray + ConcurrentDictionary
enumeration) and an isolated benchmark (60k items: 27.4s vs 27ms, ~1000x).

Left 5 other ClearByKey call sites unchanged (uSyncService_Handlers,
SyncHandlerRoot x2 incl. PrepCaches/CleanCaches) - those rely on genuine
multi-key prefix matching, one explicitly documented in a comment as
"a starts with call" for clearing a related folder cache. Changing those
to Clear() would silently break that behavior.

Local fix for LegalDesk V2's uSync migration validation work. Not yet
upstreamed to Jumoo - see LegalDesk-V2 task history for the diagnosis.
@KevinJump KevinJump added the 13.x NETCORE v13 - next LTS changes. label Aug 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

13.x NETCORE v13 - next LTS changes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants