diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs b/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs index ed711c0ffa0e9f..6a798ec5e1d7bf 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs @@ -200,6 +200,29 @@ internal void SetEntry(CacheEntry entry) priorEntry?.InvokeEvictionCallbacks(); } + else if (_options.HasSizeLimit && priorEntry != null && priorEntry.Size >= entry.Size) + { + bool entryAdded = coherentState._entries.TryUpdate(entry.Key, entry, priorEntry); + + if (entryAdded) + { + long newSizeIncrement = entry.Size - priorEntry.Size; + + if (newSizeIncrement < 0) + { + Interlocked.Add(ref coherentState._cacheSize, newSizeIncrement); + } + + entry.AttachTokens(); + } + else + { + entry.SetExpired(EvictionReason.Replaced); + entry.InvokeEvictionCallbacks(); + } + + priorEntry.InvokeEvictionCallbacks(); + } else { entry.SetExpired(EvictionReason.Capacity); diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/tests/CapacityTests.cs b/src/libraries/Microsoft.Extensions.Caching.Memory/tests/CapacityTests.cs index 2be2a66bd60e6b..ef6a43fa4190f0 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Memory/tests/CapacityTests.cs +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/tests/CapacityTests.cs @@ -293,6 +293,31 @@ public void AddingReplacementExceedsCapacityRemovesOldEntry() AssertCacheSize(0, cache); // addition was rejected due to size, and previous item with the same key removed } + [Theory] + [InlineData(6)] + [InlineData(5)] + [InlineData(2)] + public void ReplaceOldEntryWithSameSizeOrLessNewEntryAtSizeLimitCapacity(int newValueSize) + { + var cache = new MemoryCache(new MemoryCacheOptions + { + SizeLimit = 6 + }); + + AssertCacheSize(0, cache); + + cache.Set("key", "oldValue", new MemoryCacheEntryOptions { Size = 6 }); + + Assert.Equal("oldValue", cache.Get("key")); + + AssertCacheSize(6, cache); + + cache.Set("key", "newValue", new MemoryCacheEntryOptions { Size = newValueSize }); + + Assert.Equal("newValue", cache.Get("key")); + AssertCacheSize(newValueSize, cache); + } + [Fact] public void RemovingEntryDecreasesCacheSize() {