Skip to content

Commit 36c56d8

Browse files
committed
RavenDB-17373
- Pulling MemoryCache fixes from dotnet/runtime#57631 and dotnet/runtime#61187
1 parent 76753b7 commit 36c56d8

File tree

1 file changed

+24
-11
lines changed

1 file changed

+24
-11
lines changed

src/Raven.Server/Utils/MemoryCache.cs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using System.Runtime.CompilerServices;
1111
using System.Threading;
1212
using System.Threading.Tasks;
13+
using Lucene.Net.Util.Cache;
1314
using Microsoft.Extensions.Caching.Memory;
1415
using Microsoft.Extensions.Internal;
1516
using Microsoft.Extensions.Logging;
@@ -24,7 +25,7 @@ public class MemoryCache : IMemoryCache
2425
internal readonly ILogger _logger;
2526

2627
private readonly MemoryCacheOptions _options;
27-
private readonly ConcurrentDictionary<object, CacheEntry> _entries;
28+
private ConcurrentDictionary<object, CacheEntry> _entries;
2829

2930
private long _cacheSize;
3031
private bool _disposed;
@@ -85,7 +86,18 @@ public MemoryCache(IOptions<MemoryCacheOptions> optionsAccessor, ILoggerFactory
8586

8687
private ICollection<KeyValuePair<object, CacheEntry>> EntriesCollection => _entries;
8788

88-
public void Clear() => _entries.Clear();
89+
public void Clear()
90+
{
91+
var oldEntries = _entries;
92+
Interlocked.Exchange(ref _entries, new ConcurrentDictionary<object, CacheEntry>());
93+
Interlocked.Exchange(ref _cacheSize, 0);
94+
95+
foreach (var entry in oldEntries)
96+
{
97+
entry.Value.SetExpired(EvictionReason.Removed);
98+
entry.Value.InvokeEvictionCallbacks();
99+
}
100+
}
89101

90102
public IEnumerable<KeyValuePair<object, object>> EntriesForDebug => _entries.Select(kvp => new KeyValuePair<object, object>(kvp.Key, kvp.Value.Value));
91103

@@ -386,9 +398,10 @@ public void Compact(double percentage)
386398
private void Compact(long removalSizeTarget, Func<CacheEntry, long> computeEntrySize)
387399
{
388400
var entriesToRemove = new List<CacheEntry>();
389-
var lowPriEntries = new List<CacheEntry>();
390-
var normalPriEntries = new List<CacheEntry>();
391-
var highPriEntries = new List<CacheEntry>();
401+
// cache LastAccessed outside of the CacheEntry so it is stable during compaction
402+
var lowPriEntries = new List<(CacheEntry entry, DateTimeOffset lastAccessed)>();
403+
var normalPriEntries = new List<(CacheEntry entry, DateTimeOffset lastAccessed)>();
404+
var highPriEntries = new List<(CacheEntry entry, DateTimeOffset lastAccessed)>();
392405
long removedSize = 0;
393406

394407
// Sort items by expired & priority status
@@ -406,13 +419,13 @@ private void Compact(long removalSizeTarget, Func<CacheEntry, long> computeEntry
406419
switch (entry.Priority)
407420
{
408421
case CacheItemPriority.Low:
409-
lowPriEntries.Add(entry);
422+
lowPriEntries.Add((entry, entry.LastAccessed));
410423
break;
411424
case CacheItemPriority.Normal:
412-
normalPriEntries.Add(entry);
425+
normalPriEntries.Add((entry, entry.LastAccessed));
413426
break;
414427
case CacheItemPriority.High:
415-
highPriEntries.Add(entry);
428+
highPriEntries.Add((entry, entry.LastAccessed));
416429
break;
417430
case CacheItemPriority.NeverRemove:
418431
break;
@@ -437,7 +450,7 @@ private void Compact(long removalSizeTarget, Func<CacheEntry, long> computeEntry
437450
// ?. Items with the soonest sliding expiration.
438451
// ?. Larger objects - estimated by object graph size, inaccurate.
439452
static void ExpirePriorityBucket(ref long removedSize, long removalSizeTarget, Func<CacheEntry, long> computeEntrySize, List<CacheEntry> entriesToRemove,
440-
List<CacheEntry> priorityEntries)
453+
List<(CacheEntry Entry, DateTimeOffset LastAccessed)> priorityEntries)
441454
{
442455
// Do we meet our quota by just removing expired entries?
443456
if (removalSizeTarget <= removedSize)
@@ -450,8 +463,8 @@ static void ExpirePriorityBucket(ref long removedSize, long removalSizeTarget, F
450463
// TODO: Refine policy
451464

452465
// LRU
453-
priorityEntries.Sort((e1, e2) => e1.LastAccessed.CompareTo(e2.LastAccessed));
454-
foreach (CacheEntry entry in priorityEntries)
466+
priorityEntries.Sort( (e1, e2) => e1.LastAccessed.CompareTo(e2.LastAccessed));
467+
foreach ((CacheEntry entry,_) in priorityEntries)
455468
{
456469
entry.SetExpired(EvictionReason.Capacity);
457470
entriesToRemove.Add(entry);

0 commit comments

Comments
 (0)