-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7c6627c
commit 956b734
Showing
2 changed files
with
54 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using System.Collections.Concurrent; | ||
|
||
namespace ArcaneLibs.Collections; | ||
|
||
public class SemaphoreCache<T> where T : class { | ||
|
||
private readonly ConcurrentDictionary<string, T> _values = new(); | ||
private readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphores = new(); | ||
|
||
public async Task<T> GetOrAdd(string key, Func<Task<T>> factory) { | ||
ArgumentNullException.ThrowIfNull(key); | ||
_semaphores.TryAdd(key, new SemaphoreSlim(1, 1)); | ||
await _semaphores[key].WaitAsync(); | ||
if (_values.TryGetValue(key, out var value)) { | ||
_semaphores[key].Release(); | ||
return value; | ||
} | ||
|
||
var val = await factory(); | ||
_values.TryAdd(key, val); | ||
_semaphores[key].Release(); | ||
return val; | ||
} | ||
} | ||
|
||
public class ExiringSemaphoreCache<T> where T : class { | ||
|
||
private readonly ConcurrentDictionary<string, T> _values = new(); | ||
private readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphores = new(); | ||
|
||
public async Task<T> GetOrAdd(string key, Func<Task<T>> factory, TimeSpan expiry) { | ||
ArgumentNullException.ThrowIfNull(key); | ||
_semaphores.TryAdd(key, new SemaphoreSlim(1, 1)); | ||
await _semaphores[key].WaitAsync(); | ||
if (_values.TryGetValue(key, out var value)) { | ||
_semaphores[key].Release(); | ||
return value; | ||
} | ||
|
||
var val = await factory(); | ||
_values.TryAdd(key, val); | ||
_semaphores[key].Release(); | ||
|
||
#pragma warning disable CS4014 // We intentionally do not await this task - this handles cache expiry | ||
Task.Delay(expiry).ContinueWith(__ => { | ||
_values.TryRemove(key, out var _); | ||
_semaphores.TryRemove(key, out var _); | ||
}); | ||
#pragma warning restore CS4014 | ||
|
||
return val; | ||
} | ||
} |