namespace Ocelot.AcceptanceTests.Caching { using CacheManager.Core; using CacheManager.Core.Internal; using CacheManager.Core.Logging; using CacheManager.Core.Utility; using System; using System.Collections.Concurrent; using System.Linq; public class InMemoryJsonHandle : BaseCacheHandle { private readonly ICacheSerializer _serializer; private readonly ConcurrentDictionary> _cache; public InMemoryJsonHandle( ICacheManagerConfiguration managerConfiguration, CacheHandleConfiguration configuration, ICacheSerializer serializer, ILoggerFactory loggerFactory) : base(managerConfiguration, configuration) { _cache = new ConcurrentDictionary>(); _serializer = serializer; Logger = loggerFactory.CreateLogger(this); } public override int Count => _cache.Count; protected override ILogger Logger { get; } public override void Clear() => _cache.Clear(); public override void ClearRegion(string region) { Guard.NotNullOrWhiteSpace(region, nameof(region)); var key = string.Concat(region, ":"); foreach (var item in _cache.Where(p => p.Key.StartsWith(key, StringComparison.OrdinalIgnoreCase))) { _cache.TryRemove(item.Key, out Tuple val); } } public override bool Exists(string key) { Guard.NotNullOrWhiteSpace(key, nameof(key)); return _cache.ContainsKey(key); } public override bool Exists(string key, string region) { Guard.NotNullOrWhiteSpace(region, nameof(region)); var fullKey = GetKey(key, region); return _cache.ContainsKey(fullKey); } protected override bool AddInternalPrepared(CacheItem item) { Guard.NotNull(item, nameof(item)); var key = GetKey(item.Key, item.Region); var serializedItem = _serializer.SerializeCacheItem(item); return _cache.TryAdd(key, new Tuple(item.Value.GetType(), serializedItem)); } protected override CacheItem GetCacheItemInternal(string key) => GetCacheItemInternal(key, null); protected override CacheItem GetCacheItemInternal(string key, string region) { var fullKey = GetKey(key, region); CacheItem deserializedResult = null; if (_cache.TryGetValue(fullKey, out Tuple result)) { deserializedResult = _serializer.DeserializeCacheItem(result.Item2, result.Item1); if (deserializedResult.ExpirationMode != ExpirationMode.None && IsExpired(deserializedResult, DateTime.UtcNow)) { _cache.TryRemove(fullKey, out Tuple removeResult); TriggerCacheSpecificRemove(key, region, CacheItemRemovedReason.Expired, deserializedResult.Value); return null; } } return deserializedResult; } protected override void PutInternalPrepared(CacheItem item) { Guard.NotNull(item, nameof(item)); var serializedItem = _serializer.SerializeCacheItem(item); _cache[GetKey(item.Key, item.Region)] = new Tuple(item.Value.GetType(), serializedItem); } protected override bool RemoveInternal(string key) => RemoveInternal(key, null); protected override bool RemoveInternal(string key, string region) { var fullKey = GetKey(key, region); return _cache.TryRemove(fullKey, out Tuple val); } private static string GetKey(string key, string region) { Guard.NotNullOrWhiteSpace(key, nameof(key)); if (string.IsNullOrWhiteSpace(region)) { return key; } return string.Concat(region, ":", key); } private static bool IsExpired(CacheItem item, DateTime now) { if (item.ExpirationMode == ExpirationMode.Absolute && item.CreatedUtc.Add(item.ExpirationTimeout) < now) { return true; } else if (item.ExpirationMode == ExpirationMode.Sliding && item.LastAccessedUtc.Add(item.ExpirationTimeout) < now) { return true; } return false; } } }