From 61f78fffdddce086e95e6ec578dde352e8605342 Mon Sep 17 00:00:00 2001 From: Yagel Date: Sun, 25 Jul 2021 19:21:19 +0300 Subject: [PATCH] dispose of previous inner (in-memory) cache when calling ClearAll() --- Core.UnitTests/CacheInterfaceTests.cs | 37 +++++++++++++++++++ SystemRuntime.UnitTests/InMemoryCacheTests.cs | 1 + SystemRuntime/ObjectCache.cs | 17 +++++++-- SystemRuntime/SystemRuntime.csproj | 4 +- 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/Core.UnitTests/CacheInterfaceTests.cs b/Core.UnitTests/CacheInterfaceTests.cs index a83f212..7f224b9 100644 --- a/Core.UnitTests/CacheInterfaceTests.cs +++ b/Core.UnitTests/CacheInterfaceTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Threading; using System.Threading.Tasks; namespace PubComp.Caching.Core.UnitTests @@ -214,6 +215,42 @@ public void TestCacheTimeToLive_Constant() Assert.AreNotEqual("1", result); } + [TestMethod] + [Ignore("Diagnose manually the memory consumption")] + public void LotsOfClearAll() + { + var cache = GetCache("cache1"); + for (var i = 0; i < 5000; i++) + { + cache.ClearAll(); + } + Thread.Sleep(1000); + GC.Collect(); + Thread.Sleep(1000); + for (var i = 0; i < 5000; i++) + { + cache.ClearAll(); + } + } + + [TestMethod] + [Ignore("Diagnose manually the memory consumption")] + public async Task LotsOfClearAsyncAll() + { + var cache = GetCache("cache1"); + for (var i = 0; i < 5000; i++) + { + await cache.ClearAllAsync().ConfigureAwait(false); + } + await Task.Delay(1000); + GC.Collect(); + await Task.Delay(1000); + for (var i = 0; i < 5000; i++) + { + await cache.ClearAllAsync().ConfigureAwait(false); + } + } + [TestMethod] public void TestCacheTryGet() { diff --git a/SystemRuntime.UnitTests/InMemoryCacheTests.cs b/SystemRuntime.UnitTests/InMemoryCacheTests.cs index bf03000..ce574f0 100644 --- a/SystemRuntime.UnitTests/InMemoryCacheTests.cs +++ b/SystemRuntime.UnitTests/InMemoryCacheTests.cs @@ -110,6 +110,7 @@ int Get() } [TestMethod] + [Ignore("only a one time test needed")] public void LoadTest_LockingStrategiesComparison() { const int numberOfThreads = 16; diff --git a/SystemRuntime/ObjectCache.cs b/SystemRuntime/ObjectCache.cs index 545fcf1..05374f9 100644 --- a/SystemRuntime/ObjectCache.cs +++ b/SystemRuntime/ObjectCache.cs @@ -220,13 +220,24 @@ public Task ClearAsync(string key) public void ClearAll() { - innerCache = new System.Runtime.Caching.MemoryCache(this.name); + var previousInnerCache = System.Threading.Interlocked.Exchange(ref innerCache, + new System.Runtime.Caching.MemoryCache(this.name)); + + if (previousInnerCache is IDisposable disposeMe) + { + // I had a concern that some classes will hold the reference of the previous cache + // and that the disposing will cause in certain edge race cases a serious exception (AlreadyDisposedException). + // But using the dispose cache object is ok, but does nothing and no exception as well. + // Set: will not set, as if the ClearAll was called a nanosecond after setting + // Get: will get nothing, as if the ClearAll was called a nanosecond before getting + disposeMe.Dispose(); + } } public Task ClearAllAsync() { - innerCache = new System.Runtime.Caching.MemoryCache(this.name); - return Task.FromResult(null); + ClearAll(); + return Task.CompletedTask; } public object GetDetails() => new diff --git a/SystemRuntime/SystemRuntime.csproj b/SystemRuntime/SystemRuntime.csproj index be8b742..dfb599b 100644 --- a/SystemRuntime/SystemRuntime.csproj +++ b/SystemRuntime/SystemRuntime.csproj @@ -5,9 +5,9 @@ PubComp.Caching.SystemRuntime PubComp.Caching.SystemRuntime true - 5.0.0 + 5.0.1 5.0.0.0 - 5.0.0.0 + 5.0.1.0 1701;1702;1591