diff --git a/BitFaster.Caching/Atomic/AsyncAtomicFactory.cs b/BitFaster.Caching/Atomic/AsyncAtomicFactory.cs index 9e12800c..bc00ecab 100644 --- a/BitFaster.Caching/Atomic/AsyncAtomicFactory.cs +++ b/BitFaster.Caching/Atomic/AsyncAtomicFactory.cs @@ -1,13 +1,16 @@ using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; namespace BitFaster.Caching.Atomic { + /// + /// A class that provides simple, lightweight exactly once initialization for values + /// stored in a cache. + /// + /// The type of the key. + /// The type of the value. [DebuggerDisplay("IsValueCreated={IsValueCreated}, Value={ValueIfCreated}")] public sealed class AsyncAtomicFactory { @@ -16,16 +19,30 @@ public sealed class AsyncAtomicFactory [DebuggerBrowsable(DebuggerBrowsableState.Never)] private V value; + /// + /// Initializes a new instance of the class. + /// public AsyncAtomicFactory() { initializer = new Initializer(); } + /// + /// Initializes a new instance of the class with the + /// specified value. + /// + /// The value. public AsyncAtomicFactory(V value) { this.value = value; } + /// + /// Gets the value. If is false, calling will force initialization via the parameter. + /// + /// The key associated with the value. + /// The value factory to use to create the value when it is not initialized. + /// The value. public async ValueTask GetValueAsync(K key, Func> valueFactory) { if (initializer == null) @@ -36,8 +53,14 @@ public async ValueTask GetValueAsync(K key, Func> valueFactory) return await CreateValueAsync(key, valueFactory).ConfigureAwait(false); } + /// + /// Gets a value indicating whether the value has been initialized. + /// public bool IsValueCreated => initializer == null; + /// + /// Gets the value if it has been initialized, else default. + /// public V ValueIfCreated { get @@ -66,7 +89,7 @@ private async ValueTask CreateValueAsync(K key, Func> valueFactory private class Initializer { - private object syncLock = new object(); + private readonly object syncLock = new object(); private bool isInitialized; private Task valueTask; diff --git a/BitFaster.Caching/Atomic/AtomicFactory.cs b/BitFaster.Caching/Atomic/AtomicFactory.cs index e153cd00..fb390d54 100644 --- a/BitFaster.Caching/Atomic/AtomicFactory.cs +++ b/BitFaster.Caching/Atomic/AtomicFactory.cs @@ -1,13 +1,15 @@ using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Text; using System.Threading; -using System.Threading.Tasks; namespace BitFaster.Caching.Atomic { + /// + /// A class that provides simple, lightweight exactly once initialization for values + /// stored in a cache. + /// + /// The type of the key. + /// The type of the value. [DebuggerDisplay("IsValueCreated={IsValueCreated}, Value={ValueIfCreated}")] public sealed class AtomicFactory { @@ -16,16 +18,30 @@ public sealed class AtomicFactory [DebuggerBrowsable(DebuggerBrowsableState.Never)] private V value; + /// + /// Initializes a new instance of the class. + /// public AtomicFactory() { initializer = new Initializer(); } + /// + /// Initializes a new instance of the class with the + /// specified value. + /// + /// The value. public AtomicFactory(V value) { this.value = value; } + /// + /// Gets the value. If is false, calling will force initialization via the parameter. + /// + /// The key associated with the value. + /// The value factory to use to create the value when it is not initialized. + /// The value. public V GetValue(K key, Func valueFactory) { if (initializer == null) @@ -36,8 +52,14 @@ public V GetValue(K key, Func valueFactory) return CreateValue(key, valueFactory); } + /// + /// Gets a value indicating whether the value has been initialized. + /// public bool IsValueCreated => initializer == null; + /// + /// Gets the value if it has been initialized, else default. + /// public V ValueIfCreated { get @@ -66,7 +88,7 @@ private V CreateValue(K key, Func valueFactory) private class Initializer { - private object syncLock = new object(); + private readonly object syncLock = new object(); private bool isInitialized; private V value; diff --git a/BitFaster.Caching/Atomic/AtomicFactoryAsyncCache.cs b/BitFaster.Caching/Atomic/AtomicFactoryAsyncCache.cs index b1686c4e..934c9cdd 100644 --- a/BitFaster.Caching/Atomic/AtomicFactoryAsyncCache.cs +++ b/BitFaster.Caching/Atomic/AtomicFactoryAsyncCache.cs @@ -6,6 +6,11 @@ namespace BitFaster.Caching.Atomic { + /// + /// A cache decorator for working with wrapped values, giving exactly once initialization. + /// + /// The type of keys in the cache. + /// The type of values in the cache. [DebuggerDisplay("Count = {Count}")] public sealed class AtomicFactoryAsyncCache : IAsyncCache { diff --git a/BitFaster.Caching/Atomic/AtomicFactoryCache.cs b/BitFaster.Caching/Atomic/AtomicFactoryCache.cs index 9fb08fd0..86f55d4f 100644 --- a/BitFaster.Caching/Atomic/AtomicFactoryCache.cs +++ b/BitFaster.Caching/Atomic/AtomicFactoryCache.cs @@ -5,12 +5,21 @@ namespace BitFaster.Caching.Atomic { + /// + /// A cache decorator for working with wrapped values, giving exactly once initialization. + /// + /// The type of keys in the cache. + /// The type of values in the cache. [DebuggerDisplay("Count = {Count}")] public sealed class AtomicFactoryCache : ICache { private readonly ICache> cache; private readonly Optional> events; + /// + /// Initializes a new instance of the ScopedCache class with the specified inner cache. + /// + /// The decorated cache. public AtomicFactoryCache(ICache> cache) { if (cache == null) diff --git a/BitFaster.Caching/Atomic/AtomicFactoryScopedAsyncCache.cs b/BitFaster.Caching/Atomic/AtomicFactoryScopedAsyncCache.cs index c22a7b31..ffb8cb9d 100644 --- a/BitFaster.Caching/Atomic/AtomicFactoryScopedAsyncCache.cs +++ b/BitFaster.Caching/Atomic/AtomicFactoryScopedAsyncCache.cs @@ -7,6 +7,11 @@ namespace BitFaster.Caching.Atomic { + /// + /// A cache decorator for working with wrapped values, giving exactly once initialization. + /// + /// The type of keys in the cache. + /// The type of values in the cache. [DebuggerDisplay("Count = {Count}")] public sealed class AtomicFactoryScopedAsyncCache : IScopedAsyncCache where V : IDisposable { diff --git a/BitFaster.Caching/Atomic/AtomicFactoryScopedCache.cs b/BitFaster.Caching/Atomic/AtomicFactoryScopedCache.cs index 42a78adc..ce4c7c8d 100644 --- a/BitFaster.Caching/Atomic/AtomicFactoryScopedCache.cs +++ b/BitFaster.Caching/Atomic/AtomicFactoryScopedCache.cs @@ -6,6 +6,11 @@ namespace BitFaster.Caching.Atomic { + /// + /// A cache decorator for working with wrapped values, giving exactly once initialization. + /// + /// The type of keys in the cache. + /// The type of values in the cache. [DebuggerDisplay("Count = {Count}")] public sealed class AtomicFactoryScopedCache : IScopedCache where V : IDisposable { diff --git a/BitFaster.Caching/Atomic/ScopedAsyncAtomicFactory.cs b/BitFaster.Caching/Atomic/ScopedAsyncAtomicFactory.cs index 86809900..c06da3cd 100644 --- a/BitFaster.Caching/Atomic/ScopedAsyncAtomicFactory.cs +++ b/BitFaster.Caching/Atomic/ScopedAsyncAtomicFactory.cs @@ -5,22 +5,39 @@ namespace BitFaster.Caching.Atomic { + /// + /// A class that provides simple, lightweight exactly once initialization for scoped values + /// stored in a cache. + /// + /// The type of the key. + /// The type of the value. [DebuggerDisplay("IsValueCreated={initializer == null}, Value={ScopeIfCreated}")] public sealed class ScopedAsyncAtomicFactory : IScoped, IDisposable where V : IDisposable { private Scoped scope; private Initializer initializer; + /// + /// Initializes a new instance of the class. + /// public ScopedAsyncAtomicFactory() { initializer = new Initializer(); } + /// + /// Initializes a new instance of the class with the + /// specified value. + /// + /// The value. public ScopedAsyncAtomicFactory(V value) { scope = new Scoped(value); } + /// + /// Gets the scope if it has been initialized, else default. + /// public Scoped ScopeIfCreated { get @@ -34,6 +51,12 @@ public Scoped ScopeIfCreated } } + /// + /// Attempts to create a lifetime for the scoped value. The lifetime guarantees the value is alive until + /// the lifetime is disposed. + /// + /// When this method returns, contains the Lifetime that was created, or the default value of the type if the operation failed. + /// true if the Lifetime was created; otherwise false. public bool TryCreateLifetime(out Lifetime lifetime) { if (scope?.IsDisposed ?? false || initializer != null) @@ -45,6 +68,13 @@ public bool TryCreateLifetime(out Lifetime lifetime) return scope.TryCreateLifetime(out lifetime); } + /// + /// Attempts to create a lifetime for the scoped value. The lifetime guarantees the value is alive until + /// the lifetime is disposed. + /// + /// The key associated with the scoped value. + /// The value factory to use to create the scoped value when it is not initialized. + /// true if the Lifetime was created; otherwise false. If the lifetime was created, the new lifetime is also returned. public async ValueTask<(bool success, Lifetime lifetime)> TryCreateLifetimeAsync(K key, Func>> valueFactory) { // if disposed, return @@ -73,6 +103,11 @@ private async ValueTask InitializeScopeAsync(K key, Func>> val initializer = null; } } + + /// + /// 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() { var init = initializer; @@ -90,7 +125,7 @@ public void Dispose() private class Initializer { - private object syncLock = new object(); + private readonly object syncLock = new object(); private bool isTaskInitialized; private bool isTaskCompleted; private bool isDisposeRequested; diff --git a/BitFaster.Caching/Atomic/ScopedAtomicFactory.cs b/BitFaster.Caching/Atomic/ScopedAtomicFactory.cs index 32a6f46c..ee534ef0 100644 --- a/BitFaster.Caching/Atomic/ScopedAtomicFactory.cs +++ b/BitFaster.Caching/Atomic/ScopedAtomicFactory.cs @@ -4,26 +4,55 @@ namespace BitFaster.Caching.Atomic { - // Requirements: - // 1. Exactly once disposal. - // 2. Exactly once invocation of value factory (synchronized create). - // 3. Resolve race between create dispose init, if disposed is called before value is created, scoped value is disposed for life. + /// + /// A class that provides simple, lightweight exactly once initialization for scoped values + /// stored in a cache. + /// + /// The type of the key. + /// The type of the value. + /// + /// Requirements: + /// + /// + /// Exactly once disposal. + /// + /// + /// Exactly once invocation of value factory + /// Values are created atomically. + /// + /// + /// Resolve race between create dispose init + /// If disposed is called before value is created, scoped value is disposed for life. + /// + /// + /// [DebuggerDisplay("IsValueCreated={initializer == null}, Value={ScopeIfCreated}")] public sealed class ScopedAtomicFactory : IScoped, IDisposable where V : IDisposable { private Scoped scope; private Initializer initializer; + /// + /// Initializes a new instance of the class. + /// public ScopedAtomicFactory() { initializer = new Initializer(); } + /// + /// Initializes a new instance of the class with the + /// specified value. + /// + /// The value. public ScopedAtomicFactory(V value) { scope = new Scoped(value); } + /// + /// Gets the scope if it has been initialized, else default. + /// public Scoped ScopeIfCreated { get @@ -37,6 +66,12 @@ public Scoped ScopeIfCreated } } + /// + /// Attempts to create a lifetime for the scoped value. The lifetime guarantees the value is alive until + /// the lifetime is disposed. + /// + /// When this method returns, contains the Lifetime that was created, or the default value of the type if the operation failed. + /// true if the Lifetime was created; otherwise false. public bool TryCreateLifetime(out Lifetime lifetime) { if (scope?.IsDisposed ?? false || initializer != null) @@ -48,6 +83,14 @@ public bool TryCreateLifetime(out Lifetime lifetime) return scope.TryCreateLifetime(out lifetime); } + /// + /// Attempts to create a lifetime for the scoped value. The lifetime guarantees the value is alive until + /// the lifetime is disposed. + /// + /// The key associated with the scoped value. + /// The value factory to use to create the scoped value when it is not initialized. + /// When this method returns, contains the Lifetime that was created, or the default value of the type if the operation failed. + /// true if the Lifetime was created; otherwise false. public bool TryCreateLifetime(K key, Func> valueFactory, out Lifetime lifetime) { if(scope?.IsDisposed ?? false) @@ -75,6 +118,11 @@ private void InitializeScope(K key, Func> valueFactory) initializer = null; } } + + /// + /// 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() { var init = initializer; @@ -89,7 +137,7 @@ public void Dispose() private class Initializer { - private object syncLock = new object(); + private readonly object syncLock = new object(); private bool isInitialized; private Scoped value; diff --git a/BitFaster.Caching/Concurrent/PaddedLong.cs b/BitFaster.Caching/Concurrent/PaddedLong.cs index fe312b01..b32a5fdc 100644 --- a/BitFaster.Caching/Concurrent/PaddedLong.cs +++ b/BitFaster.Caching/Concurrent/PaddedLong.cs @@ -3,16 +3,33 @@ namespace BitFaster.Caching.Concurrent { + /// + /// A long value padded by the size of a CPU cache line to mitigate false sharing. + /// [StructLayout(LayoutKind.Explicit, Size = 2 * Padding.CACHE_LINE_SIZE)] // padding before/between/after fields public struct PaddedLong { + /// + /// The value. + /// [FieldOffset(Padding.CACHE_LINE_SIZE)] public long value; + /// + /// Reads the value of the field, and on systems that require it inserts a memory barrier to + /// prevent reordering of memory operations. + /// + /// The value that was read. public long VolatileRead() { return Volatile.Read(ref this.value); } + /// + /// Compares the current value with an expected value, if they are equal replaces the current value. + /// + /// The expected value. + /// The updated value. + /// True if the value is updated, otherwise false. public bool CompareAndSwap(long expected, long updated) { return Interlocked.CompareExchange(ref this.value, updated, expected) == expected; diff --git a/BitFaster.Caching/Concurrent/Striped64.cs b/BitFaster.Caching/Concurrent/Striped64.cs index a0403a85..f2e827fa 100644 --- a/BitFaster.Caching/Concurrent/Striped64.cs +++ b/BitFaster.Caching/Concurrent/Striped64.cs @@ -182,7 +182,6 @@ protected void LongAccumulate(long x, bool wasUncontended) var r = new Cell(x); // Optimistically create if (this.cellsBusy == 0 && CasCellsBusy()) { - var created = false; try { // Recheck under lock Cell[] rs; int m, j; @@ -191,15 +190,14 @@ protected void LongAccumulate(long x, bool wasUncontended) rs[j = (m - 1) & h] == null) { rs[j] = r; - created = true; + break; } } finally { VolatileWriteNotBusy(); } - if (created) - break; + continue; // Slot is now non-empty } } @@ -236,7 +234,6 @@ protected void LongAccumulate(long x, bool wasUncontended) } else if (this.cellsBusy == 0 && this.Cells == @as && CasCellsBusy()) { - var init = false; try { // Initialize table if (this.Cells == @as) @@ -244,15 +241,13 @@ protected void LongAccumulate(long x, bool wasUncontended) var rs = new Cell[2]; rs[h & 1] = new Cell(x); this.Cells = rs; - init = true; + break; } } finally { VolatileWriteNotBusy(); } - if (init) - break; } // Fall back on using base else if (this.@base.CompareAndSwap(v = this.@base.VolatileRead(), v + x)) diff --git a/BitFaster.Caching/Lfu/Builder/AsyncConcurrentLfuBuilder.cs b/BitFaster.Caching/Lfu/Builder/AsyncConcurrentLfuBuilder.cs index fe6a99aa..7560229e 100644 --- a/BitFaster.Caching/Lfu/Builder/AsyncConcurrentLfuBuilder.cs +++ b/BitFaster.Caching/Lfu/Builder/AsyncConcurrentLfuBuilder.cs @@ -1,9 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Text; - + namespace BitFaster.Caching.Lfu.Builder { + /// + /// A builder for creating a ConcurrentLfu as IAsyncCache. + /// + /// The type of the cache key. + /// The type of the cache value. + /// The type of the wrapped cache value. public sealed class AsyncConcurrentLfuBuilder : LfuBuilderBase, IAsyncCache> { internal AsyncConcurrentLfuBuilder(LfuInfo info) diff --git a/BitFaster.Caching/Lfu/Builder/AtomicAsyncConcurrentLfuBuilder.cs b/BitFaster.Caching/Lfu/Builder/AtomicAsyncConcurrentLfuBuilder.cs index d00f3215..0d8b4cba 100644 --- a/BitFaster.Caching/Lfu/Builder/AtomicAsyncConcurrentLfuBuilder.cs +++ b/BitFaster.Caching/Lfu/Builder/AtomicAsyncConcurrentLfuBuilder.cs @@ -1,10 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Text; + using BitFaster.Caching.Atomic; namespace BitFaster.Caching.Lfu.Builder { + /// + /// A builder for creating a ConcurrentLfu as IAsyncCache with atomic value creation. + /// + /// The type of the cache key. + /// The type of the cache value. public class AtomicAsyncConcurrentLfuBuilder : LfuBuilderBase, IAsyncCache> { private readonly ConcurrentLfuBuilder> inner; diff --git a/BitFaster.Caching/Lfu/Builder/AtomicScopedConcurrentLfuBuilder.cs b/BitFaster.Caching/Lfu/Builder/AtomicScopedConcurrentLfuBuilder.cs index eb0dcc97..51dd1acb 100644 --- a/BitFaster.Caching/Lfu/Builder/AtomicScopedConcurrentLfuBuilder.cs +++ b/BitFaster.Caching/Lfu/Builder/AtomicScopedConcurrentLfuBuilder.cs @@ -5,6 +5,11 @@ namespace BitFaster.Caching.Lfu.Builder { + /// + /// A builder for creating a ConcurrentLfu with scoped values. + /// + /// The type of the cache key. + /// The type of the cache value. public class AtomicScopedConcurrentLfuBuilder : LfuBuilderBase, IScopedCache> where V : IDisposable { private readonly ConcurrentLfuBuilder> inner; diff --git a/BitFaster.Caching/Lfu/Builder/ScopedConcurrentLfuBuilder.cs b/BitFaster.Caching/Lfu/Builder/ScopedConcurrentLfuBuilder.cs index 31a3730a..afc6107c 100644 --- a/BitFaster.Caching/Lfu/Builder/ScopedConcurrentLfuBuilder.cs +++ b/BitFaster.Caching/Lfu/Builder/ScopedConcurrentLfuBuilder.cs @@ -1,9 +1,13 @@ using System; -using System.Collections.Generic; -using System.Text; namespace BitFaster.Caching.Lfu.Builder { + /// + /// A builder for creating a ConcurrentLfu with scoped values. + /// + /// The type of the cache key. + /// The type of the cache value. + /// The type of the wrapped cache value. public sealed class ScopedConcurrentLfuBuilder : LfuBuilderBase, IScopedCache> where V : IDisposable where W : IScoped { private readonly ConcurrentLfuBuilder inner; diff --git a/BitFaster.Caching/Lru/Builder/AsyncConcurrentLruBuilder.cs b/BitFaster.Caching/Lru/Builder/AsyncConcurrentLruBuilder.cs index c47223f9..110b6b9b 100644 --- a/BitFaster.Caching/Lru/Builder/AsyncConcurrentLruBuilder.cs +++ b/BitFaster.Caching/Lru/Builder/AsyncConcurrentLruBuilder.cs @@ -1,11 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - + namespace BitFaster.Caching.Lru.Builder { + /// + /// A builder for creating a ConcurrentLru. + /// + /// The type of the cache key. + /// The type of the cache value. public sealed class AsyncConcurrentLruBuilder : LruBuilderBase, IAsyncCache> { internal AsyncConcurrentLruBuilder(LruInfo info) diff --git a/BitFaster.Caching/Lru/Builder/AtomicAsyncConcurrentLruBuilder.cs b/BitFaster.Caching/Lru/Builder/AtomicAsyncConcurrentLruBuilder.cs index ab1320c1..d0930c97 100644 --- a/BitFaster.Caching/Lru/Builder/AtomicAsyncConcurrentLruBuilder.cs +++ b/BitFaster.Caching/Lru/Builder/AtomicAsyncConcurrentLruBuilder.cs @@ -2,6 +2,11 @@ namespace BitFaster.Caching.Lru.Builder { + /// + /// A builder for creating a ConcurrentLru as IAsyncCache with atomic value creation. + /// + /// The type of the cache key. + /// The type of the cache value. public class AtomicAsyncConcurrentLruBuilder : LruBuilderBase, IAsyncCache> { private readonly ConcurrentLruBuilder> inner; diff --git a/BitFaster.Caching/Lru/Builder/AtomicConcurrentLruBuilder.cs b/BitFaster.Caching/Lru/Builder/AtomicConcurrentLruBuilder.cs index 420dfdf0..a2b65668 100644 --- a/BitFaster.Caching/Lru/Builder/AtomicConcurrentLruBuilder.cs +++ b/BitFaster.Caching/Lru/Builder/AtomicConcurrentLruBuilder.cs @@ -2,6 +2,11 @@ namespace BitFaster.Caching.Lru.Builder { + /// + /// A builder for creating a ConcurrentLru as ICache with atomic value creation. + /// + /// The type of the cache key. + /// The type of the cache value. public class AtomicConcurrentLruBuilder : LruBuilderBase, ICache> { private readonly ConcurrentLruBuilder> inner; diff --git a/BitFaster.Caching/Lru/Builder/AtomicScopedAsyncConcurrentLruBuilder.cs b/BitFaster.Caching/Lru/Builder/AtomicScopedAsyncConcurrentLruBuilder.cs index f545ce54..709cf6aa 100644 --- a/BitFaster.Caching/Lru/Builder/AtomicScopedAsyncConcurrentLruBuilder.cs +++ b/BitFaster.Caching/Lru/Builder/AtomicScopedAsyncConcurrentLruBuilder.cs @@ -1,12 +1,13 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using BitFaster.Caching.Atomic; namespace BitFaster.Caching.Lru.Builder { + /// + /// A builder for creating a ConcurrentLru with scoped values. + /// + /// The type of the cache key. + /// The type of the cache value. public sealed class AtomicScopedAsyncConcurrentLruBuilder : LruBuilderBase, IScopedAsyncCache> where V : IDisposable { private readonly AsyncConcurrentLruBuilder> inner; diff --git a/BitFaster.Caching/Lru/Builder/AtomicScopedConcurrentLruBuilder.cs b/BitFaster.Caching/Lru/Builder/AtomicScopedConcurrentLruBuilder.cs index f575c570..fa38c331 100644 --- a/BitFaster.Caching/Lru/Builder/AtomicScopedConcurrentLruBuilder.cs +++ b/BitFaster.Caching/Lru/Builder/AtomicScopedConcurrentLruBuilder.cs @@ -3,6 +3,11 @@ namespace BitFaster.Caching.Lru.Builder { + /// + /// A builder for creating a ConcurrentLru with scoped values. + /// + /// The type of the cache key. + /// The type of the cache value. public class AtomicScopedConcurrentLruBuilder : LruBuilderBase, IScopedCache> where V : IDisposable { private readonly ConcurrentLruBuilder> inner; diff --git a/BitFaster.Caching/Lru/Builder/ScopedAsyncConcurrentLruBuilder.cs b/BitFaster.Caching/Lru/Builder/ScopedAsyncConcurrentLruBuilder.cs index 400da06e..7b6140b3 100644 --- a/BitFaster.Caching/Lru/Builder/ScopedAsyncConcurrentLruBuilder.cs +++ b/BitFaster.Caching/Lru/Builder/ScopedAsyncConcurrentLruBuilder.cs @@ -2,6 +2,11 @@ namespace BitFaster.Caching.Lru.Builder { + /// + /// A builder for creating a ConcurrentLru with scoped values. + /// + /// The type of the cache key. + /// The type of the cache value. public sealed class ScopedAsyncConcurrentLruBuilder : LruBuilderBase, IScopedAsyncCache> where V : IDisposable { private readonly AsyncConcurrentLruBuilder> inner; diff --git a/BitFaster.Caching/Lru/Builder/ScopedConcurrentLruBuilder.cs b/BitFaster.Caching/Lru/Builder/ScopedConcurrentLruBuilder.cs index 229a088e..d6fe4708 100644 --- a/BitFaster.Caching/Lru/Builder/ScopedConcurrentLruBuilder.cs +++ b/BitFaster.Caching/Lru/Builder/ScopedConcurrentLruBuilder.cs @@ -2,6 +2,12 @@ namespace BitFaster.Caching.Lru.Builder { + /// + /// A builder for creating a ConcurrentLru with scoped values. + /// + /// The type of the cache key. + /// The type of the cache value. + /// The type of the wrapped cache value. public sealed class ScopedConcurrentLruBuilder : LruBuilderBase, IScopedCache> where V : IDisposable where W : IScoped { private readonly ConcurrentLruBuilder inner;