Skip to content

Commit 85b52ff

Browse files
authored
refactor lifetime (#33)
1 parent 81640ca commit 85b52ff

File tree

5 files changed

+61
-87
lines changed

5 files changed

+61
-87
lines changed

BitFaster.Caching.UnitTests/SingletonCacheTests.cs

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,41 +9,41 @@ namespace BitFaster.Caching.UnitTests
99
public class SingletonCacheTests
1010
{
1111
[Fact]
12-
public void AcquireWithSameKeyUsingCustomComparerReturnsSameHandle()
12+
public void AcquireWithSameKeyUsingCustomComparerReturnsSameLifetime()
1313
{
1414
var cache = new SingletonCache<string, object>(1, 3, StringComparer.OrdinalIgnoreCase);
1515

16-
var handle1 = cache.Acquire("foo");
17-
var handle2 = cache.Acquire("FOO");
18-
handle1.Value.Should().BeSameAs(handle2.Value);
19-
handle1.Dispose();
20-
handle2.Dispose();
16+
var lifetime1 = cache.Acquire("foo");
17+
var lifetime2 = cache.Acquire("FOO");
18+
lifetime1.Value.Should().BeSameAs(lifetime2.Value);
19+
lifetime1.Dispose();
20+
lifetime2.Dispose();
2121
}
2222

2323
[Fact]
24-
public void AcquireWithSameKeyReturnsSameHandle()
24+
public void AcquireWithSameKeyReturnsSameLifetime()
2525
{
2626
var cache = new SingletonCache<string, object>();
2727

28-
var handle1 = cache.Acquire("Foo");
29-
var handle2 = cache.Acquire("Foo");
30-
handle1.Value.Should().BeSameAs(handle2.Value);
31-
handle1.Dispose();
32-
handle2.Dispose();
28+
var lifetime1 = cache.Acquire("Foo");
29+
var lifetime2 = cache.Acquire("Foo");
30+
lifetime1.Value.Should().BeSameAs(lifetime2.Value);
31+
lifetime1.Dispose();
32+
lifetime2.Dispose();
3333
}
3434

3535
[Fact]
3636
public void AcquireReleaseAcquireReturnsDifferentValue()
3737
{
3838
var cache = new SingletonCache<string, object>();
3939

40-
var handle1 = cache.Acquire("Foo");
41-
handle1.Dispose();
40+
var lifetime1 = cache.Acquire("Foo");
41+
lifetime1.Dispose();
4242

43-
var handle2 = cache.Acquire("Foo");
44-
handle2.Dispose();
43+
var lifetime2 = cache.Acquire("Foo");
44+
lifetime2.Dispose();
4545

46-
handle1.Value.Should().NotBeSameAs(handle2.Value);
46+
lifetime1.Value.Should().NotBeSameAs(lifetime2.Value);
4747
}
4848

4949
[Fact]
@@ -54,34 +54,34 @@ public async Task AcquireWithSameKeyOnTwoDifferentThreadsReturnsSameValue()
5454
EventWaitHandle event1 = new EventWaitHandle(false, EventResetMode.AutoReset);
5555
EventWaitHandle event2 = new EventWaitHandle(false, EventResetMode.AutoReset);
5656

57-
SingletonCache<string, object>.Handle handle1 = null;
58-
SingletonCache<string, object>.Handle handle2 = null;
57+
Lifetime<object> lifetime1 = null;
58+
Lifetime<object> lifetime2 = null;
5959

6060
Task task1 = Task.Run(() =>
6161
{
6262
event1.WaitOne();
63-
handle1 = cache.Acquire("Foo");
63+
lifetime1 = cache.Acquire("Foo");
6464
event2.Set();
6565

6666
event1.WaitOne();
67-
handle1.Dispose();
67+
lifetime1.Dispose();
6868
event2.Set();
6969
});
7070

7171
Task task2 = Task.Run(() =>
7272
{
7373
event1.Set();
7474
event2.WaitOne();
75-
handle2 = cache.Acquire("Foo");
75+
lifetime2 = cache.Acquire("Foo");
7676

7777
event1.Set();
7878
event2.WaitOne();
79-
handle2.Dispose();
79+
lifetime2.Dispose();
8080
});
8181

8282
await Task.WhenAll(task1, task2);
8383

84-
handle1.Value.Should().BeSameAs(handle2.Value);
84+
lifetime1.Value.Should().BeSameAs(lifetime2.Value);
8585
}
8686

8787
[Fact]
@@ -99,9 +99,9 @@ public async Task AcquireWithSameKeyOnManyDifferentThreadsReturnsSameValue()
9999
{
100100
for (int i = 0; i < 100000; i++)
101101
{
102-
using (var handle = cache.Acquire("Foo"))
102+
using (var lifetime = cache.Acquire("Foo"))
103103
{
104-
lock (handle.Value)
104+
lock (lifetime.Value)
105105
{
106106
int result = Interlocked.Increment(ref count);
107107
result.Should().Be(1);
@@ -120,7 +120,7 @@ public void WhenValueIsDisposableItIsDisposedWhenReleased()
120120
{
121121
var cache = new SingletonCache<string, DisposeTest>();
122122

123-
using (var handle = cache.Acquire("Foo"))
123+
using (var lifetime = cache.Acquire("Foo"))
124124
{
125125
DisposeTest.WasDisposed.Should().BeFalse();
126126
}

BitFaster.Caching/Lifetime.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace BitFaster.Caching
6+
{
7+
public class Lifetime<T> : IDisposable
8+
{
9+
private readonly Action onDisposeAction;
10+
private bool isDisposed;
11+
12+
public Lifetime(T value, Action onDisposeAction)
13+
{
14+
this.Value = value;
15+
this.onDisposeAction = onDisposeAction;
16+
}
17+
18+
public T Value { get; }
19+
20+
public void Dispose()
21+
{
22+
if (!this.isDisposed)
23+
{
24+
this.onDisposeAction();
25+
this.isDisposed = true;
26+
}
27+
}
28+
}
29+
}

BitFaster.Caching/Scoped.cs

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public Scoped(T value)
2121
this.refCount = new ReferenceCount<T>(value);
2222
}
2323

24-
public Lifetime CreateLifetime()
24+
public Lifetime<T> CreateLifetime()
2525
{
2626
if (this.isDisposed)
2727
{
@@ -38,7 +38,7 @@ public Lifetime CreateLifetime()
3838
if (oldRefCount == Interlocked.CompareExchange(ref this.refCount, newRefCount, oldRefCount))
3939
{
4040
// When Lease is disposed, it calls DecrementReferenceCount
41-
return new Lifetime(oldRefCount.Value, this.DecrementReferenceCount);
41+
return new Lifetime<T>(oldRefCount.Value, this.DecrementReferenceCount);
4242
}
4343
}
4444
}
@@ -70,28 +70,5 @@ public void Dispose()
7070
this.isDisposed = true;
7171
}
7272
}
73-
74-
public class Lifetime : IDisposable
75-
{
76-
private readonly Action onDisposeAction;
77-
private bool isDisposed;
78-
79-
public Lifetime(T value, Action onDisposeAction)
80-
{
81-
this.Value = value;
82-
this.onDisposeAction = onDisposeAction;
83-
}
84-
85-
public T Value { get; }
86-
87-
public void Dispose()
88-
{
89-
if (!this.isDisposed)
90-
{
91-
this.onDisposeAction();
92-
this.isDisposed = true;
93-
}
94-
}
95-
}
9673
}
9774
}

BitFaster.Caching/SingletonCache.cs

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ public SingletonCache(int concurrencyLevel, int capacity, IEqualityComparer<TKey
2727
this.cache = new ConcurrentDictionary<TKey, ReferenceCount<TValue>>(concurrencyLevel, capacity, comparer);
2828
}
2929

30-
public Handle Acquire(TKey key, Func<TKey, TValue> valueFactory)
30+
public Lifetime<TValue> Acquire(TKey key, Func<TKey, TValue> valueFactory)
3131
{
3232
var refCount = this.cache.AddOrUpdate(key,
3333
(_) => new ReferenceCount<TValue>(valueFactory(_)),
3434
(_, existingRefCount) => existingRefCount.IncrementCopy());
3535

36-
return new Handle(key, refCount.Value, this);
36+
return new Lifetime<TValue>(refCount.Value, () => this.Release(key));
3737
}
3838

3939
private void Release(TKey key)
@@ -46,7 +46,6 @@ private void Release(TKey key)
4646
{
4747
if (newRefCount.Count == 0)
4848
{
49-
// This will remove from dictionary only if key and the value with ReferenceCount (== 0) matches (under a lock)
5049
if (((IDictionary<TKey, ReferenceCount<TValue>>)this.cache).Remove(new KeyValuePair<TKey, ReferenceCount<TValue>>(key, newRefCount)))
5150
{
5251
if (newRefCount.Value is IDisposable d)
@@ -59,36 +58,5 @@ private void Release(TKey key)
5958
}
6059
}
6160
}
62-
63-
public sealed class Handle : IDisposable
64-
{
65-
private TKey key;
66-
private TValue value;
67-
private SingletonCache<TKey, TValue> cache;
68-
69-
public Handle(TKey key, TValue value, SingletonCache<TKey, TValue> cache)
70-
{
71-
this.key = key;
72-
this.value = value;
73-
this.cache = cache;
74-
}
75-
76-
public TValue Value
77-
{
78-
get
79-
{
80-
return this.value;
81-
}
82-
}
83-
84-
public void Dispose()
85-
{
86-
if (this.cache != null)
87-
{
88-
this.cache.Release(this.key);
89-
this.cache = null;
90-
}
91-
}
92-
}
9361
}
9462
}

BitFaster.Caching/SingletonCacheExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace BitFaster.Caching
66
{
77
public static class SingletonCacheExtensions
88
{
9-
public static SingletonCache<TKey, TValue>.Handle Acquire<TKey, TValue>(this SingletonCache<TKey, TValue> cache, TKey key)
9+
public static Lifetime<TValue> Acquire<TKey, TValue>(this SingletonCache<TKey, TValue> cache, TKey key)
1010
where TValue : new()
1111
{
1212
return cache.Acquire(key, _ => new TValue());

0 commit comments

Comments
 (0)