Skip to content

Commit e2a3cfb

Browse files
committed
feat: changed memory cache key list implementation
1 parent e7e10d9 commit e2a3cfb

File tree

3 files changed

+308
-193
lines changed

3 files changed

+308
-193
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using Microsoft.Extensions.Caching.Memory;
2+
3+
namespace Cogworks.Essentials.EventArgs
4+
{
5+
public class CacheEvictionArgs : System.EventArgs
6+
{
7+
public object Key { get; }
8+
9+
public object Value { get; }
10+
11+
public EvictionReason EvictionReason { get; set; }
12+
13+
public CacheEvictionArgs(object key, object value, EvictionReason evictionReason)
14+
{
15+
Key = key;
16+
Value = value;
17+
EvictionReason = evictionReason;
18+
}
19+
}
20+
}

Source/Cogworks.Essentials/Services/MemoryCacheService.cs

Lines changed: 49 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
using System;
22
using System.Collections.Concurrent;
33
using System.Collections.Generic;
4+
using System.Collections.Immutable;
45
using System.Linq;
56
using System.Threading;
67
using System.Threading.Tasks;
78
using Cogworks.Essentials.Constants;
9+
using Cogworks.Essentials.EventArgs;
810
using Cogworks.Essentials.Extensions;
911
using Cogworks.Essentials.Services.Interfaces;
1012
using Microsoft.Extensions.Caching.Memory;
@@ -13,10 +15,10 @@ namespace Cogworks.Essentials.Services
1315
{
1416
public class MemoryCacheService : ICacheService, IDisposable
1517
{
16-
private const string CacheKeyList = "CacheKeyList";
17-
1818
private readonly IMemoryCache _memoryCache;
1919

20+
private ImmutableHashSet<string> _cacheKeys = ImmutableHashSet<string>.Empty;
21+
2022
private static ConcurrentDictionary<object, SemaphoreSlim> Locks => new ConcurrentDictionary<object, SemaphoreSlim>();
2123

2224
public MemoryCacheService(IMemoryCache memoryCache)
@@ -34,10 +36,7 @@ public T GetCacheItem<T>(string cacheKey)
3436
: default;
3537

3638
public void RemoveCacheItem(string cacheKey)
37-
{
38-
RemoveCacheKeyList(cacheKey);
39-
_memoryCache.Remove(cacheKey);
40-
}
39+
=> _memoryCache.Remove(cacheKey);
4140

4241
public void AddCacheItem(string cacheKey, object value, int? cacheDurationInSeconds = null)
4342
{
@@ -46,7 +45,11 @@ public void AddCacheItem(string cacheKey, object value, int? cacheDurationInSeco
4645
cacheDurationInSeconds ??= DateTimeConstants.TimeInSecondsConstants.Hour;
4746
var cacheDurationDateTime = DateTime.UtcNow.AddSeconds(cacheDurationInSeconds.Value);
4847

49-
_memoryCache.Set(cacheKey, value, cacheDurationDateTime);
48+
var entryOptions = new MemoryCacheEntryOptions()
49+
.SetAbsoluteExpiration(cacheDurationDateTime)
50+
.RegisterPostEvictionCallback(CacheCallback);
51+
52+
_memoryCache.Set(cacheKey, value, entryOptions);
5053
}
5154

5255
public T GetOrAddCacheItem<T>(string cacheKey, Func<T> getValueFunction, int? cacheDurationInSeconds = null)
@@ -57,6 +60,12 @@ public T GetOrAddCacheItem<T>(string cacheKey, Func<T> getValueFunction, int? ca
5760
var cacheDurationDateTime = DateTime.UtcNow.AddSeconds(cacheDurationInSeconds.Value);
5861

5962
entry.AbsoluteExpiration = cacheDurationDateTime;
63+
64+
entry.PostEvictionCallbacks.Add(new PostEvictionCallbackRegistration()
65+
{
66+
EvictionCallback = CacheCallback
67+
});
68+
6069
AddCacheKeyList(cacheKey);
6170

6271
return getValueFunction();
@@ -91,7 +100,11 @@ public async Task<T> GetOrAddCacheItemAsync<T>(string cacheKey, Func<Task<T>> ge
91100
cacheDurationInSeconds ??= DateTimeConstants.TimeInSecondsConstants.Hour;
92101
var cacheDurationDateTime = DateTime.UtcNow.AddSeconds(cacheDurationInSeconds.Value);
93102

94-
_memoryCache.Set(cacheKey, cacheEntry, cacheDurationDateTime);
103+
var entryOptions = new MemoryCacheEntryOptions()
104+
.SetAbsoluteExpiration(cacheDurationDateTime)
105+
.RegisterPostEvictionCallback(CacheCallback);
106+
107+
_memoryCache.Set(cacheKey, cacheEntry, entryOptions);
95108
}
96109
}
97110
finally
@@ -105,7 +118,7 @@ public async Task<T> GetOrAddCacheItemAsync<T>(string cacheKey, Func<Task<T>> ge
105118

106119
public void ClearAllStartingWith(string prefixKey)
107120
{
108-
var cacheKeys = GetOrAddCacheKeyList()
121+
var cacheKeys = _cacheKeys
109122
.Where(x => x.StartsWith(prefixKey))
110123
.ToList();
111124

@@ -118,15 +131,13 @@ public void ClearAllStartingWith(string prefixKey)
118131
{
119132
_memoryCache.Remove(key);
120133
}
121-
122-
RemoveCacheKeyList(cacheKeys);
123134
}
124135

125136
public void ClearAll()
126137
{
127-
var cacheKeys = GetOrAddCacheKeyList();
138+
var cacheKeys = _cacheKeys.ToArray();
128139

129-
if (!cacheKeys.HasAny())
140+
if (!_cacheKeys.HasAny())
130141
{
131142
return;
132143
}
@@ -135,55 +146,43 @@ public void ClearAll()
135146
{
136147
_memoryCache.Remove(key);
137148
}
138-
139-
RemoveCacheKeyList(cacheKeys);
140149
}
141150

142-
public void Dispose()
143-
=> _memoryCache.Dispose();
151+
public IEnumerable<string> GetKeys()
152+
=> _cacheKeys.ToList();
144153

145-
private void AddCacheKeyList(string cacheKey)
154+
public void Dispose()
146155
{
147-
var cacheKeyList = GetOrAddCacheKeyList();
148-
149-
cacheKeyList.AddUnique(cacheKey);
150-
151-
var cacheDurationDateTime = DateTime.UtcNow.AddSeconds(DateTimeConstants.TimeInSecondsConstants.Year);
152-
153-
_memoryCache.Set(CacheKeyList, cacheKeyList, cacheDurationDateTime);
156+
_cacheKeys = _cacheKeys.Clear();
157+
_memoryCache.Dispose();
154158
}
155159

156-
private void RemoveCacheKeyList(string cacheKey)
157-
{
158-
var cacheKeyList = GetOrAddCacheKeyList();
159-
160-
cacheKeyList.Remove(cacheKey);
160+
private void AddCacheKeyList(string cacheKey)
161+
=> ImmutableInterlocked.Update(
162+
ref _cacheKeys,
163+
(collection, item) => collection.Add(item),
164+
cacheKey);
161165

162-
UpdateCacheKeyList(cacheKeyList);
163-
}
166+
private void RemoveCacheKeyList(string cacheKey)
167+
=> ImmutableInterlocked.Update(
168+
ref _cacheKeys,
169+
(collection, item) => collection.Remove(item),
170+
cacheKey);
164171

165-
private void RemoveCacheKeyList(IEnumerable<string> toBeRemovedItems)
172+
private void CacheCallback(object key, object value, EvictionReason reason, object state)
166173
{
167-
var cacheKeys = GetOrAddCacheKeyList();
174+
if (reason == EvictionReason.Replaced || key is not string cacheKey)
175+
{
176+
return;
177+
}
168178

169-
cacheKeys = cacheKeys.Except(toBeRemovedItems).ToList();
179+
CacheEvictionEvent?.Invoke(
180+
this,
181+
new CacheEvictionArgs(key, value, reason));
170182

171-
UpdateCacheKeyList(cacheKeys);
183+
RemoveCacheKeyList(cacheKey);
172184
}
173185

174-
private void UpdateCacheKeyList(IEnumerable<string> cacheKeys)
175-
=> _memoryCache.Set(
176-
CacheKeyList,
177-
cacheKeys,
178-
DateTime.UtcNow.AddSeconds(DateTimeConstants.TimeInSecondsConstants.Year));
179-
180-
private List<string> GetOrAddCacheKeyList()
181-
=> _memoryCache.GetOrCreate(CacheKeyList, entry =>
182-
{
183-
var cacheDurationDateTime = DateTime.UtcNow.AddSeconds(DateTimeConstants.TimeInSecondsConstants.Year);
184-
entry.AbsoluteExpiration = cacheDurationDateTime;
185-
186-
return new List<string>();
187-
});
186+
public event EventHandler<CacheEvictionArgs> CacheEvictionEvent;
188187
}
189188
}

0 commit comments

Comments
 (0)