Skip to content

Commit 47fe376

Browse files
authored
Fix race condition in MemoryCache.Compact() (#12434)
## Summary Fixes #12430 This PR resolves a race condition in `MemoryCache<TKey, TValue>.Compact()` that was causing intermittent test failures. ## The Problem The `Compact()` method was enumerating a `ConcurrentDictionary` directly while other threads could simultaneously modify it: ```csharp var kvps = _dict.OrderBy(x => x.Value.LastAccess).ToArray(); ``` This violated thread-safety expectations and caused `ArgumentException` during concurrent operations. ## The Solution Add an initial `.ToArray()` call to create a snapshot before sorting: ```csharp var kvps = _dict.ToArray().OrderBy(x => x.Value.LastAccess).ToArray(); ``` This ensures we operate on a stable snapshot rather than the live dictionary, preventing concurrent modifications from disrupting the LINQ enumeration. ## Impact - Eliminates race condition without requiring additional locking - Minimal performance overhead (one extra array allocation) - Resolves intermittent test failures in `Microsoft.CodeAnalysis.Razor.Utilities.MemoryCacheTest.ConcurrentSets_DoesNotThrow`
2 parents 1f0c390 + bf34c4f commit 47fe376

File tree

1 file changed

+1
-1
lines changed

1 file changed

+1
-1
lines changed

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Utilities/MemoryCache`2.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public void Set(TKey key, TValue value)
6464

6565
protected virtual void Compact()
6666
{
67-
var kvps = _dict.OrderBy(x => x.Value.LastAccess).ToArray();
67+
var kvps = _dict.ToArray().OrderBy(x => x.Value.LastAccess).ToArray();
6868

6969
for (var i = 0; i < _sizeLimit / 2; i++)
7070
{

0 commit comments

Comments
 (0)