//using System; //using System.Collections; //using System.Collections.Concurrent; //using System.Collections.Generic; //using System.Linq; //using System.Runtime.Caching; //using System.Threading; //using System.Web; //using Umbraco.Core.Models.EntityBase; //namespace Umbraco.Core.Persistence.Caching //{ // //TODO: Remove this singleton! // /// // /// The Runtime Cache provider looks up objects in the Runtime cache for fast retrival // /// // /// // /// // /// If a web session is detected then the HttpRuntime.Cache will be used for the runtime cache, otherwise a custom // /// MemoryCache instance will be used. It is important to use the HttpRuntime.Cache when a web session is detected so // /// that the memory management of cache in IIS can be handled appopriately. // /// // /// When a web sessions is detected we will pre-fix all HttpRuntime.Cache entries so that when we clear it we are only // /// clearing items that have been inserted by this provider. // /// // /// NOTE: These changes are all temporary until we finalize the ApplicationCache implementation which will support static cache, runtime cache // /// and request based cache which will all live in one central location so it is easily managed. // /// // /// Also note that we don't always keep checking if HttpContext.Current == null and instead check for _memoryCache != null. This is because // /// when there are async requests being made even in the context of a web request, the HttpContext.Current will be null but the HttpRuntime.Cache will // /// always be available. // /// // /// // internal sealed class RuntimeCacheProvider : IRepositoryCacheProvider // { // #region Singleton // private static readonly Lazy lazy = new Lazy(() => new RuntimeCacheProvider()); // public static RuntimeCacheProvider Current { get { return lazy.Value; } } // //internal for testing! - though I'm not a huge fan of these being singletons! // internal RuntimeCacheProvider() // { // if (HttpContext.Current == null) // { // _memoryCache = new MemoryCache("in-memory"); // } // } // #endregion // //TODO Save this in cache as well, so its not limited to a single server usage // private readonly ConcurrentHashSet _keyTracker = new ConcurrentHashSet(); // private ObjectCache _memoryCache; // private static readonly ReaderWriterLockSlim ClearLock = new ReaderWriterLockSlim(); // public IEntity GetById(Type type, Guid id) // { // var key = GetCompositeId(type, id); // var item = _memoryCache != null // ? _memoryCache.Get(key) // : HttpRuntime.Cache.Get(key); // var result = item as IEntity; // if (result == null) // { // //ensure the key doesn't exist anymore in the tracker // _keyTracker.Remove(key); // return null; // } // //IMPORTANT: we must clone to resolve, see: http://issues.umbraco.org/issue/U4-4259 // return (IEntity)result.DeepClone(); // } // public IEnumerable GetByIds(Type type, List ids) // { // var collection = new List(); // foreach (var guid in ids) // { // var key = GetCompositeId(type, guid); // var item = _memoryCache != null // ? _memoryCache.Get(key) // : HttpRuntime.Cache.Get(key); // var result = item as IEntity; // if (result == null) // { // //ensure the key doesn't exist anymore in the tracker // _keyTracker.Remove(key); // } // else // { // //IMPORTANT: we must clone to resolve, see: http://issues.umbraco.org/issue/U4-4259 // collection.Add((IEntity)result.DeepClone()); // } // } // return collection; // } // public IEnumerable GetAllByType(Type type) // { // var collection = new List(); // foreach (var key in _keyTracker) // { // if (key.StartsWith(string.Format("{0}{1}-", CacheItemPrefix, type.Name))) // { // var item = _memoryCache != null // ? _memoryCache.Get(key) // : HttpRuntime.Cache.Get(key); // var result = item as IEntity; // if (result == null) // { // //ensure the key doesn't exist anymore in the tracker // _keyTracker.Remove(key); // } // else // { // //IMPORTANT: we must clone to resolve, see: http://issues.umbraco.org/issue/U4-4259 // collection.Add((IEntity)result.DeepClone()); // } // } // } // return collection; // } // public void Save(Type type, IEntity entity) // { // //IMPORTANT: we must clone to store, see: http://issues.umbraco.org/issue/U4-4259 // var clone = (IEntity)entity.DeepClone(); // var key = GetCompositeId(type, clone.Key); // _keyTracker.TryAdd(key); // //NOTE: Before we were checking if it already exists but the MemoryCache.Set handles this implicitly and does // // an add or update, same goes for HttpRuntime.Cache.Insert. // if (_memoryCache != null) // { // _memoryCache.Set(key, clone, new CacheItemPolicy { SlidingExpiration = TimeSpan.FromMinutes(5) }); // } // else // { // HttpRuntime.Cache.Insert(key, clone, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(5)); // } // } // public void Delete(Type type, IEntity entity) // { // var key = GetCompositeId(type, entity.Key); // if (_memoryCache != null) // { // _memoryCache.Remove(key); // } // else // { // HttpRuntime.Cache.Remove(key); // } // _keyTracker.Remove(key); // } // /// // /// Clear cache by type // /// // /// // public void Clear(Type type) // { // using (new WriteLock(ClearLock)) // { // var keys = new string[_keyTracker.Count]; // _keyTracker.CopyTo(keys, 0); // var keysToRemove = new List(); // foreach (var key in keys.Where(x => x.StartsWith(string.Format("{0}{1}-", CacheItemPrefix, type.Name)))) // { // _keyTracker.Remove(key); // keysToRemove.Add(key); // } // foreach (var key in keysToRemove) // { // if (_memoryCache != null) // { // _memoryCache.Remove(key); // } // else // { // HttpRuntime.Cache.Remove(key); // } // } // } // } // public void Clear() // { // using (new WriteLock(ClearLock)) // { // _keyTracker.Clear(); // ClearDataCache(); // } // } // //DO not call this unless it's for testing since it clears the data cached but not the keys // internal void ClearDataCache() // { // if (_memoryCache != null) // { // _memoryCache.DisposeIfDisposable(); // _memoryCache = new MemoryCache("in-memory"); // } // else // { // foreach (DictionaryEntry c in HttpRuntime.Cache) // { // if (c.Key is string && ((string)c.Key).InvariantStartsWith(CacheItemPrefix)) // { // if (HttpRuntime.Cache[(string)c.Key] == null) return; // HttpRuntime.Cache.Remove((string)c.Key); // } // } // } // } // /// // /// We prefix all cache keys with this so that we know which ones this class has created when // /// using the HttpRuntime cache so that when we clear it we don't clear other entries we didn't create. // /// // private const string CacheItemPrefix = "umbrtmche_"; // private string GetCompositeId(Type type, Guid id) // { // return string.Format("{0}{1}-{2}", CacheItemPrefix, type.Name, id); // } // } //}