/
FileCache.cs
228 lines (182 loc) · 7.38 KB
/
FileCache.cs
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Caching;
using PS.Runtime.Caching.API;
using PS.Runtime.Caching.Default;
using PS.Runtime.Caching.Extensions;
namespace PS.Runtime.Caching
{
public class FileCache : ObjectCache
{
private readonly IMemoryCacheFacade _memoryCacheFacade;
private readonly IRepository _repository;
private readonly IDataSerializer _serializer;
#region Constructors
public FileCache(IRepository repository,
string name = null,
IDataSerializer serializer = null,
IMemoryCacheFacade memoryCacheFacade = null)
{
Name = name;
DefaultCacheCapabilities = DefaultCacheCapabilities.AbsoluteExpirations |
DefaultCacheCapabilities.SlidingExpirations |
DefaultCacheCapabilities.InMemoryProvider |
DefaultCacheCapabilities.CacheRegions;
_repository = repository ?? new DefaultRepository();
_memoryCacheFacade = memoryCacheFacade ?? new DefaultMemoryCacheFacade();
_serializer = serializer ?? new DefaultDataSerializer();
}
#endregion
#region Properties
public override DefaultCacheCapabilities DefaultCacheCapabilities { get; }
public override object this[string key]
{
get { return Get(key); }
set { Set(key, value, InfiniteAbsoluteExpiration); }
}
public override string Name { get; }
#endregion
#region Override members
public override CacheItem GetCacheItem(string key, string regionName = null)
{
if (_memoryCacheFacade.Get(key, regionName) is ICacheEntry entry)
{
//Update access time only for items with sliding expiration
if (entry.Policy.SlidingExpiration != NoSlidingExpiration)
{
_repository.UpdateAccessTime(entry, DateTime.UtcNow);
}
return entry.GetCacheItem(_serializer);
}
return GetCacheEntry(key, regionName)?.GetCacheItem(_serializer);
}
protected override IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
return GetValues(GetKeys(null)).GetEnumerator();
}
public override CacheEntryChangeMonitor CreateCacheEntryChangeMonitor(IEnumerable<string> keys, string regionName = null)
{
throw new NotSupportedException();
}
public override IDictionary<string, object> GetValues(IEnumerable<string> keys, string regionName = null)
{
var result = new Dictionary<string, object>();
foreach (var key in keys.Enumerate().Distinct())
{
var item = GetCacheItem(key, regionName);
if (item == null) continue;
result.Add(key, item.Value);
}
return result;
}
public override object AddOrGetExisting(string key, object value, CacheItemPolicy policy, string regionName = null)
{
return AddOrGetExisting(new CacheItem(key, value, regionName), policy).Value;
}
public override object Get(string key, string regionName = null)
{
return GetCacheItem(key, regionName)?.Value;
}
public override bool Contains(string key, string regionName = null)
{
return GetCacheItem(key, regionName) != null;
}
public override void Set(string key, object value, CacheItemPolicy policy, string regionName = null)
{
Set(new CacheItem(key, value, regionName), policy);
}
public override void Set(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
{
var policy = new CacheItemPolicy
{
AbsoluteExpiration = absoluteExpiration
};
Set(new CacheItem(key, value, regionName), policy);
}
public override object AddOrGetExisting(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
{
return AddOrGetExisting(new CacheItem(key, value, regionName),
new CacheItemPolicy
{
AbsoluteExpiration = absoluteExpiration
});
}
public override CacheItem AddOrGetExisting(CacheItem value, CacheItemPolicy policy)
{
var existing = GetCacheItem(value.Key, value.RegionName);
if (existing != null) return existing;
Set(value, policy);
return value;
}
public override long GetCount(string regionName = null)
{
return GetValues(GetKeys(regionName), regionName).Count;
}
public override void Set(CacheItem item, CacheItemPolicy policy)
{
var now = DateTime.UtcNow;
var data = _serializer.SerializeItem(item);
var entry = _repository.Write(item.Key, item.RegionName, data, policy);
if (policy.SlidingExpiration != NoSlidingExpiration)
{
_repository.UpdateAccessTime(entry, now);
}
var expiration = policy.CalculateExpiration(now);
_memoryCacheFacade.Put(item.Key, item.RegionName, entry, expiration);
}
public override object Remove(string key, string regionName = null)
{
var entry = GetCacheEntry(key, regionName);
if (entry == null || entry.Policy.Priority == CacheItemPriority.NotRemovable) return null;
_repository.Delete(entry);
_memoryCacheFacade.Remove(key, regionName);
return entry.GetCacheItem(_serializer).Value;
}
#endregion
#region Members
/// <summary>
/// Marks all cached items as deleted
/// </summary>
public void Clear()
{
var regions = _repository.EnumerateRegions();
foreach (var region in regions)
{
foreach (var key in _repository.EnumerateKeys(region))
{
Remove(key, region);
}
}
}
private ICacheEntry GetCacheEntry(string key, string regionName)
{
try
{
var now = DateTime.UtcNow;
var entry = _repository.Read(key, regionName, now);
if (entry == null)
{
//Entry is not exist or expired
return null;
}
if (entry.Policy.SlidingExpiration != NoSlidingExpiration)
{
_repository.UpdateAccessTime(entry, now);
}
var expiration = entry.Policy.CalculateExpiration(now);
_memoryCacheFacade.Put(key, regionName, entry, expiration);
return entry;
}
catch
{
return null;
}
}
private IEnumerable<string> GetKeys(string regionName)
{
return _repository.EnumerateKeys(regionName);
}
#endregion
}
}