From e8eff5b51c41786c87dd3daa92a8d7d243907769 Mon Sep 17 00:00:00 2001 From: alexpeck Date: Sat, 27 Jun 2020 16:34:49 -0700 Subject: [PATCH] basic docs --- .../Lru/ConcurrentTLruTests.cs | 2 +- .../Lru/FastConcurrentTLruTests.cs | 2 +- BitFaster.Caching/ICache.cs | 31 +++++++++++++++++++ BitFaster.Caching/Lifetime.cs | 16 ++++++++++ BitFaster.Caching/Lru/ClassicLru.cs | 4 +++ BitFaster.Caching/Lru/ConcurrentLru.cs | 16 ++++++++++ BitFaster.Caching/Lru/ConcurrentTLru.cs | 22 +++++++++++-- BitFaster.Caching/Lru/FastConcurrentLru.cs | 13 ++++++++ BitFaster.Caching/Lru/FastConcurrentTLru.cs | 19 ++++++++++-- .../Lru/TemplateConcurrentLru.cs | 4 +++ BitFaster.Caching/ReferenceCount.cs | 17 ++++++++++ BitFaster.Caching/Scoped.cs | 20 ++++++++++-- BitFaster.Caching/SingletonCache.cs | 21 ++++++++++++- BitFaster.Caching/SingletonCacheExtensions.cs | 6 ++++ 14 files changed, 183 insertions(+), 10 deletions(-) diff --git a/BitFaster.Caching.UnitTests/Lru/ConcurrentTLruTests.cs b/BitFaster.Caching.UnitTests/Lru/ConcurrentTLruTests.cs index 83c15409..9cc8f8ad 100644 --- a/BitFaster.Caching.UnitTests/Lru/ConcurrentTLruTests.cs +++ b/BitFaster.Caching.UnitTests/Lru/ConcurrentTLruTests.cs @@ -24,7 +24,7 @@ public ConcurrentTLruTests() [Fact] public void ConstructAddAndRetrieveWithDefaultCtorReturnsValue() { - var x = new ConcurrentTLru(3); + var x = new ConcurrentTLru(3, TimeSpan.FromSeconds(1)); x.GetOrAdd(1, k => k).Should().Be(1); } diff --git a/BitFaster.Caching.UnitTests/Lru/FastConcurrentTLruTests.cs b/BitFaster.Caching.UnitTests/Lru/FastConcurrentTLruTests.cs index 00e1fa24..b8063628 100644 --- a/BitFaster.Caching.UnitTests/Lru/FastConcurrentTLruTests.cs +++ b/BitFaster.Caching.UnitTests/Lru/FastConcurrentTLruTests.cs @@ -23,7 +23,7 @@ public void ConstructAddAndRetrieveWithCustomComparerReturnsValue() [Fact] public void ConstructAddAndRetrieveWithDefaultCtorReturnsValue() { - var x = new FastConcurrentTLru(3); + var x = new FastConcurrentTLru(3, TimeSpan.FromSeconds(1)); x.GetOrAdd(1, k => k).Should().Be(1); } diff --git a/BitFaster.Caching/ICache.cs b/BitFaster.Caching/ICache.cs index 41e7e8fe..d3e3d4c4 100644 --- a/BitFaster.Caching/ICache.cs +++ b/BitFaster.Caching/ICache.cs @@ -6,14 +6,45 @@ namespace BitFaster.Caching { + /// + /// Represents a generic cache of key/value pairs. + /// + /// The type of keys in the cache. + /// The type of values in the cache. public interface ICache { + /// + /// Attempts to get the value associated with the specified key from the cache. + /// + /// The key of the value to get. + /// When this method returns, contains the object from the cache that has the specified key, or the default value of the type if the operation failed. + /// true if the key was found in the cache; otherwise, false. bool TryGet(K key, out V value); + /// + /// Adds a key/value pair to the cache if the key does not already exist. Returns the new value, or the + /// existing value if the key already exists. + /// + /// The key of the element to add. + /// The factory function used to generate a value for the key. + /// The value for the key. This will be either the existing value for the key if the key is already + /// in the cache, or the new value if the key was not in the dictionary. V GetOrAdd(K key, Func valueFactory); + /// + /// Adds a key/value pair to the cache if the key does not already exist. Returns the new value, or the + /// existing value if the key already exists. + /// + /// The key of the element to add. + /// The factory function used to asynchronously generate a value for the key. + /// A task that represents the asynchronous GetOrAdd operation. Task GetOrAddAsync(K key, Func> valueFactory); + /// + /// Attempts to remove and return the value that has the specified key from the cache. + /// + /// The key of the element to remove. + /// true if the object was removed successfully; otherwise, false. bool TryRemove(K key); } } diff --git a/BitFaster.Caching/Lifetime.cs b/BitFaster.Caching/Lifetime.cs index 93e10058..f7de345e 100644 --- a/BitFaster.Caching/Lifetime.cs +++ b/BitFaster.Caching/Lifetime.cs @@ -4,19 +4,35 @@ namespace BitFaster.Caching { + /// + /// Represents the lifetime of a value. The value is alive and valid for use until the + /// lifetime is disposed. + /// + /// The type of value public class Lifetime : IDisposable { private readonly Action onDisposeAction; private bool isDisposed; + /// + /// Initializes a new instance of the Lifetime class. + /// + /// The value to keep alive. + /// The action to perform when the lifetime is terminated. public Lifetime(T value, Action onDisposeAction) { this.Value = value; this.onDisposeAction = onDisposeAction; } + /// + /// Gets the value. + /// public T Value { get; } + /// + /// Terminates the lifetime and performs any cleanup required to release the value. + /// public void Dispose() { if (!this.isDisposed) diff --git a/BitFaster.Caching/Lru/ClassicLru.cs b/BitFaster.Caching/Lru/ClassicLru.cs index 5178858c..93689ecd 100644 --- a/BitFaster.Caching/Lru/ClassicLru.cs +++ b/BitFaster.Caching/Lru/ClassicLru.cs @@ -51,6 +51,7 @@ public ClassicLru(int concurrencyLevel, int capacity, IEqualityComparer compa public double HitRatio => (double)requestHitCount / (double)requestTotalCount; + /// public bool TryGet(K key, out V value) { Interlocked.Increment(ref requestTotalCount); @@ -68,6 +69,7 @@ public bool TryGet(K key, out V value) return false; } + /// public V GetOrAdd(K key, Func valueFactory) { if (this.TryGet(key, out var value)) @@ -114,6 +116,7 @@ public V GetOrAdd(K key, Func valueFactory) return this.GetOrAdd(key, valueFactory); } + /// public async Task GetOrAddAsync(K key, Func> valueFactory) { if (this.TryGet(key, out var value)) @@ -160,6 +163,7 @@ public async Task GetOrAddAsync(K key, Func> valueFactory) return await this.GetOrAddAsync(key, valueFactory); } + /// public bool TryRemove(K key) { if (dictionary.TryRemove(key, out var node)) diff --git a/BitFaster.Caching/Lru/ConcurrentLru.cs b/BitFaster.Caching/Lru/ConcurrentLru.cs index aac3023a..de133902 100644 --- a/BitFaster.Caching/Lru/ConcurrentLru.cs +++ b/BitFaster.Caching/Lru/ConcurrentLru.cs @@ -6,18 +6,34 @@ namespace BitFaster.Caching.Lru { + /// public sealed class ConcurrentLru : TemplateConcurrentLru, LruPolicy, HitCounter> { + /// + /// Initializes a new instance of the ConcurrentLru class with the specified capacity that has the default + /// concurrency level, and uses the default comparer for the key type. + /// + /// The maximum number of elements that the ConcurrentLru can contain. public ConcurrentLru(int capacity) : base(Defaults.ConcurrencyLevel, capacity, EqualityComparer.Default, new LruPolicy(), new HitCounter()) { } + /// + /// Initializes a new instance of the ConcurrentLru class that has the specified concurrency level, has the + /// specified initial capacity, and uses the specified IEqualityComparer. + /// + /// The estimated number of threads that will update the ConcurrentLru concurrently. + /// The maximum number of elements that the ConcurrentLru can contain. + /// The IEqualityComparer implementation to use when comparing keys. public ConcurrentLru(int concurrencyLevel, int capacity, IEqualityComparer comparer) : base(concurrencyLevel, capacity, comparer, new LruPolicy(), new HitCounter()) { } + /// + /// Gets the ratio of hits to misses, where a value of 1 indicates 100% hits. + /// public double HitRatio => this.hitCounter.HitRatio; } } diff --git a/BitFaster.Caching/Lru/ConcurrentTLru.cs b/BitFaster.Caching/Lru/ConcurrentTLru.cs index d96b3a65..72fed08c 100644 --- a/BitFaster.Caching/Lru/ConcurrentTLru.cs +++ b/BitFaster.Caching/Lru/ConcurrentTLru.cs @@ -6,18 +6,36 @@ namespace BitFaster.Caching.Lru { + /// public sealed class ConcurrentTLru : TemplateConcurrentLru, TLruLongTicksPolicy, HitCounter> { - public ConcurrentTLru(int capacity) - : base(Defaults.ConcurrencyLevel, capacity, EqualityComparer.Default, new TLruLongTicksPolicy(), new HitCounter()) + /// + /// Initializes a new instance of the ConcurrentTLru class with the specified capacity and time to live that has the default + /// concurrency level, and uses the default comparer for the key type. + /// + /// The maximum number of elements that the ConcurrentTLru can contain. + /// The time to live for cached values. + public ConcurrentTLru(int capacity, TimeSpan timeToLive) + : base(Defaults.ConcurrencyLevel, capacity, EqualityComparer.Default, new TLruLongTicksPolicy(timeToLive), new HitCounter()) { } + /// + /// Initializes a new instance of the ConcurrentTLru class that has the specified concurrency level, has the + /// specified initial capacity, uses the specified IEqualityComparer, and has the specified time to live. + /// + /// The estimated number of threads that will update the ConcurrentTLru concurrently. + /// The maximum number of elements that the ConcurrentTLru can contain. + /// The IEqualityComparer implementation to use when comparing keys. + /// The time to live for cached values. public ConcurrentTLru(int concurrencyLevel, int capacity, IEqualityComparer comparer, TimeSpan timeToLive) : base(concurrencyLevel, capacity, comparer, new TLruLongTicksPolicy(timeToLive), new HitCounter()) { } + /// + /// Gets the ratio of hits to misses, where a value of 1 indicates 100% hits. + /// public double HitRatio => this.hitCounter.HitRatio; } } diff --git a/BitFaster.Caching/Lru/FastConcurrentLru.cs b/BitFaster.Caching/Lru/FastConcurrentLru.cs index e69b4db5..10db549d 100644 --- a/BitFaster.Caching/Lru/FastConcurrentLru.cs +++ b/BitFaster.Caching/Lru/FastConcurrentLru.cs @@ -4,13 +4,26 @@ namespace BitFaster.Caching.Lru { + /// public sealed class FastConcurrentLru : TemplateConcurrentLru, LruPolicy, NullHitCounter> { + /// + /// Initializes a new instance of the FastConcurrentLru class with the specified capacity that has the default + /// concurrency level, and uses the default comparer for the key type. + /// + /// The maximum number of elements that the FastConcurrentLru can contain. public FastConcurrentLru(int capacity) : base(Defaults.ConcurrencyLevel, capacity, EqualityComparer.Default, new LruPolicy(), new NullHitCounter()) { } + /// + /// Initializes a new instance of the FastConcurrentLru class that has the specified concurrency level, has the + /// specified initial capacity, and uses the specified IEqualityComparer. + /// + /// The estimated number of threads that will update the FastConcurrentLru concurrently. + /// The maximum number of elements that the FastConcurrentLru can contain. + /// The IEqualityComparer implementation to use when comparing keys. public FastConcurrentLru(int concurrencyLevel, int capacity, IEqualityComparer comparer) : base(concurrencyLevel, capacity, comparer, new LruPolicy(), new NullHitCounter()) { diff --git a/BitFaster.Caching/Lru/FastConcurrentTLru.cs b/BitFaster.Caching/Lru/FastConcurrentTLru.cs index c6544ec4..75e0545d 100644 --- a/BitFaster.Caching/Lru/FastConcurrentTLru.cs +++ b/BitFaster.Caching/Lru/FastConcurrentTLru.cs @@ -4,13 +4,28 @@ namespace BitFaster.Caching.Lru { + /// public sealed class FastConcurrentTLru : TemplateConcurrentLru, TLruLongTicksPolicy, NullHitCounter> { - public FastConcurrentTLru(int capacity) - : base(Defaults.ConcurrencyLevel, capacity, EqualityComparer.Default, new TLruLongTicksPolicy(), new NullHitCounter()) + /// + /// Initializes a new instance of the FastConcurrentTLru class with the specified capacity and time to live that has the default + /// concurrency level, and uses the default comparer for the key type. + /// + /// The maximum number of elements that the FastConcurrentTLru can contain. + /// The time to live for cached values. + public FastConcurrentTLru(int capacity, TimeSpan timeToLive) + : base(Defaults.ConcurrencyLevel, capacity, EqualityComparer.Default, new TLruLongTicksPolicy(timeToLive), new NullHitCounter()) { } + /// + /// Initializes a new instance of the FastConcurrentTLru class that has the specified concurrency level, has the + /// specified initial capacity, uses the specified IEqualityComparer, and has the specified time to live. + /// + /// The estimated number of threads that will update the FastConcurrentTLru concurrently. + /// The maximum number of elements that the FastConcurrentTLru can contain. + /// The IEqualityComparer implementation to use when comparing keys. + /// The time to live for cached values. public FastConcurrentTLru(int concurrencyLevel, int capacity, IEqualityComparer comparer, TimeSpan timeToLive) : base(concurrencyLevel, capacity, comparer, new TLruLongTicksPolicy(timeToLive), new NullHitCounter()) { diff --git a/BitFaster.Caching/Lru/TemplateConcurrentLru.cs b/BitFaster.Caching/Lru/TemplateConcurrentLru.cs index 1aadbebb..a4ced1c8 100644 --- a/BitFaster.Caching/Lru/TemplateConcurrentLru.cs +++ b/BitFaster.Caching/Lru/TemplateConcurrentLru.cs @@ -92,6 +92,7 @@ public TemplateConcurrentLru( public int ColdCount => this.coldCount; + /// public bool TryGet(K key, out V value) { I item; @@ -115,6 +116,7 @@ public bool TryGet(K key, out V value) return false; } + /// public V GetOrAdd(K key, Func valueFactory) { if (this.TryGet(key, out var value)) @@ -137,6 +139,7 @@ public V GetOrAdd(K key, Func valueFactory) return this.GetOrAdd(key, valueFactory); } + /// public async Task GetOrAddAsync(K key, Func> valueFactory) { if (this.TryGet(key, out var value)) @@ -159,6 +162,7 @@ public async Task GetOrAddAsync(K key, Func> valueFactory) return await this.GetOrAddAsync(key, valueFactory).ConfigureAwait(false); } + /// public bool TryRemove(K key) { // Possible race condition: diff --git a/BitFaster.Caching/ReferenceCount.cs b/BitFaster.Caching/ReferenceCount.cs index 316e692f..e9f4d957 100644 --- a/BitFaster.Caching/ReferenceCount.cs +++ b/BitFaster.Caching/ReferenceCount.cs @@ -25,6 +25,9 @@ private ReferenceCount(TValue value, int referenceCount) this.count = referenceCount; } + /// + /// Gets the value. + /// public TValue Value { get @@ -33,6 +36,9 @@ public TValue Value } } + /// + /// Gets the count. + /// public int Count { get @@ -41,6 +47,10 @@ public int Count } } + /// + /// Create a copy of the ReferenceCount with the count incremented by 1. + /// + /// A copy of the ReferenceCount with the count incremented by 1. public ReferenceCount IncrementCopy() { if (this.count <= 0 && this.value is IDisposable) @@ -51,16 +61,22 @@ public ReferenceCount IncrementCopy() return new ReferenceCount(this.value, this.count + 1); } + /// + /// Create a copy of the ReferenceCount with the count decremented by 1. + /// + /// A copy of the ReferenceCount with the count decremented by 1. public ReferenceCount DecrementCopy() { return new ReferenceCount(this.value, this.count - 1); } + /// public override bool Equals(object obj) { return Equals(obj as ReferenceCount); } + /// public bool Equals(ReferenceCount other) { return other != null && @@ -68,6 +84,7 @@ public bool Equals(ReferenceCount other) count == other.count; } + /// public override int GetHashCode() { var hashCode = -1491496004; diff --git a/BitFaster.Caching/Scoped.cs b/BitFaster.Caching/Scoped.cs index ad552780..c6535303 100644 --- a/BitFaster.Caching/Scoped.cs +++ b/BitFaster.Caching/Scoped.cs @@ -6,9 +6,9 @@ namespace BitFaster.Caching { /// - /// A wrapper for IDisposable objects stored in a cache. If the object is used in a long - /// running operation and disposed by the cache, the scope can create a lifetime that - /// prevents the wrapped object from being diposed until the calling code completes. + /// A lifetime scope for IDisposable objects stored in a cache. If the object is used in a long + /// running operation and disposed by a cache, the scope can create a lifetime that prevents + /// the wrapped object from being diposed until the calling code completes. /// /// The type of scoped value. public class Scoped : IDisposable where T : IDisposable @@ -16,11 +16,21 @@ public class Scoped : IDisposable where T : IDisposable private ReferenceCount refCount; private bool isDisposed; + /// + /// Initializes a new Scoped value. + /// + /// The value to scope. public Scoped(T value) { this.refCount = new ReferenceCount(value); } + /// + /// Creates a lifetime for the scoped value. The lifetime guarantees the value is alive until + /// the lifetime is disposed. + /// + /// A value lifetime. + /// The scope is disposed. public Lifetime CreateLifetime() { if (this.isDisposed) @@ -62,6 +72,10 @@ private void DecrementReferenceCount() } } + /// + /// Terminates the scope and disposes the value. Once the scope is terminated, it is no longer + /// possible to create new lifetimes for the value. + /// public void Dispose() { if (!this.isDisposed) diff --git a/BitFaster.Caching/SingletonCache.cs b/BitFaster.Caching/SingletonCache.cs index a275d1a5..c3750b57 100644 --- a/BitFaster.Caching/SingletonCache.cs +++ b/BitFaster.Caching/SingletonCache.cs @@ -11,26 +11,45 @@ namespace BitFaster.Caching /// Cache a single value for each key, and maintain in memory only the values that have been acquired /// but not yet released. /// + /// Based on LockObjectCache by Mayank Mehta. /// The type of the key. /// The type of the value. public class SingletonCache { private readonly ConcurrentDictionary> cache; + /// + /// Initializes a new instance of the SingletonCache class that is empty, has the default concurrency level, + /// has the default initial capacity, and uses the default comparer for the key type. + /// public SingletonCache() { this.cache = new ConcurrentDictionary>(); } + /// + /// Initializes a new instance of the SingletonCache that has the specified concurrency level, has the + /// specified initial capacity, and uses the specified IEqualityComparer. + /// + /// The estimated number of threads that will update the SingletonCache concurrently. + /// The initial number of elements that the SingletonCache can contain. + /// The IEqualityComparer implementation to use when comparing keys. public SingletonCache(int concurrencyLevel, int capacity, IEqualityComparer comparer) { this.cache = new ConcurrentDictionary>(concurrencyLevel, capacity, comparer); } + /// + /// Acquire a singleton value for the specified key. The lifetime guarantees the value is alive and is a singleton + /// for the given key until the lifetime is disposed. + /// + /// The key of the item + /// The value factory + /// A value lifetime public Lifetime Acquire(TKey key, Func valueFactory) { var refCount = this.cache.AddOrUpdate(key, - (_) => new ReferenceCount(valueFactory(_)), + (k) => new ReferenceCount(valueFactory(k)), (_, existingRefCount) => existingRefCount.IncrementCopy()); return new Lifetime(refCount.Value, () => this.Release(key)); diff --git a/BitFaster.Caching/SingletonCacheExtensions.cs b/BitFaster.Caching/SingletonCacheExtensions.cs index 81124e85..4dc8b2d1 100644 --- a/BitFaster.Caching/SingletonCacheExtensions.cs +++ b/BitFaster.Caching/SingletonCacheExtensions.cs @@ -6,6 +6,12 @@ namespace BitFaster.Caching { public static class SingletonCacheExtensions { + /// + /// Acquire a singleton value for the specified key. The lifetime guarantees the value is alive and is a singleton + /// for the given key until the lifetime is disposed. + /// + /// The key of the item + /// A value lifetime public static Lifetime Acquire(this SingletonCache cache, TKey key) where TValue : new() {