forked from NpgsqlRest/NpgsqlRest
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRoutineCache.cs
More file actions
92 lines (78 loc) · 2.69 KB
/
Copy pathRoutineCache.cs
File metadata and controls
92 lines (78 loc) · 2.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
using System.Collections.Concurrent;
namespace NpgsqlRest;
public interface IRoutineCache
{
bool Get(RoutineEndpoint endpoint, string key, out object? result);
void AddOrUpdate(RoutineEndpoint endpoint, string key, object? value);
}
public class RoutineCache : IRoutineCache
{
private class CacheEntry
{
public object? Value { get; set; }
public DateTime? ExpirationTime { get; set; }
public bool IsExpired => ExpirationTime.HasValue && DateTime.UtcNow > ExpirationTime.Value;
}
private static readonly ConcurrentDictionary<int, CacheEntry> _cache = new();
private static readonly ConcurrentDictionary<int, string> _originalKeys = new();
private static Timer? _cleanupTimer;
public static void Start(NpgsqlRestOptions options)
{
_cleanupTimer = new Timer(
_ => CleanupExpiredEntriesInternal(),
null,
TimeSpan.FromSeconds(options.CacheOptions.MemoryCachePruneIntervalSeconds),
TimeSpan.FromSeconds(options.CacheOptions.MemoryCachePruneIntervalSeconds));
}
public static void Shutdown()
{
_cleanupTimer?.Dispose();
_cache.Clear();
_originalKeys.Clear();
}
private static void CleanupExpiredEntriesInternal()
{
var expiredKeys = _cache
.Where(kvp => kvp.Value.IsExpired)
.Select(kvp => kvp.Key)
.ToList();
foreach (var key in expiredKeys)
{
_cache.TryRemove(key, out _);
_originalKeys.TryRemove(key, out _);
}
}
public bool Get(RoutineEndpoint endpoint, string key, out object? result)
{
var hashedKey = key.GetHashCode();
if (_cache.TryGetValue(hashedKey, out var entry))
{
if (_originalKeys.TryGetValue(hashedKey, out var originalKey) && originalKey == key)
{
if (entry.IsExpired)
{
// Remove expired entry
_cache.TryRemove(hashedKey, out _);
_originalKeys.TryRemove(hashedKey, out _);
result = null;
return false;
}
result = entry.Value;
return true;
}
}
result = null;
return false;
}
public void AddOrUpdate(RoutineEndpoint endpoint, string key, object? value)
{
var hashedKey = key.GetHashCode();
var entry = new CacheEntry
{
Value = value,
ExpirationTime = endpoint.CacheExpiresIn.HasValue ? DateTime.UtcNow + endpoint.CacheExpiresIn.Value : null
};
_cache[hashedKey] = entry;
_originalKeys[hashedKey] = key;
}
}