Skip to content

Commit 2f68804

Browse files
author
Alex Peck
committed
handle trim
1 parent 775e9c0 commit 2f68804

File tree

3 files changed

+95
-7
lines changed

3 files changed

+95
-7
lines changed

BitFaster.Caching.UnitTests/Lru/ConcurrentLruTests.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,27 @@ public void WhenItemRemovedFromWarmAfterWarmupItIsEagerlyCycledOut()
764764
lru.Metrics.Value.Evicted.Should().Be(0);
765765
}
766766

767+
[Fact]
768+
public void WhenItemRemovedFromColdAfterWarmupItIsEagerlyCycledOut()
769+
{
770+
for (int i = 0; i < lru.Capacity; i++)
771+
{
772+
lru.GetOrAdd(i, valueFactory.Create);
773+
}
774+
775+
Print(); // Hot [6,7,8] Warm [1,2,3] Cold [0,4,5]
776+
lru.Metrics.Value.Evicted.Should().Be(0);
777+
778+
lru.GetOrAdd(0, valueFactory.Create);
779+
lru.TryRemove(0);
780+
781+
lru.GetOrAdd(9, valueFactory.Create);
782+
783+
Print(); // Hot [7,8,9] Warm [1,2,3] Cold [4,5,6]
784+
785+
lru.Metrics.Value.Evicted.Should().Be(0);
786+
}
787+
767788
[Fact]
768789
public void WhenKeyDoesNotExistTryRemoveReturnsFalse()
769790
{
@@ -772,6 +793,29 @@ public void WhenKeyDoesNotExistTryRemoveReturnsFalse()
772793
lru.TryRemove(2).Should().BeFalse();
773794
}
774795

796+
[Fact]
797+
public void WhenItemsAreRemovedTrimRemovesDeletedItemsFromQueues()
798+
{
799+
for (int i = 0; i < lru.Capacity; i++)
800+
{
801+
lru.GetOrAdd(i, valueFactory.Create);
802+
}
803+
804+
Print(); // Hot [6,7,8] Warm [1,2,3] Cold [0,4,5]
805+
806+
lru.TryRemove(0);
807+
lru.TryRemove(1);
808+
lru.TryRemove(6);
809+
810+
lru.Policy.Eviction.Value.Trim(1);
811+
812+
Print(); // Hot [7,8] Warm [2,3] Cold [5]
813+
814+
lru.HotCount.Should().Be(2);
815+
lru.WarmCount.Should().Be(2);
816+
lru.ColdCount.Should().Be(1);
817+
}
818+
775819
[Fact]
776820
public void WhenRepeatedlyAddingAndRemovingSameValueLruRemainsInConsistentState()
777821
{

BitFaster.Caching.UnitTests/Lru/ConcurrentTLruTests.cs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
using Xunit;
66
using System.Runtime.InteropServices;
77
using BitFaster.Caching.UnitTests.Retry;
8+
using Xunit.Abstractions;
89

910
namespace BitFaster.Caching.UnitTests.Lru
1011
{
1112
public class ConcurrentTLruTests
1213
{
14+
private readonly ITestOutputHelper testOutputHelper;
1315
private readonly TimeSpan timeToLive = TimeSpan.FromMilliseconds(10);
1416
private readonly ICapacityPartition capacity = new EqualCapacityPartition(9);
1517
private ConcurrentTLru<int, string> lru;
@@ -31,8 +33,9 @@ public ConcurrentTLru<K, V> CreateTLru<K, V>(ICapacityPartition capacity, TimeSp
3133
return new ConcurrentTLru<K, V>(1, capacity, EqualityComparer<K>.Default, timeToLive);
3234
}
3335

34-
public ConcurrentTLruTests()
36+
public ConcurrentTLruTests(ITestOutputHelper testOutputHelper)
3537
{
38+
this.testOutputHelper = testOutputHelper;
3639
lru = CreateTLru<int, string>(capacity, timeToLive);
3740
}
3841

@@ -315,6 +318,31 @@ public void WhenItemsAreExpiredEnumerateFiltersExpiredItems()
315318
);
316319
}
317320

321+
[Fact]
322+
public void WhenItemsAreRemovedTrimExpiredRemovesDeletedItemsFromQueues()
323+
{
324+
lru = CreateTLru<int, string>(capacity, TimeSpan.FromMinutes(1));
325+
326+
for (int i = 0; i < lru.Capacity; i++)
327+
{
328+
lru.GetOrAdd(i, valueFactory.Create);
329+
}
330+
331+
Print(); // Hot [6,7,8] Warm [1,2,3] Cold [0,4,5]
332+
333+
lru.TryRemove(0);
334+
lru.TryRemove(1);
335+
lru.TryRemove(6);
336+
337+
lru.Policy.ExpireAfterWrite.Value.TrimExpired();
338+
339+
Print(); // Hot [7,8] Warm [2,3] Cold [4,5]
340+
341+
lru.HotCount.Should().Be(2);
342+
lru.WarmCount.Should().Be(2);
343+
lru.ColdCount.Should().Be(2);
344+
}
345+
318346
[Fact]
319347
public void ConstructWithDefaultCtorReturnsCapacity()
320348
{
@@ -338,5 +366,12 @@ public void ConstructPartitionCtorReturnsCapacity()
338366

339367
x.Capacity.Should().Be(3);
340368
}
369+
370+
private void Print()
371+
{
372+
#if DEBUG
373+
this.testOutputHelper.WriteLine(this.lru.FormatLruString());
374+
#endif
375+
}
341376
}
342377
}

BitFaster.Caching/Lru/ConcurrentLruCore.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ public void Trim(int itemCount)
468468
lock (this.dictionary)
469469
{
470470
// first scan each queue for discardable items and remove them immediately. Note this can remove > itemCount items.
471-
int itemsRemoved = this.itemPolicy.CanDiscard() ? TrimAllDiscardedItems() : 0;
471+
int itemsRemoved = TrimAllDiscardedItems();
472472

473473
TrimLiveItems(itemsRemoved, itemCount, ItemRemovedReason.Trimmed);
474474
}
@@ -478,7 +478,10 @@ private void TrimExpired()
478478
{
479479
if (this.itemPolicy.CanDiscard())
480480
{
481-
this.TrimAllDiscardedItems();
481+
lock (this.dictionary)
482+
{
483+
this.TrimAllDiscardedItems();
484+
}
482485
}
483486
}
484487

@@ -501,12 +504,16 @@ int RemoveDiscardableItems(ConcurrentQueue<I> q, ref int queueCounter)
501504
{
502505
if (q.TryDequeue(out var item))
503506
{
504-
if (this.itemPolicy.ShouldDiscard(item) | item.WasRemoved)
507+
if (this.itemPolicy.ShouldDiscard(item))
505508
{
506509
Interlocked.Decrement(ref queueCounter);
507510
this.Move(item, ItemDestination.Remove, ItemRemovedReason.Trimmed);
508511
itemsRemoved++;
509512
}
513+
else if (item.WasRemoved)
514+
{
515+
Interlocked.Decrement(ref queueCounter);
516+
}
510517
else
511518
{
512519
q.Enqueue(item);
@@ -548,8 +555,10 @@ private void TrimLiveItems(int itemsRemoved, int itemCount, ItemRemovedReason re
548555
itemsRemoved++;
549556
trimWarmAttempts = 0;
550557
}
551-
552-
TrimWarmOrHot(reason);
558+
else
559+
{
560+
TrimWarmOrHot(reason);
561+
}
553562
}
554563
else
555564
{
@@ -829,7 +838,7 @@ IEnumerator IEnumerable.GetEnumerator()
829838
/// Format the LRU as a string by converting all the keys to strings.
830839
/// </summary>
831840
/// <returns>The LRU formatted as a string.</returns>
832-
public string FormatLruString()
841+
internal string FormatLruString()
833842
{
834843
var sb = new System.Text.StringBuilder();
835844

0 commit comments

Comments
 (0)