Skip to content

Commit 426011b

Browse files
committed
InMemoryCacheClient should filter out expired items from count and items
1 parent bee5d09 commit 426011b

File tree

1 file changed

+16
-13
lines changed

1 file changed

+16
-13
lines changed

src/Foundatio/Caching/InMemoryCacheClient.cs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public InMemoryCacheClient(InMemoryCacheClientOptions options = null)
4444
public InMemoryCacheClient(Builder<InMemoryCacheClientOptionsBuilder, InMemoryCacheClientOptions> config)
4545
: this(config(new InMemoryCacheClientOptionsBuilder()).Build()) { }
4646

47-
public int Count => _memory.Count;
47+
public int Count => _memory.Count(i => !i.Value.IsExpired);
4848
public int? MaxItems => _maxItems;
4949
public long Calls => _writes + _hits + _misses;
5050
public long Writes => _writes;
@@ -67,7 +67,7 @@ public void ResetStats()
6767
_misses = 0;
6868
}
6969

70-
public AsyncEvent<ItemExpiredEventArgs> ItemExpired { get; } = new AsyncEvent<ItemExpiredEventArgs>();
70+
public AsyncEvent<ItemExpiredEventArgs> ItemExpired { get; } = new();
7171

7272
private void OnItemExpired(string key, bool sendNotification = true)
7373
{
@@ -92,6 +92,7 @@ public ICollection<string> Keys
9292
get
9393
{
9494
return _memory.ToArray()
95+
.Where(kvp => !kvp.Value.IsExpired)
9596
.OrderBy(kvp => kvp.Value.LastAccessTicks)
9697
.ThenBy(kvp => kvp.Value.InstanceNumber)
9798
.Select(kvp => kvp.Key)
@@ -104,6 +105,7 @@ public ICollection<KeyValuePair<string, object>> Items
104105
get
105106
{
106107
return _memory.ToArray()
108+
.Where(kvp => !kvp.Value.IsExpired)
107109
.OrderBy(kvp => kvp.Value.LastAccessTicks)
108110
.ThenBy(kvp => kvp.Value.InstanceNumber)
109111
.Select(kvp => new KeyValuePair<string, object>(kvp.Key, kvp.Value))
@@ -202,11 +204,11 @@ public Task<int> RemoveByPrefixAsync(string prefix)
202204
internal void RemoveExpiredKey(string key, bool sendNotification = true)
203205
{
204206
// Consideration: We could reduce the amount of calls to this by updating ExpiresAt and only having maintenance remove keys.
205-
if (_memory.TryGetValue(key, out var existingEntry) && existingEntry.ExpiresAt < _timeProvider.GetUtcNow())
207+
if (_memory.TryGetValue(key, out var existingEntry) && existingEntry.IsExpired)
206208
{
207209
if (_memory.TryRemove(key, out var removedEntry))
208210
{
209-
if (removedEntry.ExpiresAt >= _timeProvider.GetUtcNow())
211+
if (!removedEntry.IsExpired)
210212
throw new Exception("Removed item was not expired");
211213

212214
_logger.LogDebug("Removing expired cache entry {Key}", key);
@@ -226,7 +228,7 @@ public Task<CacheValue<T>> GetAsync<T>(string key)
226228
return Task.FromResult(CacheValue<T>.NoValue);
227229
}
228230

229-
if (existingEntry.ExpiresAt < _timeProvider.GetUtcNow().UtcDateTime)
231+
if (existingEntry.IsExpired)
230232
{
231233
Interlocked.Increment(ref _misses);
232234
return Task.FromResult(CacheValue<T>.NoValue);
@@ -488,7 +490,7 @@ public async Task<long> ListAddAsync<T>(string key, IEnumerable<T> values, TimeS
488490

489491
if (values is string stringValue)
490492
{
491-
var items = new HashSet<string>(new[] { stringValue });
493+
var items = new HashSet<string>([stringValue]);
492494
var entry = new CacheEntry(items, expiresAt, _timeProvider, _shouldClone);
493495
_memory.AddOrUpdate(key, entry, (existingKey, existingEntry) =>
494496
{
@@ -551,7 +553,7 @@ public Task<long> ListRemoveAsync<T>(string key, IEnumerable<T> values, TimeSpan
551553

552554
if (values is string stringValue)
553555
{
554-
var items = new HashSet<string>(new[] { stringValue });
556+
var items = new HashSet<string>([stringValue]);
555557
_memory.TryUpdate(key, (existingKey, existingEntry) =>
556558
{
557559
if (existingEntry.Value is ICollection<string> { Count: > 0 } collection)
@@ -614,7 +616,7 @@ private async Task<bool> SetInternalAsync(string key, CacheEntry entry, bool add
614616
if (String.IsNullOrEmpty(key))
615617
throw new ArgumentNullException(nameof(key), "SetInternalAsync: Key cannot be null or empty");
616618

617-
if (entry.ExpiresAt < _timeProvider.GetUtcNow().UtcDateTime)
619+
if (entry.IsExpired)
618620
{
619621
RemoveExpiredKey(key);
620622
return false;
@@ -632,7 +634,7 @@ private async Task<bool> SetInternalAsync(string key, CacheEntry entry, bool add
632634
wasUpdated = false;
633635

634636
// check to see if existing entry is expired
635-
if (existingEntry.ExpiresAt < _timeProvider.GetUtcNow().UtcDateTime)
637+
if (existingEntry.IsExpired)
636638
{
637639
if (isTraceLogLevelEnabled)
638640
_logger.LogTrace("Attempting to replacing expired cache key: {Key}", existingKey);
@@ -812,7 +814,7 @@ public Task<bool> ExistsAsync(string key)
812814
return Task.FromResult(false);
813815
}
814816

815-
if (existingEntry.ExpiresAt < _timeProvider.GetUtcNow().UtcDateTime)
817+
if (existingEntry.IsExpired)
816818
{
817819
Interlocked.Increment(ref _misses);
818820
return Task.FromResult(false);
@@ -833,7 +835,7 @@ public Task<bool> ExistsAsync(string key)
833835
return Task.FromResult<TimeSpan?>(null);
834836
}
835837

836-
if (existingEntry.ExpiresAt < _timeProvider.GetUtcNow().UtcDateTime || existingEntry.ExpiresAt == DateTime.MaxValue)
838+
if (existingEntry.IsExpired || existingEntry.ExpiresAt == DateTime.MaxValue)
837839
{
838840
Interlocked.Increment(ref _misses);
839841
return Task.FromResult<TimeSpan?>(null);
@@ -892,7 +894,7 @@ private async Task CompactAsync()
892894
(string Key, long LastAccessTicks, long InstanceNumber) oldest = (null, Int64.MaxValue, 0);
893895
foreach (var kvp in _memory)
894896
{
895-
bool isExpired = kvp.Value.ExpiresAt < _timeProvider.GetUtcNow().UtcDateTime;
897+
bool isExpired = kvp.Value.IsExpired;
896898
if (isExpired ||
897899
kvp.Value.LastAccessTicks < oldest.LastAccessTicks ||
898900
(kvp.Value.LastAccessTicks == oldest.LastAccessTicks && kvp.Value.InstanceNumber < oldest.InstanceNumber))
@@ -907,7 +909,7 @@ private async Task CompactAsync()
907909

908910
_logger.LogDebug("Removing cache entry {Key} due to cache exceeding max item count limit", oldest);
909911
_memory.TryRemove(oldest.Key, out var cacheEntry);
910-
if (cacheEntry != null && cacheEntry.ExpiresAt < _timeProvider.GetUtcNow().UtcDateTime)
912+
if (cacheEntry is { IsExpired: true })
911913
expiredKey = oldest.Key;
912914
}
913915

@@ -972,6 +974,7 @@ public CacheEntry(object value, DateTime expiresAt, TimeProvider timeProvider, b
972974

973975
internal long InstanceNumber { get; private set; }
974976
internal DateTime ExpiresAt { get; set; }
977+
internal bool IsExpired => ExpiresAt < _timeProvider.GetUtcNow().UtcDateTime;
975978
internal long LastAccessTicks { get; private set; }
976979
internal long LastModifiedTicks { get; private set; }
977980
#if DEBUG

0 commit comments

Comments
 (0)