forked from ServiceStackV3/ServiceStack.Contrib
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAzureCacheClient.cs
More file actions
311 lines (280 loc) · 11 KB
/
AzureCacheClient.cs
File metadata and controls
311 lines (280 loc) · 11 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
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
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
using System;
using System.Collections.Generic;
using Microsoft.ApplicationServer.Caching;
using ServiceStack.Logging;
namespace ServiceStack.CacheAccess.Azure
{
public class AzureCacheClient : AdapterBase, ICacheClient
{
private DataCacheFactory CacheFactory { get; set; }
private DataCache DataCache { get; set; }
public bool FlushOnDispose { get; set; }
protected override ILog Log { get { return LogManager.GetLogger(GetType()); } }
public AzureCacheClient(string cacheName = null)
{
CacheFactory = new DataCacheFactory();
if(string.IsNullOrEmpty(cacheName))
DataCache = CacheFactory.GetDefaultCache();
else
DataCache = CacheFactory.GetCache(cacheName);
}
private bool TryGetValue(string key, out object entry)
{
entry = DataCache.Get(key);
return entry != null;
}
private bool CacheAdd(string key, object value)
{
return CacheAdd(key, value, DateTime.MaxValue);
}
/// <summary>
/// Stores The value with key only if such key doesn't exist at the server yet.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
/// <param name="expiresAt">The expires at.</param>
/// <returns></returns>
private bool CacheAdd(string key, object value, DateTime expiresAt)
{
object entry;
if (TryGetValue(key, out entry)) return false;
DataCache.Add(key, value, expiresAt.Subtract(DateTime.Now));
return true;
}
private bool CacheSet(string key, object value)
{
return CacheSet(key, value, DateTime.MaxValue);
}
/// <summary>
/// Adds or replaces the value with key. Return false if a version exists but is not the lastversion.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
/// <param name="expiresAt">The expires at.</param>
/// <param name="checkLastVersion"> The check last version</param>
/// <returns>True; if it succeeded</returns>
private bool CacheSet(string key, object value, DateTime expiresAt, DataCacheItemVersion checkLastVersion = null)
{
if (checkLastVersion != null)
{
object entry = DataCache.GetIfNewer(key, ref checkLastVersion);
if(entry != null)
{
//update value and version
DataCache.Put(key, value, checkLastVersion, expiresAt.Subtract(DateTime.Now));
return true;
}
if (TryGetValue(key, out entry))
{//version exists but is older.
return false;
}
}
//if we don't care about version, then just update
DataCache.Put(key, value, expiresAt.Subtract(DateTime.Now));
return true;
}
private bool CacheReplace(string key, object value)
{
return CacheReplace(key, value, DateTime.MaxValue);
}
private bool CacheReplace(string key, object value, DateTime expiresAt)
{
return !CacheSet(key, value, expiresAt);;
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <filterpriority>2</filterpriority>
public void Dispose()
{
if (!FlushOnDispose) return;
FlushAll();
}
/// <summary>
/// Removes the specified item from the cache.
/// </summary>
/// <param name="key">The identifier for the item to delete.</param>
/// <returns>
/// true if the item was successfully removed from the cache; false otherwise.
/// </returns>
public bool Remove(string key)
{
return DataCache.Remove(key);
}
/// <summary>
/// Removes the cache for all the keys provided.
/// </summary>
/// <param name="keys">The keys.</param>
public void RemoveAll(IEnumerable<string> keys)
{
foreach (var key in keys)
{
try
{
Remove(key);
}
catch(Exception ex)
{
Log.Error(string.Format("Error trying to remove {0} from azure cache", key), ex);
}
}
}
public object Get(string key)
{
DataCacheItemVersion version;
return Get(key, out version);
}
public object Get(string key, out DataCacheItemVersion version)
{
return DataCache.Get(key, out version);
}
/// <summary>
/// Retrieves the specified item from the cache.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key">The identifier for the item to retrieve.</param>
/// <returns>
/// The retrieved item, or <value>null</value> if the key was not found.
/// </returns>
public T Get<T>(string key)
{
var value = Get(key);
if (value != null) return (T)value;
return default(T);
}
/// <summary>
/// Increments the value of the specified key by the given amount.
/// The operation is atomic and happens on the server.
/// A non existent value at key starts at 0
/// </summary>
/// <param name="key">The identifier for the item to increment.</param>
/// <param name="amount">The amount by which the client wants to increase the item.</param>
/// <returns>
/// The new value of the item or -1 if not found.
/// </returns>
/// <remarks>The item must be inserted into the cache before it can be changed. The item must be inserted as a <see cref="T:System.String"/>. The operation only works with <see cref="System.UInt32"/> values, so -1 always indicates that the item was not found.</remarks>
public long Increment(string key, uint amount)
{
return UpdateCounter(key, (int) amount);
}
private long UpdateCounter(string key, int value)
{
long longVal;
if(Int64.TryParse(Get(key).ToString(), out longVal))
{
longVal += value;
CacheSet(key, longVal);
return longVal;
}
CacheSet(key, 0);
return 0;
}
/// <summary>
/// Increments the value of the specified key by the given amount.
/// The operation is atomic and happens on the server.
/// A non existent value at key starts at 0
/// </summary>
/// <param name="key">The identifier for the item to increment.</param>
/// <param name="amount">The amount by which the client wants to decrease the item.</param>
/// <returns>
/// The new value of the item or -1 if not found.
/// </returns>
/// <remarks>The item must be inserted into the cache before it can be changed. The item must be inserted as a <see cref="T:System.String"/>. The operation only works with <see cref="System.UInt32"/> values, so -1 always indicates that the item was not found.</remarks>
public long Decrement(string key, uint amount)
{
return UpdateCounter(key, (int)-amount);
}
/// <summary>
/// Adds a new item into the cache at the specified cache key only if the cache is empty.
/// </summary>
/// <param name="key">The key used to reference the item.</param>
/// <param name="value">The object to be inserted into the cache.</param>
/// <returns>
/// true if the item was successfully stored in the cache; false otherwise.
/// </returns>
/// <remarks>The item does not expire unless it is removed due memory pressure.</remarks>
public bool Add<T>(string key, T value)
{
return CacheAdd(key, value);
}
/// <summary>
/// Sets an item into the cache at the cache key specified regardless if it already exists or not.
/// </summary>
public bool Set<T>(string key, T value)
{
return CacheSet(key, value);
}
/// <summary>
/// Replaces the item at the cachekey specified only if an items exists at the location already.
/// </summary>
public bool Replace<T>(string key, T value)
{
return CacheReplace(key, value);
}
public bool Add<T>(string key, T value, DateTime expiresAt)
{
return CacheAdd(key, value, expiresAt);
}
public bool Set<T>(string key, T value, DateTime expiresAt)
{
return CacheSet(key, value, expiresAt);
}
public bool Replace<T>(string key, T value, DateTime expiresAt)
{
return CacheReplace(key, value, expiresAt);
}
public bool Add<T>(string key, T value, TimeSpan expiresIn)
{
return CacheAdd(key, value, DateTime.Now.Add(expiresIn));
}
public bool Set<T>(string key, T value, TimeSpan expiresIn)
{
return CacheSet(key, value, DateTime.Now.Add(expiresIn));
}
public bool Replace<T>(string key, T value, TimeSpan expiresIn)
{
return CacheReplace(key, value, DateTime.Now.Add(expiresIn));
}
/// <summary>
/// Invalidates all data on the cache.
/// </summary>
public void FlushAll()
{
var regions = DataCache.GetSystemRegions();
foreach (var region in regions)
{
DataCache.ClearRegion(region);
}
}
/// <summary>
/// Retrieves multiple items from the cache.
/// The default value of T is set for all keys that do not exist.
/// </summary>
/// <param name="keys">The list of identifiers for the items to retrieve.</param>
/// <returns>
/// a Dictionary holding all items indexed by their key.
/// </returns>
public IDictionary<string, T> GetAll<T>(IEnumerable<string> keys)
{
var valueMap = new Dictionary<string, T>();
foreach (var key in keys)
{
var value = Get<T>(key);
valueMap[key] = value;
}
return valueMap;
}
/// <summary>
/// Sets multiple items to the cache.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="values">The values.</param>
public void SetAll<T>(IDictionary<string, T> values)
{
foreach (var entry in values)
{
Set(entry.Key, entry.Value);
}
}
}
}