From 6708e736d312a30e3b045a65041135d792c63658 Mon Sep 17 00:00:00 2001 From: Mark Cilia Vincenti Date: Tue, 10 Jan 2023 10:29:56 +0100 Subject: [PATCH 1/6] Switched to AsyncKeyedLock for better performance and lower memory usage --- .../Caches/AsyncLazyCache.cs | 103 ++---------------- .../R5.Internals.Caching.csproj | 1 + 2 files changed, 9 insertions(+), 95 deletions(-) diff --git a/R5.Internals/R5.Internals.Caching/Caches/AsyncLazyCache.cs b/R5.Internals/R5.Internals.Caching/Caches/AsyncLazyCache.cs index 747101a..c1fb70d 100644 --- a/R5.Internals/R5.Internals.Caching/Caches/AsyncLazyCache.cs +++ b/R5.Internals/R5.Internals.Caching/Caches/AsyncLazyCache.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.Caching.Memory; +using AsyncKeyedLock; +using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using System; @@ -19,7 +20,11 @@ public interface IAsyncLazyCache : IDisposable public class AsyncLazyCache : IAsyncLazyCache { private readonly IMemoryCache _cache; - private static readonly KeyedLocks _locks = new KeyedLocks(); + private static readonly AsyncKeyedLocker _locks = new AsyncKeyedLocker(o => + { + o.PoolSize = 20; + o.PoolInitialFill = 1; + }); public AsyncLazyCache(IMemoryCache cache) { @@ -42,7 +47,7 @@ public async Task GetOrCreateAsync(string key, Func> factoryTask) return value; } - using (await _locks.LockAsync(key)) + using (await _locks.LockAsync(key).ConfigureAwait(false)) { if (!_cache.TryGetValue(key, out _)) { @@ -102,98 +107,6 @@ public void Dispose() { _cache?.Dispose(); } - - // internal abstraction to manage the creating/releasing of keyed semaphores - private sealed class KeyedLocks - { - private static readonly Dictionary _locks - = new Dictionary(StringComparer.OrdinalIgnoreCase); - - public IDisposable Lock(string key) - { - AcquireLock(key).Wait(); - return new LockReleaser(key); - } - - public async Task LockAsync(string key) - { - await AcquireLock(key).WaitAsync().ConfigureAwait(false); - return new LockReleaser(key); - } - - // Returns the semaphore associated to the key. Either creates - // a new one and adds to the map, or returns the already existing - // one (additionally incrementing its referenced count) - private SemaphoreSlim AcquireLock(string key) - { - CountedLock exclusiveLock; - lock (_locks) - { - if (_locks.TryGetValue(key, out exclusiveLock)) - { - exclusiveLock.Increment(); - } - else - { - exclusiveLock = new CountedLock(); - _locks[key] = exclusiveLock; - } - } - - return exclusiveLock.Lock; - } - - // Wrapper around a semaphore - keeps track of the count the key was referenced - private sealed class CountedLock - { - public SemaphoreSlim Lock { get; } = new SemaphoreSlim(1, 1); - private int _count { get; set; } = 1; - - public void Increment() - { - _count++; - } - - public void Decrement() - { - _count--; - } - - public bool NotReferenced() - { - return _count == 0; - } - } - - // IDisposable type returned after acquiring a lock. It will handle removing the - // semaphore from the map if releasing results in no more references to the key. - private sealed class LockReleaser : IDisposable - { - private string _key { get; } - - public LockReleaser(string key) - { - _key = key; - } - - public void Dispose() - { - CountedLock exclusiveLock; - lock (_locks) - { - exclusiveLock = _locks[_key]; - - exclusiveLock.Decrement(); - if (!exclusiveLock.NotReferenced()) - { - _locks.Remove(_key); - } - } - - exclusiveLock.Lock.Release(); - } - } - } } public static class ServiceCollectionExtensions diff --git a/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj b/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj index b0042e5..31be2a6 100644 --- a/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj +++ b/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj @@ -6,6 +6,7 @@ + From 33b5c18baa7f6e5d0e70de5d1ef489753f9b7d48 Mon Sep 17 00:00:00 2001 From: Mark Cilia Vincenti Date: Thu, 26 Jan 2023 09:27:38 +0100 Subject: [PATCH 2/6] Update to AsyncKeyedLock 6.1.0 --- R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj b/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj index 31be2a6..6a1b2cb 100644 --- a/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj +++ b/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj @@ -6,7 +6,7 @@ - + From a09bac7241509c99393f62652353bfa231211bbd Mon Sep 17 00:00:00 2001 From: Mark Cilia Vincenti Date: Fri, 27 Jan 2023 19:10:17 +0100 Subject: [PATCH 3/6] Update to AsyncKeyedLock 6.1.1 --- R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj b/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj index 6a1b2cb..250bc98 100644 --- a/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj +++ b/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj @@ -6,7 +6,7 @@ - + From 8499142e010ee68f3e6a2aefe7e0b3cdb618c1e7 Mon Sep 17 00:00:00 2001 From: Mark Cilia Vincenti Date: Sat, 25 Feb 2023 14:26:28 +0100 Subject: [PATCH 4/6] Update to AsyncKeyedLock 6.2.0 --- R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj b/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj index 250bc98..ae8a1b4 100644 --- a/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj +++ b/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj @@ -6,7 +6,7 @@ - + From 8d59397e9975058c17b4fe814b63a87b3356714e Mon Sep 17 00:00:00 2001 From: Mark Cilia Vincenti Date: Mon, 10 Apr 2023 09:36:53 +0200 Subject: [PATCH 5/6] Update R5.Internals.Caching.csproj --- R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj b/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj index ae8a1b4..ea8c3ab 100644 --- a/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj +++ b/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj @@ -6,7 +6,7 @@ - + From 1a72d0630cdd6a27eaa45e6b5108cdcbed92d80c Mon Sep 17 00:00:00 2001 From: Mark Cilia Vincenti Date: Sat, 3 Feb 2024 17:17:42 +0100 Subject: [PATCH 6/6] Bump AsyncKeyedLock to 6.3.4 --- R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj b/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj index ea8c3ab..e2afdff 100644 --- a/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj +++ b/R5.Internals/R5.Internals.Caching/R5.Internals.Caching.csproj @@ -6,7 +6,7 @@ - +