-
Notifications
You must be signed in to change notification settings - Fork 91
Expand file tree
/
Copy pathSlidingExpirationCache.cs
More file actions
80 lines (72 loc) · 2.38 KB
/
SlidingExpirationCache.cs
File metadata and controls
80 lines (72 loc) · 2.38 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
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
namespace EddiDataProviderService
{
public abstract class SlidingExpirationCache<TKey, TValue> : IDisposable
{
private class CacheItem
{
public TValue Value;
public DateTime LastAccess;
}
private readonly ConcurrentDictionary<TKey, CacheItem> cache = new();
private readonly TimeSpan slidingExpiration;
private readonly Timer cleanupTimer;
protected SlidingExpirationCache ( int expirationSeconds )
{
slidingExpiration = TimeSpan.FromSeconds( expirationSeconds );
cleanupTimer = new Timer( Cleanup, null, TimeSpan.FromMinutes( 1 ), TimeSpan.FromMinutes( 1 ) );
}
public void AddOrUpdate ( TKey key, TValue value )
{
cache.AddOrUpdate(
key,
_ => new CacheItem { Value = value, LastAccess = DateTime.UtcNow },
( _, existing ) => new CacheItem { Value = value, LastAccess = DateTime.UtcNow }
);
}
public bool TryGet ( TKey key, out TValue value )
{
value = default;
if ( cache.TryGetValue( key, out var item ) )
{
if ( DateTime.UtcNow - item.LastAccess < slidingExpiration )
{
item.LastAccess = DateTime.UtcNow;
value = item.Value;
return true;
}
else
{
cache.TryRemove( key, out _ );
}
}
return false;
}
public void AddOrUpdate ( IEnumerable<KeyValuePair<TKey, TValue>> items )
{
foreach ( var kvp in items )
{
AddOrUpdate( kvp.Key, kvp.Value );
}
}
private void Cleanup ( object state )
{
var now = DateTime.UtcNow;
foreach ( var key in cache.Keys )
{
if ( cache.TryGetValue( key, out var item ) && now - item.LastAccess >= slidingExpiration )
{
cache.TryRemove( key, out _ );
}
}
}
public void Dispose ()
{
cleanupTimer?.Dispose();
GC.SuppressFinalize( this );
}
}
}