Skip to content

Commit 09a88ad

Browse files
authored
Merge branch 'main' into users/alexpeck/v2.3.0
2 parents 0065097 + 26063a4 commit 09a88ad

File tree

7 files changed

+72
-27
lines changed

7 files changed

+72
-27
lines changed

BitFaster.Caching.UnitTests/BitFaster.Caching.UnitTests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<PackageReference Include="FluentAssertions" Version="6.12.0" />
1414
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
1515
<PackageReference Include="Moq" Version="4.20.69" />
16-
<PackageReference Include="xunit" Version="2.5.0" />
16+
<PackageReference Include="xunit" Version="2.5.1" />
1717
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
1818
<PrivateAssets>all</PrivateAssets>
1919
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ public void WhenKeyIsRequestedWithArgItIsCreatedAndCached()
5656
[Fact]
5757
public async Task WhenKeyIsRequesteItIsCreatedAndCachedAsync()
5858
{
59-
var result1 = await cache.GetOrAddAsync(1, valueFactory.CreateAsync).ConfigureAwait(false);
60-
var result2 = await cache.GetOrAddAsync(1, valueFactory.CreateAsync).ConfigureAwait(false);
59+
var result1 = await cache.GetOrAddAsync(1, valueFactory.CreateAsync);
60+
var result2 = await cache.GetOrAddAsync(1, valueFactory.CreateAsync);
6161

6262
valueFactory.timesCalled.Should().Be(1);
6363
result1.Should().Be(result2);
@@ -66,8 +66,8 @@ public async Task WhenKeyIsRequesteItIsCreatedAndCachedAsync()
6666
[Fact]
6767
public async Task WhenKeyIsRequestedWithArgItIsCreatedAndCachedAsync()
6868
{
69-
var result1 = await cache.GetOrAddAsync(1, valueFactory.CreateAsync, 9).ConfigureAwait(false);
70-
var result2 = await cache.GetOrAddAsync(1, valueFactory.CreateAsync, 17).ConfigureAwait(false);
69+
var result1 = await cache.GetOrAddAsync(1, valueFactory.CreateAsync, 9);
70+
var result2 = await cache.GetOrAddAsync(1, valueFactory.CreateAsync, 17);
7171

7272
valueFactory.timesCalled.Should().Be(1);
7373
result1.Should().Be(result2);
@@ -676,18 +676,37 @@ public void WhenItemDoesNotExistTryUpdateIsFalse()
676676

677677
[Fact]
678678
public void WhenClearedCacheIsEmpty()
679-
{
679+
{
680680
cache.GetOrAdd(1, k => k);
681-
cache.GetOrAdd(2, k => k);
682-
cache.DoMaintenance();
683-
681+
cache.GetOrAdd(2, k => k);
682+
684683
cache.Clear();
685-
cache.DoMaintenance();
686684

687685
cache.Count.Should().Be(0);
688686
cache.TryGet(1, out var _).Should().BeFalse();
689687
}
690688

689+
[Fact]
690+
public void WhenBackgroundMaintenanceRepeatedReadThenClearResultsInEmpty()
691+
{
692+
cache = new ConcurrentLfu<int, int>(1, 40, new BackgroundThreadScheduler(), EqualityComparer<int>.Default);
693+
694+
var overflow = 0;
695+
for (var a = 0; a < 200; a++)
696+
{
697+
for (var i = 0; i < 40; i++)
698+
{
699+
cache.GetOrAdd(i, k => k);
700+
}
701+
702+
cache.Clear();
703+
overflow += cache.Count;
704+
}
705+
706+
// there should be no iteration of the loop where count != 0
707+
overflow.Should().Be(0);
708+
}
709+
691710
[Fact]
692711
public void TrimRemovesNItems()
693712
{

BitFaster.Caching.UnitTests/Lru/ClassicLruTests.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,8 @@ public void WhenKeyIsRequestedWithArgItIsCreatedAndCached()
195195
[Fact]
196196
public async Task WhenKeyIsRequesteItIsCreatedAndCachedAsync()
197197
{
198-
var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync).ConfigureAwait(false);
199-
var result2 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync).ConfigureAwait(false);
198+
var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync);
199+
var result2 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync);
200200

201201
valueFactory.timesCalled.Should().Be(1);
202202
result1.Should().Be(result2);
@@ -205,8 +205,8 @@ public async Task WhenKeyIsRequesteItIsCreatedAndCachedAsync()
205205
[Fact]
206206
public async Task WhenKeyIsRequestedWithArgItIsCreatedAndCachedAsync()
207207
{
208-
var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync, "x").ConfigureAwait(false);
209-
var result2 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync, "y").ConfigureAwait(false);
208+
var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync, "x");
209+
var result2 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync, "y");
210210

211211
valueFactory.timesCalled.Should().Be(1);
212212
result1.Should().Be(result2);
@@ -227,8 +227,8 @@ public void WhenDifferentKeysAreRequestedValueIsCreatedForEach()
227227
[Fact]
228228
public async Task WhenDifferentKeysAreRequesteValueIsCreatedForEachAsync()
229229
{
230-
var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync).ConfigureAwait(false);
231-
var result2 = await lru.GetOrAddAsync(2, valueFactory.CreateAsync).ConfigureAwait(false);
230+
var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync);
231+
var result2 = await lru.GetOrAddAsync(2, valueFactory.CreateAsync);
232232

233233
valueFactory.timesCalled.Should().Be(2);
234234

BitFaster.Caching.UnitTests/Lru/ConcurrentLruTests.cs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ public void WhenItemIsAddedCountIsCorrect()
134134
public async Task WhenItemIsAddedCountIsCorrectAsync()
135135
{
136136
lru.Count.Should().Be(0);
137-
await lru.GetOrAddAsync(0, valueFactory.CreateAsync).ConfigureAwait(false);
137+
await lru.GetOrAddAsync(0, valueFactory.CreateAsync);
138138
lru.Count.Should().Be(1);
139139
}
140140

@@ -261,8 +261,8 @@ public void WhenKeyIsRequestedWithArgItIsCreatedAndCached()
261261
[Fact]
262262
public async Task WhenKeyIsRequestedItIsCreatedAndCachedAsync()
263263
{
264-
var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync).ConfigureAwait(false);
265-
var result2 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync).ConfigureAwait(false);
264+
var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync);
265+
var result2 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync);
266266

267267
valueFactory.timesCalled.Should().Be(1);
268268
result1.Should().Be(result2);
@@ -271,8 +271,8 @@ public async Task WhenKeyIsRequestedItIsCreatedAndCachedAsync()
271271
[Fact]
272272
public async Task WhenKeyIsRequestedWithArgItIsCreatedAndCachedAsync()
273273
{
274-
var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync, "x").ConfigureAwait(false);
275-
var result2 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync, "y").ConfigureAwait(false);
274+
var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync, "x");
275+
var result2 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync, "y");
276276

277277
valueFactory.timesCalled.Should().Be(1);
278278
result1.Should().Be(result2);
@@ -293,8 +293,8 @@ public void WhenDifferentKeysAreRequestedValueIsCreatedForEach()
293293
[Fact]
294294
public async Task WhenDifferentKeysAreRequesteValueIsCreatedForEachAsync()
295295
{
296-
var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync).ConfigureAwait(false);
297-
var result2 = await lru.GetOrAddAsync(2, valueFactory.CreateAsync).ConfigureAwait(false);
296+
var result1 = await lru.GetOrAddAsync(1, valueFactory.CreateAsync);
297+
var result2 = await lru.GetOrAddAsync(2, valueFactory.CreateAsync);
298298

299299
valueFactory.timesCalled.Should().Be(2);
300300

@@ -866,6 +866,25 @@ public void WhenItemsExistClearRemovesAllItems()
866866
lru.HotCount.Should().Be(0);
867867
lru.WarmCount.Should().Be(0);
868868
lru.ColdCount.Should().Be(0);
869+
}
870+
871+
[Fact]
872+
public void WhenWarmThenClearedIsWarmIsReset()
873+
{
874+
for (int i = 0; i < 20; i++)
875+
{
876+
lru.GetOrAdd(i, k => k.ToString());
877+
}
878+
879+
lru.Clear();
880+
lru.Count.Should().Be(0);
881+
882+
for (int i = 0; i < 20; i++)
883+
{
884+
lru.GetOrAdd(i, k => k.ToString());
885+
}
886+
887+
lru.Count.Should().Be(capacity.Hot + capacity.Warm + capacity.Cold);
869888
}
870889

871890
[Fact]

BitFaster.Caching.UnitTests/Scheduler/BackgroundSchedulerTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,14 @@ public async Task WhenWorkThrowsLastExceptionIsPopulated()
6868
[Fact]
6969
public void WhenBacklogExceededTasksAreDropped()
7070
{
71-
var tcs = new TaskCompletionSource<bool>();
71+
var mre = new ManualResetEvent(false);
7272

7373
for (int i = 0; i < BackgroundThreadScheduler.MaxBacklog * 2; i++)
7474
{
75-
scheduler.Run(() => { tcs.Task.Wait(); });
75+
scheduler.Run(() => { mre.WaitOne(); });
7676
}
7777

78-
tcs.SetResult(true);
78+
mre.Set();
7979

8080
scheduler.RunCount.Should().BeCloseTo(BackgroundThreadScheduler.MaxBacklog, 1);
8181
}

BitFaster.Caching/Lfu/ConcurrentLfu.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,12 @@ private static void TakeCandidatesInLruOrder(LfuNodeList<K, V> lru, List<LfuNode
426426

427427
while (candidates.Count < itemCount && curr != null)
428428
{
429-
candidates.Add(curr);
429+
// LRUs can contain items that are already removed, skip those
430+
if (!curr.WasRemoved)
431+
{
432+
candidates.Add(curr);
433+
}
434+
430435
curr = curr.Next;
431436
}
432437
}

BitFaster.Caching/Lru/ConcurrentLruCore.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,8 @@ public void Clear()
430430
CycleWarmUnchecked(ItemRemovedReason.Cleared);
431431
TryRemoveCold(ItemRemovedReason.Cleared);
432432
}
433+
434+
Volatile.Write(ref this.isWarm, false);
433435
}
434436

435437
/// <summary>

0 commit comments

Comments
 (0)