diff options
| author | Roy Ben-Shabat <Roy@Twine-s.com> | 2019-02-27 16:49:42 +0200 |
|---|---|---|
| committer | Roy Ben-Shabat <Roy@Twine-s.com> | 2019-02-27 16:49:42 +0200 |
| commit | 2ab54573d10ca59351100ab8416178be2223fc91 (patch) | |
| tree | 9a5077998e301c1e86cf00b07ea98eca501fc4a8 /Software/Visual_Studio/Tango.BL/ObservablesContextInMemoryCache.cs | |
| parent | 88a73106e8113a4a6ce224f9205e11219939798e (diff) | |
| download | Tango-2ab54573d10ca59351100ab8416178be2223fc91.tar.gz Tango-2ab54573d10ca59351100ab8416178be2223fc91.zip | |
Added support for caching on machine studio.
Diffstat (limited to 'Software/Visual_Studio/Tango.BL/ObservablesContextInMemoryCache.cs')
| -rw-r--r-- | Software/Visual_Studio/Tango.BL/ObservablesContextInMemoryCache.cs | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/Software/Visual_Studio/Tango.BL/ObservablesContextInMemoryCache.cs b/Software/Visual_Studio/Tango.BL/ObservablesContextInMemoryCache.cs new file mode 100644 index 000000000..39e6d7d9a --- /dev/null +++ b/Software/Visual_Studio/Tango.BL/ObservablesContextInMemoryCache.cs @@ -0,0 +1,221 @@ +using EFCache; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.BL +{ + public class ObservablesContextInMemoryCache : ICache + { + private readonly Dictionary<string, CacheEntry> _cache = new Dictionary<string, CacheEntry>(); + private readonly Dictionary<string, HashSet<string>> _entitySetToKey = new Dictionary<string, HashSet<string>>(); + + public TimeSpan Expiration { get; set; } + public bool ResetAccessTimeOnAccess { get; set; } + + public bool GetItem(string key, out object value) + { + if (key == null) + { + throw new ArgumentNullException("key"); + } + + value = null; + + lock (_cache) + { + var now = DateTimeOffset.Now; + + CacheEntry entry; + if (_cache.TryGetValue(key, out entry)) + { + if (EntryExpired(entry, now)) + { + InvalidateItem(key); + } + else + { + if (ResetAccessTimeOnAccess) + { + entry.LastAccess = now; + } + value = entry.Value; + return true; + } + } + } + + return false; + } + + public void PutItem(string key, object value, IEnumerable<string> dependentEntitySets, TimeSpan slidingExpiration, DateTimeOffset absoluteExpiration) + { + if (key == null) + { + throw new ArgumentNullException("key"); + } + + if (dependentEntitySets == null) + { + throw new ArgumentNullException("dependentEntitySets"); + } + + lock (_cache) + { + var entitySets = dependentEntitySets.ToArray(); + + _cache[key] = new CacheEntry(value, entitySets, slidingExpiration, absoluteExpiration); + + foreach (var entitySet in entitySets) + { + HashSet<string> keys; + + if (!_entitySetToKey.TryGetValue(entitySet, out keys)) + { + keys = new HashSet<string>(); + _entitySetToKey[entitySet] = keys; + } + + keys.Add(key); + } + } + } + + public void InvalidateSets(IEnumerable<string> entitySets) + { + if (entitySets == null) + { + throw new ArgumentNullException("entitySets"); + } + + lock (_cache) + { + var itemsToInvalidate = new HashSet<string>(); + + foreach (var entitySet in entitySets) + { + HashSet<string> keys; + + if (_entitySetToKey.TryGetValue(entitySet, out keys)) + { + itemsToInvalidate.UnionWith(keys); + + _entitySetToKey.Remove(entitySet); + } + } + + foreach (var key in itemsToInvalidate) + { + InvalidateItem(key); + } + } + } + + public void InvalidateItem(string key) + { + if (key == null) + { + throw new ArgumentNullException("key"); + } + + lock (_cache) + { + CacheEntry entry; + + if (_cache.TryGetValue(key, out entry)) + { + _cache.Remove(key); + + foreach (var set in entry.EntitySets) + { + HashSet<string> keys; + if (_entitySetToKey.TryGetValue(set, out keys)) + { + keys.Remove(key); + } + } + } + } + } + + public void Purge() + { + Purge(false); + } + + public void Purge(bool removeUnexpiredItems) + { + lock (_cache) + { + var now = DateTimeOffset.Now; + var itemsToRemove = new HashSet<string>(); + + foreach (var item in _cache) + { + if (removeUnexpiredItems || EntryExpired(item.Value, now)) + { + itemsToRemove.Add(item.Key); + } + } + + foreach (var key in itemsToRemove) + { + InvalidateItem(key); + } + } + } + + public int Count + { + get { return _cache.Count; } + } + + private bool EntryExpired(CacheEntry entry, DateTimeOffset now) + { + return entry.AbsoluteExpiration < now || (now - entry.LastAccess) > Expiration; + } + + private class CacheEntry + { + private readonly object _value; + private readonly string[] _entitySets; + private readonly TimeSpan _slidingExpiration; + private readonly DateTimeOffset _absoluteExpiration; + private readonly DateTime _created; + + public CacheEntry(object value, string[] entitySets, TimeSpan slidingExpiration, + DateTimeOffset absoluteExpiration) + { + _value = value; + _entitySets = entitySets; + _slidingExpiration = slidingExpiration; + _absoluteExpiration = absoluteExpiration; + LastAccess = DateTimeOffset.Now; + } + + public object Value + { + get { return _value; } + } + + public string[] EntitySets + { + get { return _entitySets; } + } + + public TimeSpan SlidingExpiration + { + get { return _slidingExpiration; } + } + + public DateTimeOffset AbsoluteExpiration + { + get { return _absoluteExpiration; } + } + + public DateTimeOffset LastAccess { get; set; } + } + } +} |
