Skip to content

Commit

Permalink
Add SemaphoreCache
Browse files Browse the repository at this point in the history
  • Loading branch information
TheArcaneBrony committed Apr 4, 2024
1 parent 7c6627c commit 956b734
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 1 deletion.
2 changes: 1 addition & 1 deletion ArcaneLibs/Collections/ObservableDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public void Clear() {

public TValue this[TKey key] {
get {
Console.WriteLine($"Getting value {key}");
// Console.WriteLine($"Getting value {key}");
return _dictionary[key];
}
set {
Expand Down
53 changes: 53 additions & 0 deletions ArcaneLibs/Collections/SemaphoreCache.cs
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;
}
}

0 comments on commit 956b734

Please sign in to comment.