From 1a8cf35434f22bd777c47623e044412ed7b31737 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Sat, 3 Sep 2022 16:20:57 -0700 Subject: [PATCH 01/15] lock contention --- BitFaster.Caching/Lfu/ConcurrentLfu.cs | 39 ++++++++++++++++++-------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/BitFaster.Caching/Lfu/ConcurrentLfu.cs b/BitFaster.Caching/Lfu/ConcurrentLfu.cs index 5913b827..948f237d 100644 --- a/BitFaster.Caching/Lfu/ConcurrentLfu.cs +++ b/BitFaster.Caching/Lfu/ConcurrentLfu.cs @@ -35,7 +35,7 @@ namespace BitFaster.Caching.Lfu [DebuggerDisplay("Count = {Count}/{Capacity}")] public sealed class ConcurrentLfu : ICache, IAsyncCache, IBoundedPolicy { - private const int MaxWriteBufferRetries = 16; + private const int MaxWriteBufferRetries = 64; private readonly ConcurrentDictionary> dictionary; @@ -265,8 +265,6 @@ private static void TakeCandidatesInLruOrder(LfuNodeList lru, List node) { - var spinner = new SpinWait(); - for (int i = 0; i < MaxWriteBufferRetries; i++) { if (writeBuffer.TryAdd(node) == BufferStatus.Success) @@ -276,12 +274,22 @@ private void AfterWrite(LfuNode node) } TryScheduleDrain(); - - spinner.SpinOnce(); } lock (this.maintenanceLock) { + // aggressively try to exit the lock early before doing full maintenance + var status = BufferStatus.Contended; + while (status != BufferStatus.Full) + { + status = writeBuffer.TryAdd(node); + + if (status != BufferStatus.Success) + { + return; + } + } + // if the write was dropped from the buffer, explicitly pass it to maintenance Maintenance(node); } @@ -289,6 +297,7 @@ private void AfterWrite(LfuNode node) private void ScheduleAfterWrite() { + var spinner = new SpinWait(); while (true) { switch (this.drainStatus.Status()) @@ -309,6 +318,7 @@ private void ScheduleAfterWrite() case DrainStatus.ProcessingToRequired: return; } + spinner.SpinOnce(); } } @@ -384,11 +394,11 @@ private bool Maintenance(LfuNode droppedWrite = null) #if !NETSTANDARD2_0 var localDrainBuffer = ArrayPool>.Shared.Rent(this.readBuffer.Capacity); #endif - int maxSweeps = 1; + // int maxSweeps = 1; int count = 0; - for (int s = 0; s < maxSweeps; s++) - { + // for (int s = 0; s < maxSweeps; s++) + // { count = 0; // extract to a buffer before doing book keeping work, ~2x faster @@ -404,11 +414,16 @@ private bool Maintenance(LfuNode droppedWrite = null) OnAccess(localDrainBuffer[i]); } - wasDrained = count == 0; - } + wasDrained = count == 0 && droppedWrite == null; + // } count = this.writeBuffer.DrainTo(localDrainBuffer); + if (!wasDrained) + { + wasDrained = count == 0 && droppedWrite == null; + } + for (int i = 0; i < count; i++) { OnWrite(localDrainBuffer[i]); @@ -567,7 +582,7 @@ private void EvictFromMain(LfuNode candidate) while (this.windowLru.Count + this.probationLru.Count + this.protectedLru.Count > this.Capacity) { // bail when we run out of options - if (candidate == null || victim == null || victim == candidate) + if (candidate == null | victim == null | victim == candidate) { break; } @@ -579,7 +594,7 @@ private void EvictFromMain(LfuNode candidate) // victim is initialized to first, and iterates forwards victim = victim.Next; - candidate = candidate.Next; + //candidate = candidate.Next; Evict(evictee); } From f783d7610c1d71fe6031fe04e3942f01be0e1f12 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Sat, 3 Sep 2022 17:43:29 -0700 Subject: [PATCH 02/15] fix tests --- .../Lfu/ConcurrentLfuTests.cs | 20 --------------- BitFaster.Caching/Lfu/ConcurrentLfu.cs | 25 +++++++++---------- 2 files changed, 12 insertions(+), 33 deletions(-) diff --git a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs index da263c47..8599237b 100644 --- a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs +++ b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs @@ -176,16 +176,6 @@ public void ReadPromotesProbation() cache.PendingMaintenance(); LogLru(); - for (int i = 25; i < 50; i++) - { - cache.GetOrAdd(i, k => k); - cache.GetOrAdd(i, k => k); - } - - // W [49] Protected [16] Probation [25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42] - cache.PendingMaintenance(); - LogLru(); - cache.Trim(18); // W [49] Protected [16] Probation [] @@ -213,16 +203,6 @@ public void WritePromotesProbation() cache.PendingMaintenance(); LogLru(); - for (int i = 25; i < 50; i++) - { - cache.GetOrAdd(i, k => k); - cache.GetOrAdd(i, k => k); - } - - // W [49] Protected [16] Probation [2,6,7,8,9,10,11,12,13,14,15,17,18,19,20,21,22,23] - cache.PendingMaintenance(); - LogLru(); - cache.Trim(18); // W [49] Protected [16] Probation [] diff --git a/BitFaster.Caching/Lfu/ConcurrentLfu.cs b/BitFaster.Caching/Lfu/ConcurrentLfu.cs index d50c3e2f..02b0dd27 100644 --- a/BitFaster.Caching/Lfu/ConcurrentLfu.cs +++ b/BitFaster.Caching/Lfu/ConcurrentLfu.cs @@ -388,35 +388,34 @@ private bool Maintenance(LfuNode droppedWrite = null) { this.drainStatus.Set(DrainStatus.ProcessingToIdle); var localDrainBuffer = RentDrainBuffer(); + // extract to a buffer before doing book keeping work, ~2x faster - var count = readBuffer.DrainTo(localDrainBuffer); + int readCount = readBuffer.DrainTo(localDrainBuffer); - for (int i = 0; i < count; i++) + for (int i = 0; i < readCount; i++) { this.cmSketch.Increment(localDrainBuffer[i].Key); } - for (int i = 0; i < count; i++) + for (int i = 0; i < readCount; i++) { OnAccess(localDrainBuffer[i]); } - var wasDrained = count == 0 && droppedWrite == null; - count = this.writeBuffer.DrainTo(localDrainBuffer); + int writeCount = this.writeBuffer.DrainTo(localDrainBuffer); - if (!wasDrained) - { - wasDrained = count == 0 && droppedWrite == null; - } - - for (int i = 0; i < count; i++) + for (int i = 0; i < writeCount; i++) { OnWrite(localDrainBuffer[i]); } + // we are done only when both buffers were empty + var done = readCount == 0 & writeCount == 0; + if (droppedWrite != null) { OnWrite(droppedWrite); + done = true; } ReturnDrainBuffer(localDrainBuffer); @@ -428,14 +427,14 @@ private bool Maintenance(LfuNode droppedWrite = null) // Reset to idle if either // 1. We drained both input buffers (all work done) // 2. or scheduler is foreground (since don't run continuously on the foreground) - if ((wasDrained || !scheduler.IsBackground) && + if ((done || !scheduler.IsBackground) && (this.drainStatus.Status() != DrainStatus.ProcessingToIdle || !this.drainStatus.Cas(DrainStatus.ProcessingToIdle, DrainStatus.Idle))) { this.drainStatus.Set(DrainStatus.Required); } - return wasDrained; + return done; } private void OnAccess(LfuNode node) From 080dac649b5c1b20946c65ed5260367c6d28937b Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Sat, 3 Sep 2022 17:46:13 -0700 Subject: [PATCH 03/15] comment --- BitFaster.Caching/Lfu/ConcurrentLfu.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BitFaster.Caching/Lfu/ConcurrentLfu.cs b/BitFaster.Caching/Lfu/ConcurrentLfu.cs index 02b0dd27..7888b18d 100644 --- a/BitFaster.Caching/Lfu/ConcurrentLfu.cs +++ b/BitFaster.Caching/Lfu/ConcurrentLfu.cs @@ -409,7 +409,7 @@ private bool Maintenance(LfuNode droppedWrite = null) OnWrite(localDrainBuffer[i]); } - // we are done only when both buffers were empty + // we are done only when both buffers are empty var done = readCount == 0 & writeCount == 0; if (droppedWrite != null) From 242b07faf79eda7d1e67e69dcd20d939df8b8532 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Sat, 3 Sep 2022 18:35:25 -0700 Subject: [PATCH 04/15] test --- .../Lfu/ConcurrentLfuTests.cs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs index 8599237b..040c9fa3 100644 --- a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs +++ b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs @@ -720,6 +720,37 @@ public void VerifyHitsWithForegroundScheduler() VerifyHits(iterations: iterations + dropped, minSamples: iterations); } + [Fact] + public void VerifyMisses() + { + int iterations = 100000; + Func func = x => x; + + var start = Stopwatch.GetTimestamp(); + + for (int i = 0; i < iterations; i++) + { + cache.GetOrAdd(i, func); + } + + var end = Stopwatch.GetTimestamp(); + + cache.PendingMaintenance(); + + var totalTicks = end - start; + var timeMs = ((double)totalTicks / Stopwatch.Frequency) * 1000.0; + var timeNs = timeMs / 1000000; + + var timePerOp = timeMs / (double)iterations; + var samplePercent = this.cache.Metrics.Value.Misses / (double)iterations * 100; + + this.output.WriteLine($"Elapsed {timeMs}ms - {timeNs}ns/op"); + this.output.WriteLine($"Cache misses {this.cache.Metrics.Value.Misses} (sampled {samplePercent}%)"); + this.output.WriteLine($"Maintenance ops {this.cache.Scheduler.RunCount}"); + + cache.Metrics.Value.Misses.Should().Be(iterations); + } + private void VerifyHits(int iterations, int minSamples) { Func func = x => x; From 387720d852bc479bf6fe3d8b9239dd085c3c5782 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Sat, 3 Sep 2022 18:44:55 -0700 Subject: [PATCH 05/15] foreground --- BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs index 040c9fa3..e765f194 100644 --- a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs +++ b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs @@ -723,6 +723,9 @@ public void VerifyHitsWithForegroundScheduler() [Fact] public void VerifyMisses() { + cache = new ConcurrentLfu(1, 20, new ForegroundScheduler(), EqualityComparer.Default, + new LfuBufferSize(new StripedBufferSize(1, 1), new StripedBufferSize(1, 1))); + int iterations = 100000; Func func = x => x; From 67e8cebcd8bd0c86a1ab1c1faa183d825ee71732 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Sat, 3 Sep 2022 18:50:50 -0700 Subject: [PATCH 06/15] bkgnd --- BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs index e765f194..3071f52b 100644 --- a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs +++ b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs @@ -723,7 +723,7 @@ public void VerifyHitsWithForegroundScheduler() [Fact] public void VerifyMisses() { - cache = new ConcurrentLfu(1, 20, new ForegroundScheduler(), EqualityComparer.Default, + cache = new ConcurrentLfu(1, 20, new BackgroundThreadScheduler(), EqualityComparer.Default, new LfuBufferSize(new StripedBufferSize(1, 1), new StripedBufferSize(1, 1))); int iterations = 100000; From 749ad354eecaea46958451a6bfb2b7f038e83816 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Sat, 3 Sep 2022 19:11:17 -0700 Subject: [PATCH 07/15] thread test --- .../Lfu/ConcurrentLfuTests.cs | 26 +++++++++++++++++++ BitFaster.Caching.UnitTests/Threaded.cs | 26 +++++++++++++++++-- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs index 3071f52b..f223edd6 100644 --- a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs +++ b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs @@ -754,6 +754,32 @@ public void VerifyMisses() cache.Metrics.Value.Misses.Should().Be(iterations); } + [Fact] + public async Task ThreadedVerifyMisses() + { + int threads = 4; + int iterations = 100000; + + await Threaded.Run(threads, i => + { + Func func = x => x; + + int start = i * iterations; + + for (int j = start; j < start + iterations; j++) + { + cache.GetOrAdd(j, func); + } + }); + + var samplePercent = this.cache.Metrics.Value.Misses / (double)iterations / threads * 100; + + this.output.WriteLine($"Cache misses {this.cache.Metrics.Value.Misses} (sampled {samplePercent}%)"); + this.output.WriteLine($"Maintenance ops {this.cache.Scheduler.RunCount}"); + + cache.Metrics.Value.Misses.Should().Be(iterations * threads); + } + private void VerifyHits(int iterations, int minSamples) { Func func = x => x; diff --git a/BitFaster.Caching.UnitTests/Threaded.cs b/BitFaster.Caching.UnitTests/Threaded.cs index 04cc97de..442576b7 100644 --- a/BitFaster.Caching.UnitTests/Threaded.cs +++ b/BitFaster.Caching.UnitTests/Threaded.cs @@ -9,17 +9,39 @@ namespace BitFaster.Caching.UnitTests { public class Threaded { - public static async Task Run(int threadCount, Action action) + public static Task Run(int threadCount, Action action) + { + return Run(threadCount, i => action()); + + //var tasks = new Task[threadCount]; + //ManualResetEvent mre = new ManualResetEvent(false); + + //for (int i = 0; i < threadCount; i++) + //{ + // tasks[i] = Task.Run(() => + // { + // mre.WaitOne(); + // action(); + // }); + //} + + //mre.Set(); + + //await Task.WhenAll(tasks); + } + + public static async Task Run(int threadCount, Action action) { var tasks = new Task[threadCount]; ManualResetEvent mre = new ManualResetEvent(false); for (int i = 0; i < threadCount; i++) { + int run = i; tasks[i] = Task.Run(() => { mre.WaitOne(); - action(); + action(run); }); } From dd42d660c8701f9f8807079f61a872884acf3ecc Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Sat, 3 Sep 2022 19:21:42 -0700 Subject: [PATCH 08/15] 1buffer --- BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs index f223edd6..28df2a5d 100644 --- a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs +++ b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs @@ -757,6 +757,10 @@ public void VerifyMisses() [Fact] public async Task ThreadedVerifyMisses() { + // buffer size is 1, this will cause dropped writes on some threads where the buffer is full + cache = new ConcurrentLfu(1, 20, new BackgroundThreadScheduler(), EqualityComparer.Default, + new LfuBufferSize(new StripedBufferSize(1, 1), new StripedBufferSize(1, 1))); + int threads = 4; int iterations = 100000; From 45457b85189b8ec36dc264d1d875bf6c14511d02 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Sat, 3 Sep 2022 19:30:14 -0700 Subject: [PATCH 09/15] null --- BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs index 28df2a5d..7ae590ea 100644 --- a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs +++ b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs @@ -758,7 +758,7 @@ public void VerifyMisses() public async Task ThreadedVerifyMisses() { // buffer size is 1, this will cause dropped writes on some threads where the buffer is full - cache = new ConcurrentLfu(1, 20, new BackgroundThreadScheduler(), EqualityComparer.Default, + cache = new ConcurrentLfu(1, 20, new NullScheduler(), EqualityComparer.Default, new LfuBufferSize(new StripedBufferSize(1, 1), new StripedBufferSize(1, 1))); int threads = 4; From c452478601339593b7fae9d36c8eeaccd30e7088 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Sat, 3 Sep 2022 19:53:29 -0700 Subject: [PATCH 10/15] fix --- BitFaster.Caching/Lfu/ConcurrentLfu.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BitFaster.Caching/Lfu/ConcurrentLfu.cs b/BitFaster.Caching/Lfu/ConcurrentLfu.cs index 7888b18d..c0b9c163 100644 --- a/BitFaster.Caching/Lfu/ConcurrentLfu.cs +++ b/BitFaster.Caching/Lfu/ConcurrentLfu.cs @@ -283,7 +283,7 @@ private void AfterWrite(LfuNode node) { status = writeBuffer.TryAdd(node); - if (status != BufferStatus.Success) + if (status == BufferStatus.Success) { return; } From 080f28bd51675a0ce08b7ac5d78d91da145e15d9 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Sun, 4 Sep 2022 14:55:51 -0700 Subject: [PATCH 11/15] test --- BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs index 7ae590ea..b23f5889 100644 --- a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs +++ b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs @@ -782,6 +782,7 @@ await Threaded.Run(threads, i => this.output.WriteLine($"Maintenance ops {this.cache.Scheduler.RunCount}"); cache.Metrics.Value.Misses.Should().Be(iterations * threads); + cache.Count.Should().Be(20); } private void VerifyHits(int iterations, int minSamples) From ca88ddf49d997b1326e782bc6f9f04531ce312e2 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Tue, 6 Sep 2022 14:43:20 -0700 Subject: [PATCH 12/15] afterwrite --- BitFaster.Caching/Lfu/ConcurrentLfu.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/BitFaster.Caching/Lfu/ConcurrentLfu.cs b/BitFaster.Caching/Lfu/ConcurrentLfu.cs index b7052051..5b5640e8 100644 --- a/BitFaster.Caching/Lfu/ConcurrentLfu.cs +++ b/BitFaster.Caching/Lfu/ConcurrentLfu.cs @@ -329,6 +329,7 @@ private void AfterWrite(LfuNode node) if (status == BufferStatus.Success) { + ScheduleAfterWrite(); return; } } From b8c3267c1f5ed58f2d479cfbf9bc706958dce897 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Tue, 6 Sep 2022 17:42:40 -0700 Subject: [PATCH 13/15] fix tests --- .../Lfu/ConcurrentLfuTests.cs | 10 ++++++++++ BitFaster.Caching.UnitTests/Threaded.cs | 16 ---------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs index b23f5889..25b634a3 100644 --- a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs +++ b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs @@ -176,6 +176,16 @@ public void ReadPromotesProbation() cache.PendingMaintenance(); LogLru(); + for (int i = 25; i < 50; i++) + { + cache.GetOrAdd(i, k => k); + cache.GetOrAdd(i, k => k); + } + + // W [49] Protected [16] Probation [25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42] + cache.PendingMaintenance(); + LogLru(); + cache.Trim(18); // W [49] Protected [16] Probation [] diff --git a/BitFaster.Caching.UnitTests/Threaded.cs b/BitFaster.Caching.UnitTests/Threaded.cs index 442576b7..50e3f10b 100644 --- a/BitFaster.Caching.UnitTests/Threaded.cs +++ b/BitFaster.Caching.UnitTests/Threaded.cs @@ -12,22 +12,6 @@ public class Threaded public static Task Run(int threadCount, Action action) { return Run(threadCount, i => action()); - - //var tasks = new Task[threadCount]; - //ManualResetEvent mre = new ManualResetEvent(false); - - //for (int i = 0; i < threadCount; i++) - //{ - // tasks[i] = Task.Run(() => - // { - // mre.WaitOne(); - // action(); - // }); - //} - - //mre.Set(); - - //await Task.WhenAll(tasks); } public static async Task Run(int threadCount, Action action) From b8a566e1b141140382368ae5e19007afcdb2b1f2 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Tue, 6 Sep 2022 17:49:37 -0700 Subject: [PATCH 14/15] relax --- BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs index 25b634a3..e7da6a6e 100644 --- a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs +++ b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs @@ -792,7 +792,7 @@ await Threaded.Run(threads, i => this.output.WriteLine($"Maintenance ops {this.cache.Scheduler.RunCount}"); cache.Metrics.Value.Misses.Should().Be(iterations * threads); - cache.Count.Should().Be(20); + cache.Count.Should().BeCloseTo(20, 1); } private void VerifyHits(int iterations, int minSamples) From cf7f77acb39463f097347cba2c54779140261241 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Tue, 6 Sep 2022 17:55:55 -0700 Subject: [PATCH 15/15] rem comment --- BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs | 10 ++++++++++ BitFaster.Caching/Lfu/ConcurrentLfu.cs | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs index e7da6a6e..082d67c5 100644 --- a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs +++ b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs @@ -213,6 +213,16 @@ public void WritePromotesProbation() cache.PendingMaintenance(); LogLru(); + for (int i = 25; i < 50; i++) + { + cache.GetOrAdd(i, k => k); + cache.GetOrAdd(i, k => k); + } + + // W [49] Protected [16] Probation [2,6,7,8,9,10,11,12,13,14,15,17,18,19,20,21,22,23] + cache.PendingMaintenance(); + LogLru(); + cache.Trim(18); // W [49] Protected [16] Probation [] diff --git a/BitFaster.Caching/Lfu/ConcurrentLfu.cs b/BitFaster.Caching/Lfu/ConcurrentLfu.cs index 5b5640e8..058bdd8e 100644 --- a/BitFaster.Caching/Lfu/ConcurrentLfu.cs +++ b/BitFaster.Caching/Lfu/ConcurrentLfu.cs @@ -621,7 +621,7 @@ private void EvictFromMain(LfuNode candidate) // victim is initialized to first, and iterates forwards victim = victim.Next; - //candidate = candidate.Next; + candidate = candidate.Next; Evict(evictee); }