diff --git a/Algorithm/Eocron.Algorithms.csproj b/Algorithm/Eocron.Algorithms.csproj index 51fa35a..452f19e 100644 --- a/Algorithm/Eocron.Algorithms.csproj +++ b/Algorithm/Eocron.Algorithms.csproj @@ -22,6 +22,7 @@ + @@ -36,4 +37,4 @@ README.md - \ No newline at end of file + diff --git a/Algorithm/FileCache/Async/FileCacheAsync.cs b/Algorithm/FileCache/Async/FileCacheAsync.cs index 65335d7..d3e3448 100644 --- a/Algorithm/FileCache/Async/FileCacheAsync.cs +++ b/Algorithm/FileCache/Async/FileCacheAsync.cs @@ -1,4 +1,5 @@ -using Eocron.Algorithms.Disposing; +using AsyncKeyedLock; +using Eocron.Algorithms.Disposing; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -14,79 +15,6 @@ public sealed class FileCacheAsync : IFileCacheAsync, IDisposable #region Private helper classes private delegate Task CancellableAction(CancellationToken token); - private sealed class PerKeySemaphoreSlim : IDisposable - { - private sealed class RefCounted - { - public RefCounted(T value) - { - RefCount = 1; - Value = value; - } - - public int RefCount { get; set; } - public T Value { get; private set; } - } - - private readonly SemaphoreSlim _lock = new SemaphoreSlim(1); - private readonly Dictionary> _dict = new Dictionary>(); - - private async Task> GetOrCreate(object key, CancellationToken token) - { - RefCounted item; - await _lock.WaitAsync(token); - try - { - if (_dict.TryGetValue(key, out item)) - { - ++item.RefCount; - } - else - { - item = new RefCounted(new SemaphoreSlim(1, 1)); - _dict[key] = item; - } - } - finally - { - _lock.Release(); - } - - return item; - } - - public async Task LockAsync(object key, CancellationToken token) - { - var item = await GetOrCreate(key, token); - await item.Value.WaitAsync(CancellationToken.None); - return new Disposable(() => - { - _lock.Wait(CancellationToken.None); - try - { - --item.RefCount; - if (item.RefCount == 0) - _dict.Remove(key); - } - finally - { - _lock.Release(); - } - - item.Value.Release(); - }); - } - - public void Dispose() - { - _lock.Dispose(); - foreach (var v in _dict.Values) - { - v.Value.Dispose(); - } - } - } - private sealed class CFileCacheEntry : AnyExpirationPolicy { public string FilePath { get; set; } @@ -168,7 +96,7 @@ public void Dispose() private readonly int _gcIntervalMs = 5 * 1000; private readonly int _gcFailRetryIntervalMs = 10 * 1000; - private readonly PerKeySemaphoreSlim _perKeyLock; + private readonly AsyncKeyedLocker _perKeyLock; private readonly IFileSystemAsync _fs; private readonly string _baseFolder; private readonly AsyncReaderWriterLock _cacheLock; @@ -203,7 +131,11 @@ public FileCacheAsync(string baseFolder, IFileSystemAsync fileSystem = null, boo { if (baseFolder == null) throw new ArgumentNullException(nameof(baseFolder)); - _perKeyLock = new PerKeySemaphoreSlim(); + _perKeyLock = new AsyncKeyedLocker(o => + { + o.PoolSize = 20; + o.PoolInitialFill = 1; + }); _cacheLock = new AsyncReaderWriterLock(); _fs = fileSystem ?? FileSystemAsync.Instance; _baseFolder = baseFolder; @@ -464,7 +396,7 @@ private async Task InternalGetOrAdd(TKey key, Func : IFileCache, IDisposable #region Private helper classes private delegate void CancellableAction(CancellationToken token); - private sealed class PerKeySemaphoreSlim : IDisposable - { - private sealed class RefCounted - { - public RefCounted(T value) - { - RefCount = 1; - Value = value; - } - - public int RefCount { get; set; } - public T Value { get; private set; } - } - - private readonly SemaphoreSlim _lock = new SemaphoreSlim(1); - private readonly Dictionary> _dict = new Dictionary>(); - - private RefCounted GetOrCreate(object key, CancellationToken token) - { - RefCounted item; - _lock.Wait(token); - try - { - if (_dict.TryGetValue(key, out item)) - { - ++item.RefCount; - } - else - { - item = new RefCounted(new SemaphoreSlim(1, 1)); - _dict[key] = item; - } - } - finally - { - _lock.Release(); - } - - return item; - } - - public IDisposable Lock(object key, CancellationToken token) - { - var item = GetOrCreate(key, token); - item.Value.Wait(CancellationToken.None); - return new Disposable(() => - { - _lock.Wait(CancellationToken.None); - try - { - --item.RefCount; - if (item.RefCount == 0) - _dict.Remove(key); - } - finally - { - _lock.Release(); - } - - item.Value.Release(); - }); - } - - public void Dispose() - { - _lock.Dispose(); - foreach (var v in _dict.Values) - { - v.Value.Dispose(); - } - } - } - private sealed class CFileCacheEntry : AnyExpirationPolicy { public string FilePath { get; set; } @@ -168,7 +96,7 @@ public void Dispose() private readonly int _gcIntervalMs = 5 * 1000; private readonly int _gcFailRetryIntervalMs = 10 * 1000; - private readonly PerKeySemaphoreSlim _perKeyLock; + private readonly AsyncKeyedLocker _perKeyLock; private readonly IFileSystem _fs; private readonly string _baseFolder; private readonly ReaderWriterLockSlim _cacheLock; @@ -203,7 +131,11 @@ public FileCache(string baseFolder, IFileSystem fileSystem = null, bool disableG { if (baseFolder == null) throw new ArgumentNullException(nameof(baseFolder)); - _perKeyLock = new PerKeySemaphoreSlim(); + _perKeyLock = new AsyncKeyedLocker(o => + { + o.PoolSize = 20; + o.PoolInitialFill = 1; + }); _cacheLock = new ReaderWriterLockSlim(); _fs = fileSystem ?? FileSystem.Instance; _baseFolder = baseFolder; @@ -750,7 +682,6 @@ public void Dispose() { _cts?.Dispose(); _gc?.Join(); - _perKeyLock.Dispose(); //_cacheLock.Dispose(); } }