Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion BitFaster.Caching.UnitTests/Lfu/ConcurrentLfuTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Threading.Tasks;
using BitFaster.Caching.Buffers;
using BitFaster.Caching.Lfu;
using BitFaster.Caching.Lru;
using BitFaster.Caching.Scheduler;
using BitFaster.Caching.UnitTests.Lru;
using FluentAssertions;
Expand Down Expand Up @@ -56,13 +57,23 @@ public void WhenCapacityIsValidCacheIsCreated()
}

[Fact]
public void WhenConcurrencyIsLessThan1CtorThrows()
public void WhenConcurrencyIsZeroCtorThrows()
{
Action constructor = () => { var x = new ConcurrentLfu<int, string>(0, 20, new ForegroundScheduler(), EqualityComparer<int>.Default); };

constructor.Should().Throw<ArgumentOutOfRangeException>();
}

#if NET8_0_OR_GREATER
// -1 is default conc level on .NET 8+. This can cause invalid striped buffer size without explicit handling.
[Fact]
public void WhenConcurrencyIsNegativeOneReadBufferIsCorrectSize()
{
var x = new ConcurrentLfu<int, string>(-1, 20, new ForegroundScheduler(), EqualityComparer<int>.Default);
x.Core.readBuffer.Capacity.Should().Be(BitOps.CeilingPowerOfTwo(Defaults.ConcurrencyLevel) * 128);
}
#endif

[Fact]
public void DefaultSchedulerIsThreadPool()
{
Expand Down
10 changes: 10 additions & 0 deletions BitFaster.Caching/Lfu/ConcurrentLfuCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
using BitFaster.Caching.Buffers;
using BitFaster.Caching.Counters;
using BitFaster.Caching.Scheduler;
using BitFaster.Caching.Lru;


#if DEBUG
using System.Text;
Expand Down Expand Up @@ -96,6 +98,14 @@ public ConcurrentLfuCore(int concurrencyLevel, int capacity, IScheduler schedule
int dictionaryCapacity = ConcurrentDictionarySize.Estimate(capacity);
this.dictionary = new(concurrencyLevel, dictionaryCapacity, comparer);

// On .NET 8+, -1 can be used for default conc level. concurrencyLevel is guarded by the dictionary ctor that will not throw in this case.
#if NET8_0_OR_GREATER
if (concurrencyLevel == -1)
{
concurrencyLevel = Defaults.ConcurrencyLevel;
}
#endif

// cap concurrency at proc count * 2
int readStripes = Math.Min(BitOps.CeilingPowerOfTwo(concurrencyLevel), BitOps.CeilingPowerOfTwo(Environment.ProcessorCount * 2));
this.readBuffer = new(readStripes, DefaultBufferSize);
Expand Down
5 changes: 0 additions & 5 deletions BitFaster.Caching/Lru/Defaults.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@ namespace BitFaster.Caching.Lru
{
internal static class Defaults
{
#if NET8_0_OR_GREATER
// Note that on .net8+, -1 indicates the default concurrency level
public static int ConcurrencyLevel => -1;
#else
public static int ConcurrencyLevel => Environment.ProcessorCount;
#endif
}
}
Loading