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
25 changes: 25 additions & 0 deletions BitFaster.Caching.UnitTests/SingletonCacheTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,31 @@ public void AcquireWithSameKeyReturnsSameLifetime()
lifetime2.Dispose();
}

[Fact]
public void AcquireWithSameKeyMaintainsReferenceCount()
{
var cache = new SingletonCache<string, object>();

using (var lifetime1 = cache.Acquire("Foo"))
{
using (var lifetime2 = cache.Acquire("Foo"))
{
lifetime1.ReferenceCount.Should().Be(1);
lifetime2.ReferenceCount.Should().Be(2);
}

using (var lifetime3 = cache.Acquire("Foo"))
{
lifetime3.ReferenceCount.Should().Be(2);
}
}

using (var lifetime4 = cache.Acquire("Foo"))
{
lifetime4.ReferenceCount.Should().Be(1);
}
}

[Fact]
public void AcquireReleaseAcquireReturnsDifferentValue()
{
Expand Down
12 changes: 9 additions & 3 deletions BitFaster.Caching/Lifetime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,29 @@ namespace BitFaster.Caching
public class Lifetime<T> : IDisposable
{
private readonly Action onDisposeAction;
private readonly ReferenceCount<T> refCount;
private bool isDisposed;

/// <summary>
/// Initializes a new instance of the Lifetime class.
/// </summary>
/// <param name="value">The value to keep alive.</param>
/// <param name="onDisposeAction">The action to perform when the lifetime is terminated.</param>
public Lifetime(T value, Action onDisposeAction)
public Lifetime(ReferenceCount<T> value, Action onDisposeAction)
{
this.Value = value;
this.refCount = value;
this.onDisposeAction = onDisposeAction;
}

/// <summary>
/// Gets the value.
/// </summary>
public T Value { get; }
public T Value => this.refCount.Value;

/// <summary>
/// Gets the count of Lifetime instances referencing the same value.
/// </summary>
public int ReferenceCount => this.refCount.Count;

/// <summary>
/// Terminates the lifetime and performs any cleanup required to release the value.
Expand Down
2 changes: 1 addition & 1 deletion BitFaster.Caching/Scoped.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public Lifetime<T> CreateLifetime()
if (oldRefCount == Interlocked.CompareExchange(ref this.refCount, newRefCount, oldRefCount))
{
// When Lease is disposed, it calls DecrementReferenceCount
return new Lifetime<T>(oldRefCount.Value, this.DecrementReferenceCount);
return new Lifetime<T>(oldRefCount, this.DecrementReferenceCount);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion BitFaster.Caching/SingletonCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public Lifetime<TValue> Acquire(TKey key, Func<TKey, TValue> valueFactory)
(k) => new ReferenceCount<TValue>(valueFactory(k)),
(_, existingRefCount) => existingRefCount.IncrementCopy());

return new Lifetime<TValue>(refCount.Value, () => this.Release(key));
return new Lifetime<TValue>(refCount, () => this.Release(key));
}

private void Release(TKey key)
Expand Down