Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
CachedStringDictionary.cs
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.Threading.Tasks;
5using Waher.Events;
7
9{
13 public class CachedStringDictionary : IDictionary<string, object>, IPersistentDictionary, IDisposable
14 {
15 private readonly Cache<string, Rec> cache;
16 private readonly IPersistentDictionary dictionary;
17
23 public CachedStringDictionary(int CacheSize, IPersistentDictionary Dictionary)
24 {
25 this.dictionary = Dictionary;
26 this.cache = new Cache<string, Rec>(CacheSize, TimeSpan.MaxValue, TimeSpan.MaxValue, true);
27 this.cache.Removed += this.Cache_Removed;
28 }
29
33 public class Rec
34 {
38 public object Value;
39
43 public bool FromDB;
44 }
45
46 private async Task Cache_Removed(object Sender, CacheItemEventArgs<string, Rec> e)
47 {
48 try
49 {
50 switch (e.Reason)
51 {
52 case RemovedReason.Replaced:
53 if (e.Value.FromDB)
54 {
55 try
56 {
57 await this.dictionary.RemoveAsync(e.Key);
58 }
59 catch (Exception ex)
60 {
61 Log.Exception(ex);
62 }
63 }
64 break;
65
66 case RemovedReason.NotUsed:
67 case RemovedReason.Old:
68 case RemovedReason.Space:
69 if (!e.Value.FromDB)
70 {
71 try
72 {
73 await this.dictionary.AddAsync(e.Key, e.Value.Value, true);
74 }
75 catch (Exception ex)
76 {
77 Log.Exception(ex);
78 }
79 }
80 break;
81
82 case RemovedReason.Manual:
83 default:
84 break;
85 }
86 }
87 catch (Exception ex)
88 {
89 Log.Exception(ex);
90 }
91 }
92
96 public object this[string key]
97 {
98 get
99 {
100 if (this.cache.TryGetValue(key, out Rec Rec))
101 return Rec.Value;
102
103 if (this.dictionary.TryGetValue(key, out object Value))
104 {
105 this.cache[key] = new Rec()
106 {
107 Value = Value,
108 FromDB = true
109 };
110
111 return Value;
112 }
113
114 throw new KeyNotFoundException("key not found in dictionary: " + key);
115 }
116
117 set
118 {
119 this.cache[key] = new Rec()
120 {
121 Value = value,
122 FromDB = false
123 };
124 }
125 }
126
130 public ICollection<string> Keys
131 {
132 get
133 {
134 this.Flush();
135 return this.dictionary.Keys;
136 }
137 }
138
142 public ICollection<object> Values
143 {
144 get
145 {
146 this.Flush();
147 return this.dictionary.Values;
148 }
149 }
150
154 public int Count
155 {
156 get
157 {
158 this.Flush();
159 return this.dictionary.Count;
160 }
161 }
162
166 public bool IsReadOnly => false;
167
171 public void Add(string key, object value)
172 {
173 this.cache[key] = new Rec()
174 {
175 Value = value,
176 FromDB = false
177 };
178 }
179
183 public void Add(KeyValuePair<string, object> item)
184 {
185 this.cache[item.Key] = new Rec()
186 {
187 Value = item.Value,
188 FromDB = false
189 };
190 }
191
195 public void Clear()
196 {
197 this.cache.Clear();
198 this.dictionary.Clear();
199 }
200
204 public bool Contains(KeyValuePair<string, object> item)
205 {
206 if (this.cache.TryGetValue(item.Key, out Rec Rec))
207 return Rec.Value.Equals(item.Value);
208 else if (this.dictionary.TryGetValue(item.Key, out object Value))
209 return Value.Equals(item.Value);
210 else
211 return false;
212 }
213
217 public bool ContainsKey(string key)
218 {
219 return this.cache.ContainsKey(key) || this.dictionary.ContainsKey(key);
220 }
221
225 public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
226 {
227 this.Flush();
228 this.dictionary.CopyTo(array, arrayIndex);
229 }
230
234 public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
235 {
236 this.Flush();
237 return this.dictionary.GetEnumerator();
238 }
239
243 public async Task<IEnumerator<KeyValuePair<string, object>>> GetEnumeratorAsync()
244 {
245 await this.FlushAsync();
246 return this.dictionary.GetEnumerator();
247 }
248
252 public bool Remove(string key)
253 {
254 if (this.cache.TryGetValue(key, out Rec Rec))
255 {
256 this.cache.Remove(key);
257
258 if (Rec.FromDB)
259 return this.dictionary.Remove(key);
260 else
261 return true;
262 }
263 else
264 return this.dictionary.Remove(key);
265 }
266
270 public bool Remove(KeyValuePair<string, object> item)
271 {
272 if (this.cache.TryGetValue(item.Key, out Rec Rec))
273 {
274 if (!Rec.Value.Equals(item.Value))
275 return false;
276
277 this.cache.Remove(item.Key);
278
279 if (Rec.FromDB)
280 return this.dictionary.Remove(item.Key);
281 else
282 return true;
283 }
284 else if (this.dictionary.TryGetValue(item.Key, out object Value))
285 {
286 if (Value.Equals(item.Value))
287 return this.dictionary.Remove(item.Key);
288 else
289 {
290 this.cache[item.Key] = new Rec()
291 {
292 Value = Value,
293 FromDB = true
294 };
295
296 return false;
297 }
298 }
299 else
300 return false;
301 }
302
306 public bool TryGetValue(string key, out object value)
307 {
308 if (this.cache.TryGetValue(key, out Rec Rec))
309 {
310 value = Rec.Value;
311 return true;
312 }
313 else if (this.dictionary.TryGetValue(key, out value))
314 {
315 this.cache[key] = new Rec()
316 {
317 Value = value,
318 FromDB = true
319 };
320
321 return true;
322 }
323 else
324 return false;
325 }
326
327 IEnumerator IEnumerable.GetEnumerator()
328 {
329 this.Flush();
330 return this.dictionary.GetEnumerator();
331 }
332
336 public async void Flush()
337 {
338 try
339 {
340 KeyValuePair<string, Rec>[] Records = this.cache.ToArray();
341 this.cache.Clear();
342
343 try
344 {
345 await Database.StartBulk();
346
347 int i = 0;
348
349 try
350 {
351 foreach (KeyValuePair<string, Rec> Rec in Records)
352 {
353 if (!Rec.Value.FromDB)
354 {
355 await this.dictionary.AddAsync(Rec.Key, Rec.Value.Value, true);
356
357 i++;
358 if (i >= 1000)
359 {
360 await Database.EndBulk();
361 await Database.StartBulk();
362 i = 0;
363 }
364 }
365 }
366 }
367 finally
368 {
369 await Database.EndBulk();
370 }
371 }
372 catch (Exception ex)
373 {
374 Log.Exception(ex);
375 }
376 }
377 catch (Exception ex)
378 {
379 Log.Exception(ex);
380 }
381 }
382
386 public async Task FlushAsync()
387 {
388 KeyValuePair<string, Rec>[] Records = this.cache.ToArray();
389 this.cache.Clear();
390
391 foreach (KeyValuePair<string, Rec> Rec in Records)
392 {
393 if (!Rec.Value.FromDB)
394 await this.dictionary.AddAsync(Rec.Key, Rec.Value.Value, true);
395 }
396 }
397
401 public void Dispose()
402 {
403 this.Flush();
404 this.cache.Dispose();
405 this.dictionary.Dispose();
406 }
407
411 public void DeleteAndDispose()
412 {
413 this.Clear();
414 this.dictionary.DeleteAndDispose();
415 }
416
420 public Task ClearAsync()
421 {
422 this.cache.Clear();
423 return this.dictionary.ClearAsync();
424 }
425
429 public async Task<bool> ContainsKeyAsync(string key)
430 {
431 return this.cache.ContainsKey(key) || await this.dictionary.ContainsKeyAsync(key);
432 }
433
437 public Task AddAsync(string key, object value)
438 {
439 this.Add(key, value);
440 return Task.CompletedTask;
441 }
442
446 public Task AddAsync(string key, object value, bool ReplaceIfExists)
447 {
448 if (ReplaceIfExists)
449 this[key] = value;
450 else
451 this.Add(key, value);
452
453 return Task.CompletedTask;
454 }
455
459 public async Task<bool> RemoveAsync(string key)
460 {
461 if (this.cache.TryGetValue(key, out Rec Rec))
462 {
463 this.cache.Remove(key);
464
465 if (Rec.FromDB)
466 return await this.dictionary.RemoveAsync(key);
467 else
468 return true;
469 }
470 else
471 return await this.dictionary.RemoveAsync(key);
472 }
473
477 public async Task<KeyValuePair<bool, object>> TryGetValueAsync(string key)
478 {
479 if (this.cache.TryGetValue(key, out Rec Rec))
480 return new KeyValuePair<bool, object>(true, Rec.Value);
481 else
482 {
483 KeyValuePair<bool, object> P = await this.dictionary.TryGetValueAsync(key);
484
485 if (P.Key)
486 {
487 this.cache[key] = new Rec()
488 {
489 Value = P.Value,
490 FromDB = true
491 };
492 }
493
494 return P;
495 }
496 }
497
504 public async Task<KeyValuePair<string, object>[]> GetEntriesAsync(string FromKey, string ToKey)
505 {
506 Dictionary<string, object> ByName = new Dictionary<string, object>();
507
508 foreach (KeyValuePair<string, object> Entry in await this.dictionary.GetEntriesAsync(FromKey, ToKey))
509 ByName[Entry.Key] = Entry.Value;
510
511 foreach (KeyValuePair<string, Rec> Entry in this.cache.ToArray())
512 ByName[Entry.Key] = Entry.Value;
513
514 KeyValuePair<string, object>[] Result = new KeyValuePair<string, object>[ByName.Count];
515 int i = 0;
516 foreach (KeyValuePair<string, object> Entry in ByName)
517 Result[i++] = Entry;
518
519 return Result;
520 }
521
527 public Task CopyKeysToAsync(string[] Keys, int Offset)
528 {
529 return this.dictionary.CopyKeysToAsync(Keys, Offset);
530 }
531
537 public Task CopyValuesToAsync(object[] Values, int Offset)
538 {
539 return this.dictionary.CopyValuesToAsync(Values, Offset);
540 }
541
546 public Task<string[]> GetKeysAsync()
547 {
548 return this.dictionary.GetKeysAsync();
549 }
550
555 public Task<object[]> GetValuesAsync()
556 {
557 return this.dictionary.GetValuesAsync();
558 }
559
560 }
561}
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
Definition: Log.cs:1647
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:19
static Task EndBulk()
Ends bulk-processing of data. Must be called once for every call to StartBulk.
Definition: Database.cs:1494
static Task StartBulk()
Starts bulk-proccessing of data. Must be followed by a call to EndBulk.
Definition: Database.cs:1486
Optimizes a persistent IPersistentDictionary using a cache.
Task CopyValuesToAsync(object[] Values, int Offset)
Copies available values to an array.
async Task< KeyValuePair< bool, object > > TryGetValueAsync(string key)
TODO
CachedStringDictionary(int CacheSize, IPersistentDictionary Dictionary)
Optimizes a persistent IPersistentDictionary using a cache.
bool Contains(KeyValuePair< string, object > item)
TODO
void Add(KeyValuePair< string, object > item)
TODO
void CopyTo(KeyValuePair< string, object >[] array, int arrayIndex)
TODO
async Task< KeyValuePair< string, object >[]> GetEntriesAsync(string FromKey, string ToKey)
Gets a range of entries from one key to another.
IEnumerator< KeyValuePair< string, object > > GetEnumerator()
TODO
Task CopyKeysToAsync(string[] Keys, int Offset)
Copies available keys to a string array.
Task AddAsync(string key, object value, bool ReplaceIfExists)
TODO
bool TryGetValue(string key, out object value)
TODO
async Task< IEnumerator< KeyValuePair< string, object > > > GetEnumeratorAsync()
TODO
bool Remove(KeyValuePair< string, object > item)
TODO
Represents an entry in a block or bucket file.
Definition: Entry.cs:11
Implements an in-memory cache.
Definition: Cache.cs:15
Event arguments for cache item removal events.
KeyType Key
Key of item that was removed.
ValueType Value
Value of item that was removed.
RemovedReason Reason
Reason for removing the item.
Persistent dictionary that can contain more entries than possible in the internal memory.
RemovedReason
Reason for removing the item.