From 7ddba5ea208fb9b780f1a61d959b4701b5e24dc1 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Tue, 26 Sep 2023 15:30:05 -0700 Subject: [PATCH 1/5] replace tcs blocking task method call (#400) --- .../Scheduler/BackgroundSchedulerTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BitFaster.Caching.UnitTests/Scheduler/BackgroundSchedulerTests.cs b/BitFaster.Caching.UnitTests/Scheduler/BackgroundSchedulerTests.cs index e1938a8c..62db4f7b 100644 --- a/BitFaster.Caching.UnitTests/Scheduler/BackgroundSchedulerTests.cs +++ b/BitFaster.Caching.UnitTests/Scheduler/BackgroundSchedulerTests.cs @@ -68,14 +68,14 @@ public async Task WhenWorkThrowsLastExceptionIsPopulated() [Fact] public void WhenBacklogExceededTasksAreDropped() { - var tcs = new TaskCompletionSource(); + var mre = new ManualResetEvent(false); for (int i = 0; i < BackgroundThreadScheduler.MaxBacklog * 2; i++) { - scheduler.Run(() => { tcs.Task.Wait(); }); + scheduler.Run(() => { mre.WaitOne(); }); } - tcs.SetResult(true); + mre.Set(); scheduler.RunCount.Should().BeCloseTo(BackgroundThreadScheduler.MaxBacklog, 1); } From 1e7741f479ce02fa69a1f29e0629934a41deb1aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Sep 2023 16:28:09 -0700 Subject: [PATCH 2/5] Bump xunit from 2.5.0 to 2.5.1 (#397) Bumps [xunit](https://github.com/xunit/xunit) from 2.5.0 to 2.5.1. - [Commits](https://github.com/xunit/xunit/compare/2.5.0...2.5.1) --- updated-dependencies: - dependency-name: xunit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Alex Peck --- BitFaster.Caching.UnitTests/BitFaster.Caching.UnitTests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BitFaster.Caching.UnitTests/BitFaster.Caching.UnitTests.csproj b/BitFaster.Caching.UnitTests/BitFaster.Caching.UnitTests.csproj index d5487652..591d8285 100644 --- a/BitFaster.Caching.UnitTests/BitFaster.Caching.UnitTests.csproj +++ b/BitFaster.Caching.UnitTests/BitFaster.Caching.UnitTests.csproj @@ -13,7 +13,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 822e160b18dd7f212280140850c112add7e8b931 Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Mon, 2 Oct 2023 11:38:25 -0700 Subject: [PATCH 3/5] ConcurrentLfu.Clear() polluted by removed items (#401) * fix * cleanup --------- --- .../Lfu/ConcurrentLfuTests.cs | 29 +++++++++++++++---- BitFaster.Caching/Lfu/ConcurrentLfu.cs | 7 ++++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs index 453a77a6..8e461068 100644 --- a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs +++ b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs @@ -676,18 +676,37 @@ public void WhenItemDoesNotExistTryUpdateIsFalse() [Fact] public void WhenClearedCacheIsEmpty() - { + { cache.GetOrAdd(1, k => k); - cache.GetOrAdd(2, k => k); - cache.DoMaintenance(); - + cache.GetOrAdd(2, k => k); + cache.Clear(); - cache.DoMaintenance(); cache.Count.Should().Be(0); cache.TryGet(1, out var _).Should().BeFalse(); } + [Fact] + public void WhenBackgroundMaintenanceRepeatedReadThenClearResultsInEmpty() + { + cache = new ConcurrentLfu(1, 40, new BackgroundThreadScheduler(), EqualityComparer.Default); + + var overflow = 0; + for (var a = 0; a < 200; a++) + { + for (var i = 0; i < 40; i++) + { + cache.GetOrAdd(i, k => k); + } + + cache.Clear(); + overflow += cache.Count; + } + + // there should be no iteration of the loop where count != 0 + overflow.Should().Be(0); + } + [Fact] public void TrimRemovesNItems() { diff --git a/BitFaster.Caching/Lfu/ConcurrentLfu.cs b/BitFaster.Caching/Lfu/ConcurrentLfu.cs index 5d4a3bc7..762e282b 100644 --- a/BitFaster.Caching/Lfu/ConcurrentLfu.cs +++ b/BitFaster.Caching/Lfu/ConcurrentLfu.cs @@ -426,7 +426,12 @@ private static void TakeCandidatesInLruOrder(LfuNodeList lru, List Date: Mon, 2 Oct 2023 17:28:31 -0700 Subject: [PATCH 4/5] Fix Infer ConfigureAwait test warnings (#403) * rem * more --------- --- .../Lfu/ConcurrentLfuTests.cs | 8 ++++---- BitFaster.Caching.UnitTests/Lru/ClassicLruTests.cs | 12 ++++++------ .../Lru/ConcurrentLruTests.cs | 14 +++++++------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs index 8e461068..4cbcdacd 100644 --- a/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs +++ b/BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs @@ -56,8 +56,8 @@ public void WhenKeyIsRequestedWithArgItIsCreatedAndCached() [Fact] public async Task WhenKeyIsRequesteItIsCreatedAndCachedAsync() { - var result1 = await cache.GetOrAddAsync(1, valueFactory.CreateAsync).ConfigureAwait(false); - var result2 = await cache.GetOrAddAsync(1, valueFactory.CreateAsync).ConfigureAwait(false); + var result1 = await cache.GetOrAddAsync(1, valueFactory.CreateAsync); + var result2 = await cache.GetOrAddAsync(1, valueFactory.CreateAsync); valueFactory.timesCalled.Should().Be(1); result1.Should().Be(result2); @@ -66,8 +66,8 @@ public async Task WhenKeyIsRequesteItIsCreatedAndCachedAsync() [Fact] public async Task WhenKeyIsRequestedWithArgItIsCreatedAndCachedAsync() { - var result1 = await cache.GetOrAddAsync(1, valueFactory.CreateAsync, 9).ConfigureAwait(false); - var result2 = await cache.GetOrAddAsync(1, valueFactory.CreateAsync, 17).ConfigureAwait(false); + var result1 = await cache.GetOrAddAsync(1, valueFactory.CreateAsync, 9); + var result2 = await cache.GetOrAddAsync(1, valueFactory.CreateAsync, 17); valueFactory.timesCalled.Should().Be(1); result1.Should().Be(result2); diff --git a/BitFaster.Caching.UnitTests/Lru/ClassicLruTests.cs b/BitFaster.Caching.UnitTests/Lru/ClassicLruTests.cs index 9141759b..4b0b790f 100644 --- a/BitFaster.Caching.UnitTests/Lru/ClassicLruTests.cs +++ b/BitFaster.Caching.UnitTests/Lru/ClassicLruTests.cs @@ -195,8 +195,8 @@ public void WhenKeyIsRequestedWithArgItIsCreatedAndCached() [Fact] public async Task WhenKeyIsRequesteItIsCreatedAndCachedAsync() { - var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync).ConfigureAwait(false); - var result2 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync).ConfigureAwait(false); + var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync); + var result2 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync); valueFactory.timesCalled.Should().Be(1); result1.Should().Be(result2); @@ -205,8 +205,8 @@ public async Task WhenKeyIsRequesteItIsCreatedAndCachedAsync() [Fact] public async Task WhenKeyIsRequestedWithArgItIsCreatedAndCachedAsync() { - var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync, "x").ConfigureAwait(false); - var result2 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync, "y").ConfigureAwait(false); + var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync, "x"); + var result2 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync, "y"); valueFactory.timesCalled.Should().Be(1); result1.Should().Be(result2); @@ -227,8 +227,8 @@ public void WhenDifferentKeysAreRequestedValueIsCreatedForEach() [Fact] public async Task WhenDifferentKeysAreRequesteValueIsCreatedForEachAsync() { - var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync).ConfigureAwait(false); - var result2 = await lru.GetOrAddAsync(2, valueFactory.CreateAsync).ConfigureAwait(false); + var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync); + var result2 = await lru.GetOrAddAsync(2, valueFactory.CreateAsync); valueFactory.timesCalled.Should().Be(2); diff --git a/BitFaster.Caching.UnitTests/Lru/ConcurrentLruTests.cs b/BitFaster.Caching.UnitTests/Lru/ConcurrentLruTests.cs index 74f7800f..fc8c5a37 100644 --- a/BitFaster.Caching.UnitTests/Lru/ConcurrentLruTests.cs +++ b/BitFaster.Caching.UnitTests/Lru/ConcurrentLruTests.cs @@ -134,7 +134,7 @@ public void WhenItemIsAddedCountIsCorrect() public async Task WhenItemIsAddedCountIsCorrectAsync() { lru.Count.Should().Be(0); - await lru.GetOrAddAsync(0, valueFactory.CreateAsync).ConfigureAwait(false); + await lru.GetOrAddAsync(0, valueFactory.CreateAsync); lru.Count.Should().Be(1); } @@ -261,8 +261,8 @@ public void WhenKeyIsRequestedWithArgItIsCreatedAndCached() [Fact] public async Task WhenKeyIsRequestedItIsCreatedAndCachedAsync() { - var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync).ConfigureAwait(false); - var result2 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync).ConfigureAwait(false); + var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync); + var result2 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync); valueFactory.timesCalled.Should().Be(1); result1.Should().Be(result2); @@ -271,8 +271,8 @@ public async Task WhenKeyIsRequestedItIsCreatedAndCachedAsync() [Fact] public async Task WhenKeyIsRequestedWithArgItIsCreatedAndCachedAsync() { - var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync, "x").ConfigureAwait(false); - var result2 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync, "y").ConfigureAwait(false); + var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync, "x"); + var result2 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync, "y"); valueFactory.timesCalled.Should().Be(1); result1.Should().Be(result2); @@ -293,8 +293,8 @@ public void WhenDifferentKeysAreRequestedValueIsCreatedForEach() [Fact] public async Task WhenDifferentKeysAreRequesteValueIsCreatedForEachAsync() { - var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync).ConfigureAwait(false); - var result2 = await lru.GetOrAddAsync(2, valueFactory.CreateAsync).ConfigureAwait(false); + var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync); + var result2 = await lru.GetOrAddAsync(2, valueFactory.CreateAsync); valueFactory.timesCalled.Should().Be(2); From 26063a45e7ebf2e5734bb5ab5dad3370216891bf Mon Sep 17 00:00:00 2001 From: Alex Peck Date: Thu, 5 Oct 2023 12:33:34 -0700 Subject: [PATCH 5/5] fix (#404) --- .../Lru/ConcurrentLruTests.cs | 19 +++++++++++++++++++ BitFaster.Caching/Lru/ConcurrentLruCore.cs | 2 ++ 2 files changed, 21 insertions(+) diff --git a/BitFaster.Caching.UnitTests/Lru/ConcurrentLruTests.cs b/BitFaster.Caching.UnitTests/Lru/ConcurrentLruTests.cs index fc8c5a37..c97d3ed4 100644 --- a/BitFaster.Caching.UnitTests/Lru/ConcurrentLruTests.cs +++ b/BitFaster.Caching.UnitTests/Lru/ConcurrentLruTests.cs @@ -866,6 +866,25 @@ public void WhenItemsExistClearRemovesAllItems() lru.HotCount.Should().Be(0); lru.WarmCount.Should().Be(0); lru.ColdCount.Should().Be(0); + } + + [Fact] + public void WhenWarmThenClearedIsWarmIsReset() + { + for (int i = 0; i < 20; i++) + { + lru.GetOrAdd(i, k => k.ToString()); + } + + lru.Clear(); + lru.Count.Should().Be(0); + + for (int i = 0; i < 20; i++) + { + lru.GetOrAdd(i, k => k.ToString()); + } + + lru.Count.Should().Be(capacity.Hot + capacity.Warm + capacity.Cold); } [Fact] diff --git a/BitFaster.Caching/Lru/ConcurrentLruCore.cs b/BitFaster.Caching/Lru/ConcurrentLruCore.cs index 59ec796c..25340ca5 100644 --- a/BitFaster.Caching/Lru/ConcurrentLruCore.cs +++ b/BitFaster.Caching/Lru/ConcurrentLruCore.cs @@ -430,6 +430,8 @@ public void Clear() CycleWarmUnchecked(ItemRemovedReason.Cleared); TryRemoveCold(ItemRemovedReason.Cleared); } + + Volatile.Write(ref this.isWarm, false); } ///