From c5aacea6e7f0d3ef32be2f27e12005a496645990 Mon Sep 17 00:00:00 2001 From: Hendrik Bulens Date: Tue, 22 Apr 2025 09:54:33 +0200 Subject: [PATCH 1/3] Delete entries using wildcard in memory cache --- .../InMemoryCacheDecorator.cs | 52 +++++++++++++++++-- .../MammothCache.InMemory.csproj | 8 +-- src/MammothCache.sln | 11 ++++ src/MammothCache/MammothCache.csproj | 8 +-- .../MSTestSettings.cs | 1 + .../MammothCache.InMemory.Tests.csproj | 19 +++++++ test/MammothCache.InMemory.Tests/Test1.cs | 25 +++++++++ 7 files changed, 113 insertions(+), 11 deletions(-) create mode 100644 test/MammothCache.InMemory.Tests/MSTestSettings.cs create mode 100644 test/MammothCache.InMemory.Tests/MammothCache.InMemory.Tests.csproj create mode 100644 test/MammothCache.InMemory.Tests/Test1.cs diff --git a/src/MammothCache.InMemory/InMemoryCacheDecorator.cs b/src/MammothCache.InMemory/InMemoryCacheDecorator.cs index 6fa939f..dc2aa41 100644 --- a/src/MammothCache.InMemory/InMemoryCacheDecorator.cs +++ b/src/MammothCache.InMemory/InMemoryCacheDecorator.cs @@ -1,4 +1,9 @@ using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Memory; @@ -48,10 +53,24 @@ public Task SetAsync(string key, T value, TimeSpan? expiry = null) public void Remove(string key, bool exactMatch = true) { - if (!exactMatch) - throw new NotSupportedException("This action is not supported yet"); + if (exactMatch) + { + Cache.Remove(key); + return; + } - Cache.Remove(key); + if (Cache is MemoryCache memoryCache) + { + List entries = GetAllKeys(); + if (entries != null) + { + string pattern = "^" + Regex.Escape(key).Replace("\\*", ".*").Replace("\\?", ".") + "$"; + Regex regex = new(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase); + + foreach (string entry in entries.Where(entry => regex.IsMatch(entry))) + memoryCache.Remove(entry); + } + } } public Task RemoveAsync(string key, bool exactMatch = true) @@ -59,5 +78,32 @@ public Task RemoveAsync(string key, bool exactMatch = true) Remove(key, exactMatch); return Task.CompletedTask; } + + private List GetAllKeys() + { + var coherentState = typeof(MemoryCache).GetField("_coherentState", BindingFlags.NonPublic | BindingFlags.Instance); + + var coherentStateValue = coherentState.GetValue(Cache); + + var stringEntriesCollection = coherentStateValue.GetType().GetProperty("StringEntriesCollection", BindingFlags.NonPublic | BindingFlags.Instance); + + var stringEntriesCollectionValue = stringEntriesCollection.GetValue(coherentStateValue) as ICollection; + + var keys = new List(); + + if (stringEntriesCollectionValue != null) + { + foreach (var item in stringEntriesCollectionValue) + { + var methodInfo = item.GetType().GetProperty("Key"); + + var val = methodInfo.GetValue(item); + + keys.Add(val.ToString()); + } + } + + return keys; + } } } \ No newline at end of file diff --git a/src/MammothCache.InMemory/MammothCache.InMemory.csproj b/src/MammothCache.InMemory/MammothCache.InMemory.csproj index e3c597a..ea40070 100644 --- a/src/MammothCache.InMemory/MammothCache.InMemory.csproj +++ b/src/MammothCache.InMemory/MammothCache.InMemory.csproj @@ -7,9 +7,9 @@ README.md - 1.0.1.0 - 1.0.1.0 - 1.0.1.0 + 1.0.2.0 + 1.0.2.0 + 1.0.2.0 logo.png @@ -18,7 +18,7 @@ Dime Software Mammoth Cache A caching library that decorates the InMemory cache provider. - Copyright © 2024 + Copyright © 2025 https://github.com/dimesoftware/mammoth-cache https://cdn.dime-software.com/dime-software/logo-shape.png https://github.com/dimesoftware/mammoth-cache diff --git a/src/MammothCache.sln b/src/MammothCache.sln index accfa13..cc5c6bd 100644 --- a/src/MammothCache.sln +++ b/src/MammothCache.sln @@ -9,6 +9,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MammothCache.InMemory", "Ma EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MammothCache.Redis", "MammothCache.Redis\MammothCache.Redis.csproj", "{38B1816D-29D7-4D5E-A1FB-1772FC0B044E}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MammothCache.InMemory.Tests", "..\test\MammothCache.InMemory.Tests\MammothCache.InMemory.Tests.csproj", "{C7A1EE8B-243B-4668-A884-4ACF91449B52}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,10 +31,17 @@ Global {38B1816D-29D7-4D5E-A1FB-1772FC0B044E}.Debug|Any CPU.Build.0 = Debug|Any CPU {38B1816D-29D7-4D5E-A1FB-1772FC0B044E}.Release|Any CPU.ActiveCfg = Release|Any CPU {38B1816D-29D7-4D5E-A1FB-1772FC0B044E}.Release|Any CPU.Build.0 = Release|Any CPU + {C7A1EE8B-243B-4668-A884-4ACF91449B52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7A1EE8B-243B-4668-A884-4ACF91449B52}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7A1EE8B-243B-4668-A884-4ACF91449B52}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7A1EE8B-243B-4668-A884-4ACF91449B52}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {C7A1EE8B-243B-4668-A884-4ACF91449B52} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BBFF732A-AEFB-4861-9BB6-18E1D577498B} EndGlobalSection diff --git a/src/MammothCache/MammothCache.csproj b/src/MammothCache/MammothCache.csproj index a2e5131..56a662b 100644 --- a/src/MammothCache/MammothCache.csproj +++ b/src/MammothCache/MammothCache.csproj @@ -1,8 +1,8 @@  - 1.0.0.0 - 1.0.0.0 - 1.0.0.0 + 1.0.1.0 + 1.0.1.0 + 1.0.1.0-beta.1 true @@ -21,7 +21,7 @@ false false false - Copyright © 2023 + Copyright © 2025 https://github.com/dimesoftware/mammoth-cache git diff --git a/test/MammothCache.InMemory.Tests/MSTestSettings.cs b/test/MammothCache.InMemory.Tests/MSTestSettings.cs new file mode 100644 index 0000000..aaf278c --- /dev/null +++ b/test/MammothCache.InMemory.Tests/MSTestSettings.cs @@ -0,0 +1 @@ +[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)] diff --git a/test/MammothCache.InMemory.Tests/MammothCache.InMemory.Tests.csproj b/test/MammothCache.InMemory.Tests/MammothCache.InMemory.Tests.csproj new file mode 100644 index 0000000..fdd664f --- /dev/null +++ b/test/MammothCache.InMemory.Tests/MammothCache.InMemory.Tests.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + latest + enable + enable + + true + + + + + + + diff --git a/test/MammothCache.InMemory.Tests/Test1.cs b/test/MammothCache.InMemory.Tests/Test1.cs new file mode 100644 index 0000000..91d2975 --- /dev/null +++ b/test/MammothCache.InMemory.Tests/Test1.cs @@ -0,0 +1,25 @@ +using Microsoft.Extensions.Caching.Memory; + +namespace MammothCache.InMemory.Tests +{ + [TestClass] + public sealed class InMemoryCacheDecoratorTests + { + [TestMethod] + public void InMemoryCacheDecorator_Remove_Wildcard_ShouldDeleteAll() + { + InMemoryCacheDecorator cache = new(new MemoryCache(new MemoryCacheOptions())); + cache.Set("key1:suffix1", true); + cache.Set("key1:suffix2", true); + cache.Set("prefix1:key1:suffix2", true); + cache.Set("key2", true); + + cache.Remove("key1:*", false); + + Assert.IsTrue(cache.Get("key1:suffix1") == null); + Assert.IsTrue(cache.Get("key1:suffix2") == null); + Assert.IsTrue(cache.Get("key2") == true); + Assert.IsTrue(cache.Get("prefix1:key1:suffix2") == true); + } + } +} From 85e816ba5473a113ef9ad761b21bab3024105702 Mon Sep 17 00:00:00 2001 From: Hendrik Bulens Date: Tue, 22 Apr 2025 10:00:01 +0200 Subject: [PATCH 2/3] Refactor --- .../InMemoryCacheDecorator.cs | 22 +++++++------------ src/MammothCache/MammothCache.csproj | 2 +- ...est1.cs => InMemoryCacheDecoratorTests.cs} | 0 3 files changed, 9 insertions(+), 15 deletions(-) rename test/MammothCache.InMemory.Tests/{Test1.cs => InMemoryCacheDecoratorTests.cs} (100%) diff --git a/src/MammothCache.InMemory/InMemoryCacheDecorator.cs b/src/MammothCache.InMemory/InMemoryCacheDecorator.cs index 009a8c2..c2e239e 100644 --- a/src/MammothCache.InMemory/InMemoryCacheDecorator.cs +++ b/src/MammothCache.InMemory/InMemoryCacheDecorator.cs @@ -107,24 +107,18 @@ public Task RemoveAsync(string key, bool exactMatch = true) private List GetAllKeys() { - var coherentState = typeof(MemoryCache).GetField("_coherentState", BindingFlags.NonPublic | BindingFlags.Instance); + FieldInfo coherentState = typeof(MemoryCache).GetField("_coherentState", BindingFlags.NonPublic | BindingFlags.Instance); + object coherentStateValue = coherentState.GetValue(Cache); + PropertyInfo stringEntriesCollection = coherentStateValue.GetType().GetProperty("StringEntriesCollection", BindingFlags.NonPublic | BindingFlags.Instance); - var coherentStateValue = coherentState.GetValue(Cache); + List keys = []; - var stringEntriesCollection = coherentStateValue.GetType().GetProperty("StringEntriesCollection", BindingFlags.NonPublic | BindingFlags.Instance); - - var stringEntriesCollectionValue = stringEntriesCollection.GetValue(coherentStateValue) as ICollection; - - var keys = new List(); - - if (stringEntriesCollectionValue != null) + if (stringEntriesCollection.GetValue(coherentStateValue) is ICollection stringEntriesCollectionValue) { - foreach (var item in stringEntriesCollectionValue) + foreach (object item in stringEntriesCollectionValue) { - var methodInfo = item.GetType().GetProperty("Key"); - - var val = methodInfo.GetValue(item); - + PropertyInfo methodInfo = item.GetType().GetProperty("Key"); + object val = methodInfo.GetValue(item); keys.Add(val.ToString()); } } diff --git a/src/MammothCache/MammothCache.csproj b/src/MammothCache/MammothCache.csproj index 4889c5d..cdb4f04 100644 --- a/src/MammothCache/MammothCache.csproj +++ b/src/MammothCache/MammothCache.csproj @@ -2,7 +2,7 @@ 1.1.0.0 1.1.0.0 - 1.1.0.0 + 1.1.1.0-beta.1 true diff --git a/test/MammothCache.InMemory.Tests/Test1.cs b/test/MammothCache.InMemory.Tests/InMemoryCacheDecoratorTests.cs similarity index 100% rename from test/MammothCache.InMemory.Tests/Test1.cs rename to test/MammothCache.InMemory.Tests/InMemoryCacheDecoratorTests.cs From 5f3b65893778a35879f0f1683c9abdd5cd62ed32 Mon Sep 17 00:00:00 2001 From: Hendrik Bulens Date: Tue, 22 Apr 2025 11:22:43 +0200 Subject: [PATCH 3/3] Bump packages --- src/MammothCache.InMemory/MammothCache.InMemory.csproj | 2 +- src/MammothCache.Redis/MammothCache.Redis.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MammothCache.InMemory/MammothCache.InMemory.csproj b/src/MammothCache.InMemory/MammothCache.InMemory.csproj index 785af65..d17c6aa 100644 --- a/src/MammothCache.InMemory/MammothCache.InMemory.csproj +++ b/src/MammothCache.InMemory/MammothCache.InMemory.csproj @@ -9,7 +9,7 @@ 1.1.0.0 1.1.0.0 - 1.1.0.0-beta.5 + 1.1.1.0-beta.1 logo.png diff --git a/src/MammothCache.Redis/MammothCache.Redis.csproj b/src/MammothCache.Redis/MammothCache.Redis.csproj index 3d8ba6e..78661f6 100644 --- a/src/MammothCache.Redis/MammothCache.Redis.csproj +++ b/src/MammothCache.Redis/MammothCache.Redis.csproj @@ -11,7 +11,7 @@ 1.1.0.0 1.1.0.0 - 1.1.0-beta.5 + 1.1.1.0-beta.1 net8.0