Skip to content

Commit

Permalink
Fixed spontaneous InvalidOperationException exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
sakno committed Oct 16, 2024
1 parent 78bf136 commit cfe9bc3
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 38 deletions.
27 changes: 0 additions & 27 deletions src/DotNext.Tests/Runtime/Caching/RandomAccessCacheTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,31 +192,4 @@ public static async Task Invalidation()

await cache.InvalidateAsync();
}

[Fact]
public static async Task EvictWhileAdding()
{
await using var cache = new RandomAccessCache<int, string>(3);
using (var scope1 = await cache.ChangeAsync(0))
{
scope1.SetValue("0");

using (var scope = await cache.ChangeAsync(1))
{
scope.SetValue("1");
}

using (var scope = await cache.ChangeAsync(2))
{
scope.SetValue("2");
}

using (var scope = await cache.ChangeAsync(4))
{
scope.SetValue("4");
}
}

False(cache.TryRead(0, out _));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,27 +159,32 @@ internal required TValue Value
[DebuggerDisplay($"NumberOfItems = {{{nameof(Count)}}}")]
internal sealed class Bucket : AsyncExclusiveLock
{
private bool newPairAdded;
private volatile KeyValuePair? first; // volatile

[ExcludeFromCodeCoverage]
private (int Alive, int Dead) Count => first?.BucketNodesCount ?? default;

internal KeyValuePair? TryAdd(IEqualityComparer<TKey>? keyComparer, TKey key, int hashCode, TValue value)
internal KeyValuePair? TryAdd(TKey key, int hashCode, TValue value)
{
var firstCopy = first;
if (firstCopy is not null && firstCopy.KeyHashCode == hashCode
&& (keyComparer?.Equals(key, firstCopy.Key)
?? EqualityComparer<TKey>.Default.Equals(key, firstCopy.Key)))
KeyValuePair? result;
if (newPairAdded)
{
return null;
result = null;
}
else
{
result = CreatePair(key, value, hashCode);
result.NextInBucket = first;
first = result;
newPairAdded = true;
}

var newPair = CreatePair(key, value, hashCode);
newPair.NextInBucket = firstCopy;
first = newPair;
return newPair;
return result;
}

internal void MarkAsReadyToAdd() => newPairAdded = false;

private void Remove(KeyValuePair? previous, KeyValuePair current)
{
ref var location = ref previous is null ? ref first : ref previous.NextInBucket;
Expand Down
3 changes: 2 additions & 1 deletion src/DotNext.Threading/Runtime/Caching/RandomAccessCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ public void SetValue(TValue value)
{
switch (bucketOrValueHolder)
{
case Bucket bucket when bucket.TryAdd(cache.keyComparer, key, hashCode, value) is { } newPair:
case Bucket bucket when bucket.TryAdd(key, hashCode, value) is { } newPair:
cache.Promote(newPair);
break;
case KeyValuePair existingPair:
Expand All @@ -448,6 +448,7 @@ void IDisposable.Dispose()
switch (bucketOrValueHolder)
{
case Bucket bucket:
bucket.MarkAsReadyToAdd();
bucket.Release();
break;
case KeyValuePair pair when pair.ReleaseCounter() is false:
Expand Down

0 comments on commit cfe9bc3

Please sign in to comment.