From b04d0fc886634cdcb5be83fd0ca384f73190e50b Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 6 Jan 2016 13:48:03 +0100 Subject: [PATCH 01/15] Adds Isolated cache to the CacheHelper, adds cache option: GetAllCacheAsCollection, changes the default repository cache to be an isolated cache (instead of part of the single main dictionary cache), adds the logic for the cache option GetAllCacheAsCollection to RepositoryBase, updates Language and Domain repositories to use GetAllCacheAsCollection, updates RepositoryFactory to be the one responsible for injecting a DeepCloneRuntimeCacheProvider and to use a single _noCache instance. --- src/Umbraco.Core/CacheHelper.cs | 103 ++++++++++-------- .../Repositories/DomainRepository.cs | 3 +- .../Repositories/LanguageRepository.cs | 3 +- .../Repositories/RepositoryBase.cs | 69 +++++++----- .../Repositories/RepositoryCacheOptions.cs | 11 ++ .../Persistence/RepositoryFactory.cs | 27 +++-- 6 files changed, 136 insertions(+), 80 deletions(-) diff --git a/src/Umbraco.Core/CacheHelper.cs b/src/Umbraco.Core/CacheHelper.cs index 51cf37aa23..44a0a35f2b 100644 --- a/src/Umbraco.Core/CacheHelper.cs +++ b/src/Umbraco.Core/CacheHelper.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; @@ -11,7 +12,6 @@ using Umbraco.Core.Logging; namespace Umbraco.Core { - /// /// Class that is exposed by the ApplicationContext for application wide caching purposes /// @@ -22,9 +22,10 @@ namespace Umbraco.Core private readonly ICacheProvider _nullRequestCache = new NullCacheProvider(); private readonly ICacheProvider _staticCache; private readonly ICacheProvider _nullStaticCache = new NullCacheProvider(); - private readonly IRuntimeCacheProvider _httpCache; - private readonly IRuntimeCacheProvider _nullHttpCache = new NullCacheProvider(); - + private readonly IRuntimeCacheProvider _runtimeCache; + private readonly IRuntimeCacheProvider _nullRuntimeCache = new NullCacheProvider(); + private readonly ConcurrentDictionary _isolatedCache = new ConcurrentDictionary(); + /// /// Creates a cache helper with disabled caches /// @@ -89,13 +90,13 @@ namespace Umbraco.Core { if (enableCache) { - _httpCache = httpCacheProvider; + _runtimeCache = httpCacheProvider; _staticCache = staticCacheProvider; _requestCache = requestCacheProvider; } else { - _httpCache = null; + _runtimeCache = null; _staticCache = null; _requestCache = null; } @@ -104,6 +105,22 @@ namespace Umbraco.Core } /// + /// Returns an isolated runtime cache for a given type + /// + /// + /// + /// + /// This is useful for repository level caches to ensure that cache lookups by key are fast so + /// that the repository doesn't need to search through all keys on a global scale. + /// + public IRuntimeCacheProvider GetIsolatedRuntimeCache() + { + return _enableCache == false + ? _nullRuntimeCache + : _isolatedCache.GetOrAdd(typeof (T), type => new ObjectCacheRuntimeCacheProvider()); + } + + /// /// Returns the current Request cache /// public ICacheProvider RequestCache @@ -124,7 +141,7 @@ namespace Umbraco.Core /// public IRuntimeCacheProvider RuntimeCache { - get { return _enableCache ? _httpCache : _nullHttpCache; } + get { return _enableCache ? _runtimeCache : _nullRuntimeCache; } } #region Legacy Runtime/Http Cache accessors @@ -137,11 +154,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.ClearAllCache(); + _nullRuntimeCache.ClearAllCache(); } else { - _httpCache.ClearAllCache(); + _runtimeCache.ClearAllCache(); } } @@ -154,11 +171,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.ClearCacheItem(key); + _nullRuntimeCache.ClearCacheItem(key); } else { - _httpCache.ClearCacheItem(key); + _runtimeCache.ClearCacheItem(key); } } @@ -173,11 +190,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.ClearCacheObjectTypes(typeName); + _nullRuntimeCache.ClearCacheObjectTypes(typeName); } else { - _httpCache.ClearCacheObjectTypes(typeName); + _runtimeCache.ClearCacheObjectTypes(typeName); } } @@ -189,11 +206,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.ClearCacheObjectTypes(); + _nullRuntimeCache.ClearCacheObjectTypes(); } else { - _httpCache.ClearCacheObjectTypes(); + _runtimeCache.ClearCacheObjectTypes(); } } @@ -206,11 +223,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.ClearCacheByKeySearch(keyStartsWith); + _nullRuntimeCache.ClearCacheByKeySearch(keyStartsWith); } else { - _httpCache.ClearCacheByKeySearch(keyStartsWith); + _runtimeCache.ClearCacheByKeySearch(keyStartsWith); } } @@ -223,11 +240,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.ClearCacheByKeyExpression(regexString); + _nullRuntimeCache.ClearCacheByKeyExpression(regexString); } else { - _httpCache.ClearCacheByKeyExpression(regexString); + _runtimeCache.ClearCacheByKeyExpression(regexString); } } @@ -236,11 +253,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - return _nullHttpCache.GetCacheItemsByKeySearch(keyStartsWith); + return _nullRuntimeCache.GetCacheItemsByKeySearch(keyStartsWith); } else { - return _httpCache.GetCacheItemsByKeySearch(keyStartsWith); + return _runtimeCache.GetCacheItemsByKeySearch(keyStartsWith); } } @@ -255,11 +272,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - return _nullHttpCache.GetCacheItem(cacheKey); + return _nullRuntimeCache.GetCacheItem(cacheKey); } else { - return _httpCache.GetCacheItem(cacheKey); + return _runtimeCache.GetCacheItem(cacheKey); } } @@ -275,11 +292,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - return _nullHttpCache.GetCacheItem(cacheKey, getCacheItem); + return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem); } else { - return _httpCache.GetCacheItem(cacheKey, getCacheItem); + return _runtimeCache.GetCacheItem(cacheKey, getCacheItem); } } @@ -297,11 +314,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - return _nullHttpCache.GetCacheItem(cacheKey, getCacheItem, timeout); + return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, timeout); } else { - return _httpCache.GetCacheItem(cacheKey, getCacheItem, timeout); + return _runtimeCache.GetCacheItem(cacheKey, getCacheItem, timeout); } } @@ -321,11 +338,11 @@ namespace Umbraco.Core { if (!_enableCache) { - return _nullHttpCache.GetCacheItem(cacheKey, getCacheItem, timeout, removedCallback: refreshAction); + return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, removedCallback: refreshAction); } else { - return _httpCache.GetCacheItem(cacheKey, getCacheItem, timeout, removedCallback: refreshAction); + return _runtimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, removedCallback: refreshAction); } } @@ -346,11 +363,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - return _nullHttpCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction); + return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction); } else { - return _httpCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction); + return _runtimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction); } } @@ -375,11 +392,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - return _nullHttpCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction, null); + return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction, null); } else { - var cache = _httpCache as HttpRuntimeCacheProvider; + var cache = _runtimeCache as HttpRuntimeCacheProvider; if (cache != null) { var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency); @@ -406,11 +423,11 @@ namespace Umbraco.Core { if (!_enableCache) { - return _nullHttpCache.GetCacheItem(cacheKey, getCacheItem, null, false, priority, null, null); + return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, null, false, priority, null, null); } else { - var cache = _httpCache as HttpRuntimeCacheProvider; + var cache = _runtimeCache as HttpRuntimeCacheProvider; if (cache != null) { var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), null, false, priority, null, cacheDependency); @@ -433,11 +450,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.InsertCacheItem(cacheKey, getCacheItem, priority: priority); + _nullRuntimeCache.InsertCacheItem(cacheKey, getCacheItem, priority: priority); } else { - _httpCache.InsertCacheItem(cacheKey, getCacheItem, priority: priority); + _runtimeCache.InsertCacheItem(cacheKey, getCacheItem, priority: priority); } } @@ -456,11 +473,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority); + _nullRuntimeCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority); } else { - _httpCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority); + _runtimeCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority); } } @@ -482,11 +499,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority, dependentFiles:null); + _nullRuntimeCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority, dependentFiles:null); } else { - var cache = _httpCache as HttpRuntimeCacheProvider; + var cache = _runtimeCache as HttpRuntimeCacheProvider; if (cache != null) { cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, null, cacheDependency); @@ -515,11 +532,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.InsertCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction, null); + _nullRuntimeCache.InsertCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction, null); } else { - var cache = _httpCache as HttpRuntimeCacheProvider; + var cache = _runtimeCache as HttpRuntimeCacheProvider; if (cache != null) { cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency); diff --git a/src/Umbraco.Core/Persistence/Repositories/DomainRepository.cs b/src/Umbraco.Core/Persistence/Repositories/DomainRepository.cs index 21ba8b4baf..75a592c7fe 100644 --- a/src/Umbraco.Core/Persistence/Repositories/DomainRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/DomainRepository.cs @@ -27,7 +27,8 @@ namespace Umbraco.Core.Persistence.Repositories _cacheOptions = new RepositoryCacheOptions { GetAllCacheAllowZeroCount = true, - GetAllCacheValidateCount = false + GetAllCacheValidateCount = false, + GetAllCacheAsCollection = true }; } diff --git a/src/Umbraco.Core/Persistence/Repositories/LanguageRepository.cs b/src/Umbraco.Core/Persistence/Repositories/LanguageRepository.cs index 2f379b4587..d1a28b7b4d 100644 --- a/src/Umbraco.Core/Persistence/Repositories/LanguageRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/LanguageRepository.cs @@ -25,7 +25,8 @@ namespace Umbraco.Core.Persistence.Repositories _cacheOptions = new RepositoryCacheOptions { GetAllCacheAllowZeroCount = true, - GetAllCacheValidateCount = false + GetAllCacheValidateCount = false, + GetAllCacheAsCollection = true }; } diff --git a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs index 124aaeb035..d5febf6e0f 100644 --- a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using Umbraco.Core.Cache; @@ -22,11 +23,7 @@ namespace Umbraco.Core.Persistence.Repositories if (logger == null) throw new ArgumentNullException("logger"); Logger = logger; _work = work; - - //IMPORTANT: We will force the DeepCloneRuntimeCacheProvider to be used here which is a wrapper for the underlying - // runtime cache to ensure that anything that can be deep cloned in/out is done so, this also ensures that our tracks - // changes entities are reset. - _cache = new CacheHelper(new DeepCloneRuntimeCacheProvider(cache.RuntimeCache), cache.StaticCache, cache.RequestCache); + _cache = cache; } /// @@ -86,7 +83,13 @@ namespace Umbraco.Core.Persistence.Repositories private readonly RepositoryCacheOptions _cacheOptions = new RepositoryCacheOptions(); - #region IRepository Members + /// + /// The runtime cache used for this repo by default is the isolated cache for this type + /// + protected override IRuntimeCacheProvider RuntimeCache + { + get { return RepositoryCache.GetIsolatedRuntimeCache(); } + } /// /// Adds or Updates an entity of type TEntity @@ -167,9 +170,18 @@ namespace Umbraco.Core.Persistence.Repositories } else { - var allEntities = RuntimeCache.GetCacheItemsByKeySearch(GetCacheTypeKey()) - .WhereNotNull() - .ToArray(); + TEntity[] allEntities; + if (RepositoryCacheOptions.GetAllCacheAsCollection) + { + var found = RuntimeCache.GetCacheItem>(GetCacheTypeKey()); + allEntities = found == null ? new TEntity[] {} : found.WhereNotNull().ToArray(); + } + else + { + allEntities = RuntimeCache.GetCacheItemsByKeySearch(GetCacheTypeKey()) + .WhereNotNull() + .ToArray(); + } if (allEntities.Any()) { @@ -205,21 +217,32 @@ namespace Umbraco.Core.Persistence.Repositories //ensure we don't include any null refs in the returned collection! .WhereNotNull() .ToArray(); - - //We need to put a threshold here! IF there's an insane amount of items - // coming back here we don't want to chuck it all into memory, this added cache here - // is more for convenience when paging stuff temporarily - - if (entityCollection.Length > RepositoryCacheOptions.GetAllCacheThresholdLimit) - return entityCollection; - + if (entityCollection.Length == 0 && RepositoryCacheOptions.GetAllCacheAllowZeroCount) { //there was nothing returned but we want to cache a zero count result so add an TEntity[] to the cache // to signify that there is a zero count cache RuntimeCache.InsertCacheItem(GetCacheTypeKey(), () => new TEntity[] {}); + return entityCollection; } + if (RepositoryCacheOptions.GetAllCacheAsCollection) + { + //when this is true, we don't want to cache each item individually, we want to cache the result as a single collection + RuntimeCache.InsertCacheItem(GetCacheTypeKey(), () => entityCollection.ToList()); + return entityCollection; + } + + if (entityCollection.Length > RepositoryCacheOptions.GetAllCacheThresholdLimit) + { + //We need to put a threshold here! IF there's an insane amount of items + // coming back here we don't want to chuck it all into memory, this added cache here + // is more for convenience when paging stuff temporarily + return entityCollection; + } + + //This is the default behavior, we'll individually cache each item so that if/when these items are resolved + // by id, they are returned from the already existing cache. foreach (var entity in entityCollection) { if (entity != null) @@ -279,11 +302,7 @@ namespace Umbraco.Core.Persistence.Repositories { return PerformCount(query); } - - #endregion - - #region IUnitOfWorkRepository Members - + /// /// Unit of work method that tells the repository to persist the new entity /// @@ -345,16 +364,12 @@ namespace Umbraco.Core.Persistence.Repositories //If there's a GetAll zero count cache, ensure it is cleared RuntimeCache.ClearCacheItem(GetCacheTypeKey()); } - - #endregion - - #region Abstract IUnitOfWorkRepository Methods + protected abstract void PersistNewItem(TEntity item); protected abstract void PersistUpdatedItem(TEntity item); protected abstract void PersistDeletedItem(TEntity item); - #endregion /// /// Dispose disposable properties diff --git a/src/Umbraco.Core/Persistence/Repositories/RepositoryCacheOptions.cs b/src/Umbraco.Core/Persistence/Repositories/RepositoryCacheOptions.cs index 9ac8aa6abd..b5abedac86 100644 --- a/src/Umbraco.Core/Persistence/Repositories/RepositoryCacheOptions.cs +++ b/src/Umbraco.Core/Persistence/Repositories/RepositoryCacheOptions.cs @@ -10,6 +10,7 @@ namespace Umbraco.Core.Persistence.Repositories GetAllCacheValidateCount = true; GetAllCacheAllowZeroCount = false; GetAllCacheThresholdLimit = 100; + GetAllCacheAsCollection = false; } /// @@ -32,5 +33,15 @@ namespace Umbraco.Core.Persistence.Repositories /// The threshold entity count for which the GetAll method will cache entities /// public int GetAllCacheThresholdLimit { get; set; } + + /// + /// When set to true, the cache for the result of GetAll will be cached as a List/Collection rather than + /// individual entities in the dictionary + /// + /// + /// The default is false which means that if the result of GetAll is less than the GetAllCacheThresholdLimit, each entity + /// returned will be cached individually + /// + public bool GetAllCacheAsCollection { get; set; } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/RepositoryFactory.cs b/src/Umbraco.Core/Persistence/RepositoryFactory.cs index a22b2511ea..f3d1702946 100644 --- a/src/Umbraco.Core/Persistence/RepositoryFactory.cs +++ b/src/Umbraco.Core/Persistence/RepositoryFactory.cs @@ -18,6 +18,7 @@ namespace Umbraco.Core.Persistence private readonly ILogger _logger; private readonly ISqlSyntaxProvider _sqlSyntax; private readonly CacheHelper _cacheHelper; + private readonly CacheHelper _noCache; private readonly IUmbracoSettingsSection _settings; #region Ctors @@ -30,6 +31,15 @@ namespace Umbraco.Core.Persistence if (settings == null) throw new ArgumentNullException("settings"); _cacheHelper = cacheHelper; + //IMPORTANT: We will force the DeepCloneRuntimeCacheProvider to be used here which is a wrapper for the underlying + // runtime cache to ensure that anything that can be deep cloned in/out is done so, this also ensures that our tracks + // changes entities are reset. + if ((_cacheHelper.RuntimeCache is DeepCloneRuntimeCacheProvider) == false) + { + _cacheHelper = new CacheHelper(new DeepCloneRuntimeCacheProvider(_cacheHelper.RuntimeCache), _cacheHelper.StaticCache, _cacheHelper.RequestCache); + } + + _noCache = CacheHelper.CreateDisabledCacheHelper(); _logger = logger; _sqlSyntax = sqlSyntax; _settings = settings; @@ -53,6 +63,7 @@ namespace Umbraco.Core.Persistence { if (cacheHelper == null) throw new ArgumentNullException("cacheHelper"); _cacheHelper = cacheHelper; + _noCache = CacheHelper.CreateDisabledCacheHelper(); } [Obsolete("Use the ctor specifying all dependencies instead")] @@ -80,15 +91,15 @@ namespace Umbraco.Core.Persistence public virtual ITaskRepository CreateTaskRepository(IDatabaseUnitOfWork uow) { - return new TaskRepository(uow, - CacheHelper.CreateDisabledCacheHelper(), //never cache + return new TaskRepository(uow, + _noCache, //never cache _logger, _sqlSyntax); } public virtual IAuditRepository CreateAuditRepository(IDatabaseUnitOfWork uow) { return new AuditRepository(uow, - CacheHelper.CreateDisabledCacheHelper(), //never cache + _noCache, //never cache _logger, _sqlSyntax); } @@ -175,7 +186,7 @@ namespace Umbraco.Core.Persistence { return new RelationRepository( uow, - CacheHelper.CreateDisabledCacheHelper(), //never cache + _noCache, //never cache _logger, _sqlSyntax, CreateRelationTypeRepository(uow)); } @@ -184,7 +195,7 @@ namespace Umbraco.Core.Persistence { return new RelationTypeRepository( uow, - CacheHelper.CreateDisabledCacheHelper(), //never cache + _noCache, //never cache _logger, _sqlSyntax); } @@ -222,7 +233,7 @@ namespace Umbraco.Core.Persistence { return new MigrationEntryRepository( uow, - CacheHelper.CreateDisabledCacheHelper(), //never cache + _noCache, //never cache _logger, _sqlSyntax); } @@ -299,8 +310,8 @@ namespace Umbraco.Core.Persistence public ITaskTypeRepository CreateTaskTypeRepository(IDatabaseUnitOfWork uow) { - return new TaskTypeRepository(uow, - CacheHelper.CreateDisabledCacheHelper(), //never cache + return new TaskTypeRepository(uow, + _noCache, //never cache _logger, _sqlSyntax); } } From 4f40fff5ee009a3830bb8770aa5ab66fe04be6ca Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 6 Jan 2016 14:17:51 +0100 Subject: [PATCH 02/15] Moves DeepCloneRuntimeCacheProvider to Cache namespace. Creates DeepCloneableList + tests. Updates RepositoryBase to use DeepCloneableList when GetAllCacheAsCollection is used (so that all entries that get cached are deep cloned into and out-of the cache). Adds test for DeepCloneRuntimeCacheProvider for dealing with this list type. --- .../DeepCloneRuntimeCacheProvider.cs | 3 +- .../Collections/DeepCloneableList.cs | 108 ++++++++++++++ .../Repositories/RepositoryBase.cs | 5 +- .../Persistence/RepositoryFactory.cs | 1 + src/Umbraco.Core/Umbraco.Core.csproj | 3 +- .../DeepCloneRuntimeCacheProviderTests.cs | 19 +++ .../Collections/DeepCloneableListTests.cs | 139 ++++++++++++++++++ src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + 8 files changed, 274 insertions(+), 5 deletions(-) rename src/Umbraco.Core/{Persistence/Repositories => Cache}/DeepCloneRuntimeCacheProvider.cs (98%) create mode 100644 src/Umbraco.Core/Collections/DeepCloneableList.cs create mode 100644 src/Umbraco.Tests/Collections/DeepCloneableListTests.cs diff --git a/src/Umbraco.Core/Persistence/Repositories/DeepCloneRuntimeCacheProvider.cs b/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs similarity index 98% rename from src/Umbraco.Core/Persistence/Repositories/DeepCloneRuntimeCacheProvider.cs rename to src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs index 0b5b42660d..861c6b803e 100644 --- a/src/Umbraco.Core/Persistence/Repositories/DeepCloneRuntimeCacheProvider.cs +++ b/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs @@ -2,11 +2,10 @@ using System; using System.Collections.Generic; using System.Linq; using System.Web.Caching; -using Umbraco.Core.Cache; using Umbraco.Core.Models; using Umbraco.Core.Models.EntityBase; -namespace Umbraco.Core.Persistence.Repositories +namespace Umbraco.Core.Cache { /// /// A wrapper for any IRuntimeCacheProvider that ensures that all inserts and returns diff --git a/src/Umbraco.Core/Collections/DeepCloneableList.cs b/src/Umbraco.Core/Collections/DeepCloneableList.cs new file mode 100644 index 0000000000..365bf53b06 --- /dev/null +++ b/src/Umbraco.Core/Collections/DeepCloneableList.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Umbraco.Core.Models; +using Umbraco.Core.Models.EntityBase; + +namespace Umbraco.Core.Collections +{ + /// + /// A List that can be deep cloned with deep cloned elements and can reset the collection's items dirty flags + /// + /// + internal class DeepCloneableList : List, IDeepCloneable, IRememberBeingDirty + { + /// + /// Initializes a new instance of the class that is empty and has the default initial capacity. + /// + public DeepCloneableList() + { + } + + /// + /// Initializes a new instance of the class that contains elements copied from the specified collection and has sufficient capacity to accommodate the number of elements copied. + /// + /// The collection whose elements are copied to the new list. is null. + public DeepCloneableList(IEnumerable collection) : base(collection) + { + } + + /// + /// Creates a new list and adds each element as a deep cloned element if it is of type IDeepCloneable + /// + /// + public object DeepClone() + { + var newList = new DeepCloneableList(); + foreach (var item in this) + { + var dc = item as IDeepCloneable; + if (dc != null) + { + newList.Add((T) dc.DeepClone()); + } + else + { + newList.Add(item); + } + } + return newList; + } + + public bool IsDirty() + { + return this.OfType().Any(x => x.IsDirty()); + } + + public bool WasDirty() + { + return this.OfType().Any(x => x.WasDirty()); + } + + /// + /// Always returns false, the list has no properties we need to report + /// + /// + /// + public bool IsPropertyDirty(string propName) + { + return false; + } + + /// + /// Always returns false, the list has no properties we need to report + /// + /// + /// + public bool WasPropertyDirty(string propertyName) + { + return false; + } + + public void ResetDirtyProperties() + { + foreach (var dc in this.OfType()) + { + dc.ResetDirtyProperties(); + } + } + + public void ForgetPreviouslyDirtyProperties() + { + foreach (var dc in this.OfType()) + { + dc.ForgetPreviouslyDirtyProperties(); + } + } + + public void ResetDirtyProperties(bool rememberPreviouslyChangedProperties) + { + foreach (var dc in this.OfType()) + { + dc.ResetDirtyProperties(rememberPreviouslyChangedProperties); + } + } + } +} diff --git a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs index d5febf6e0f..2ce3537bb9 100644 --- a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; using Umbraco.Core.Cache; +using Umbraco.Core.Collections; using Umbraco.Core.Logging; using Umbraco.Core.Models.EntityBase; @@ -173,7 +174,7 @@ namespace Umbraco.Core.Persistence.Repositories TEntity[] allEntities; if (RepositoryCacheOptions.GetAllCacheAsCollection) { - var found = RuntimeCache.GetCacheItem>(GetCacheTypeKey()); + var found = RuntimeCache.GetCacheItem>(GetCacheTypeKey()); allEntities = found == null ? new TEntity[] {} : found.WhereNotNull().ToArray(); } else @@ -229,7 +230,7 @@ namespace Umbraco.Core.Persistence.Repositories if (RepositoryCacheOptions.GetAllCacheAsCollection) { //when this is true, we don't want to cache each item individually, we want to cache the result as a single collection - RuntimeCache.InsertCacheItem(GetCacheTypeKey(), () => entityCollection.ToList()); + RuntimeCache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList(entityCollection)); return entityCollection; } diff --git a/src/Umbraco.Core/Persistence/RepositoryFactory.cs b/src/Umbraco.Core/Persistence/RepositoryFactory.cs index f3d1702946..d99ae8f464 100644 --- a/src/Umbraco.Core/Persistence/RepositoryFactory.cs +++ b/src/Umbraco.Core/Persistence/RepositoryFactory.cs @@ -1,5 +1,6 @@ using Umbraco.Core.Configuration; using System; +using Umbraco.Core.Cache; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.IO; using Umbraco.Core.Logging; diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index bf28645754..d294bdaddf 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -176,6 +176,7 @@ + @@ -441,7 +442,7 @@ - + diff --git a/src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs b/src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs index 44deb1da40..63225f6725 100644 --- a/src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs +++ b/src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs @@ -4,9 +4,11 @@ using System.Web; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; +using Umbraco.Core.Collections; using Umbraco.Core.Models; using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Persistence.Repositories; +using Umbraco.Tests.Collections; namespace Umbraco.Tests.Cache { @@ -36,6 +38,23 @@ namespace Umbraco.Tests.Cache get { return _provider; } } + [Test] + public void Clones_List() + { + var original = new DeepCloneableList(); + original.Add(new DeepCloneableListTests.TestClone()); + original.Add(new DeepCloneableListTests.TestClone()); + original.Add(new DeepCloneableListTests.TestClone()); + + var val = _provider.GetCacheItem>("test", () => original); + + Assert.AreEqual(original.Count, val.Count); + foreach (var item in val) + { + Assert.IsTrue(item.IsClone); + } + } + [Test] public void Ensures_Cloned_And_Reset() { diff --git a/src/Umbraco.Tests/Collections/DeepCloneableListTests.cs b/src/Umbraco.Tests/Collections/DeepCloneableListTests.cs new file mode 100644 index 0000000000..fcc50df60c --- /dev/null +++ b/src/Umbraco.Tests/Collections/DeepCloneableListTests.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NUnit.Framework; +using Umbraco.Core.Collections; +using Umbraco.Core.Models; + +namespace Umbraco.Tests.Collections +{ + [TestFixture] + public class DeepCloneableListTests + { + [Test] + public void Deep_Clones_All_Elements() + { + var list = new DeepCloneableList(); + list.Add(new TestClone()); + list.Add(new TestClone()); + list.Add(new TestClone()); + + var cloned = list.DeepClone() as DeepCloneableList; + + Assert.IsNotNull(cloned); + Assert.AreNotSame(list, cloned); + Assert.AreEqual(list.Count, cloned.Count); + } + + [Test] + public void Clones_Each_Item() + { + var list = new DeepCloneableList(); + list.Add(new TestClone()); + list.Add(new TestClone()); + list.Add(new TestClone()); + + var cloned = (DeepCloneableList) list.DeepClone(); + + foreach (var item in cloned) + { + Assert.IsTrue(item.IsClone); + } + } + + [Test] + public void Cloned_Sequence_Equals() + { + var list = new DeepCloneableList(); + list.Add(new TestClone()); + list.Add(new TestClone()); + list.Add(new TestClone()); + + var cloned = (DeepCloneableList)list.DeepClone(); + + //Test that each item in the sequence is equal - based on the equality comparer of TestClone (i.e. it's ID) + Assert.IsTrue(list.SequenceEqual(cloned)); + + //Test that each instance in the list is not the same one + foreach (var item in list) + { + var clone = cloned.Single(x => x.Id == item.Id); + Assert.AreNotSame(item, clone); + } + } + + public class TestClone : IDeepCloneable, IEquatable + { + public TestClone(Guid id) + { + Id = id; + IsClone = true; + } + + public TestClone() + { + Id = Guid.NewGuid(); + } + + public Guid Id { get; private set; } + public bool IsClone { get; private set; } + + public object DeepClone() + { + return new TestClone(Id); + } + + /// + /// Indicates whether the current object is equal to another object of the same type. + /// + /// + /// true if the current object is equal to the parameter; otherwise, false. + /// + /// An object to compare with this object. + public bool Equals(TestClone other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Id.Equals(other.Id); + } + + /// + /// Determines whether the specified object is equal to the current object. + /// + /// + /// true if the specified object is equal to the current object; otherwise, false. + /// + /// The object to compare with the current object. + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((TestClone)obj); + } + + /// + /// Serves as the default hash function. + /// + /// + /// A hash code for the current object. + /// + public override int GetHashCode() + { + return Id.GetHashCode(); + } + + public static bool operator ==(TestClone left, TestClone right) + { + return Equals(left, right); + } + + public static bool operator !=(TestClone left, TestClone right) + { + return Equals(left, right) == false; + } + } + } +} diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 59a9166e5a..e689fe08f9 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -175,6 +175,7 @@ + From ff829d49a3faa0dfe2a8876052ed30f003a087bc Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 6 Jan 2016 18:08:14 +0100 Subject: [PATCH 03/15] Updates all cache refreshers to reference the IsolatedRuntimeCache where required, refactors how IsolatedRuntimeCache is exposed on the CacheHelper, ensures that IsolatedRuntimeCache is used in all repositories instead of the global RuntimeCache, changes all obsolete usages of CacheHelper to the non obsolete equivalent, obsoletes many of the cache keys, obsoletes a couple cache refreshers that aren't used anymore in 7.3, simplifies CacheHelper with regards to it's 'disabled' cache state. --- src/Umbraco.Core/ApplicationContext.cs | 3 +- src/Umbraco.Core/Cache/CacheKeys.cs | 31 +- src/Umbraco.Core/Cache/CacheRefresherBase.cs | 11 + .../Cache/IsolatedRuntimeCache.cs | 91 +++++ src/Umbraco.Core/CacheHelper.cs | 313 ++++++------------ src/Umbraco.Core/CoreBootManager.cs | 10 +- .../DataTypeDefinitionRepository.cs | 14 +- .../Repositories/MemberGroupRepository.cs | 8 +- .../Repositories/PermissionRepository.cs | 7 +- .../Repositories/RepositoryBase.cs | 2 +- .../Persistence/RepositoryFactory.cs | 20 +- .../Services/ApplicationTreeService.cs | 2 +- src/Umbraco.Core/Services/SectionService.cs | 2 +- src/Umbraco.Core/Services/ServiceContext.cs | 1 + src/Umbraco.Core/Umbraco.Core.csproj | 1 + src/Umbraco.Tests/Macros/MacroTests.cs | 13 +- .../DataTypeDefinitionRepositoryTest.cs | 23 +- .../Repositories/MemberRepositoryTest.cs | 2 +- .../Cache/ApplicationCacheRefresher.cs | 4 +- .../Cache/ApplicationTreeCacheRefresher.cs | 4 +- .../Cache/ContentTypeCacheRefresher.cs | 22 +- .../Cache/DataTypeCacheRefresher.cs | 25 +- .../Cache/DictionaryCacheRefresher.cs | 4 +- src/Umbraco.Web/Cache/DistributedCache.cs | 3 + .../Cache/DistributedCacheExtensions.cs | 2 +- src/Umbraco.Web/Cache/DomainCacheRefresher.cs | 4 +- .../Cache/LanguageCacheRefresher.cs | 4 +- src/Umbraco.Web/Cache/MacroCacheRefresher.cs | 8 +- src/Umbraco.Web/Cache/MediaCacheRefresher.cs | 58 ++-- src/Umbraco.Web/Cache/MemberCacheRefresher.cs | 4 +- .../Cache/MemberGroupCacheRefresher.cs | 8 +- src/Umbraco.Web/Cache/PageCacheRefresher.cs | 6 +- .../Cache/PublicAccessCacheRefresher.cs | 8 +- .../Cache/StylesheetCacheRefresher.cs | 25 +- .../Cache/StylesheetPropertyCacheRefresher.cs | 27 +- .../Cache/TemplateCacheRefresher.cs | 6 +- .../Cache/UnpublishedPageCacheRefresher.cs | 33 +- src/Umbraco.Web/Cache/UserCacheRefresher.cs | 24 +- .../Cache/UserPermissionsCacheRefresher.cs | 12 +- .../Cache/UserTypeCacheRefresher.cs | 10 +- src/Umbraco.Web/CacheHelperExtensions.cs | 2 +- src/Umbraco.Web/Media/ImageUrl.cs | 2 +- .../umbraco.presentation/content.cs | 2 +- .../umbraco.presentation/library.cs | 12 +- src/Umbraco.Web/umbraco.presentation/macro.cs | 32 +- .../umbraco.presentation/template.cs | 2 +- .../developer/Packages/LoadNitros.ascx.cs | 3 +- .../umbraco/templateControls/ItemRenderer.cs | 10 +- src/umbraco.businesslogic/User.cs | 2 +- src/umbraco.cms/businesslogic/ContentType.cs | 20 +- src/umbraco.cms/businesslogic/cache/Cache.cs | 8 +- src/umbraco.cms/businesslogic/macro/Macro.cs | 12 +- .../businesslogic/member/Member.cs | 16 +- .../propertytype/propertytype.cs | 44 +-- src/umbraco.cms/businesslogic/web/Document.cs | 2 +- 55 files changed, 527 insertions(+), 497 deletions(-) create mode 100644 src/Umbraco.Core/Cache/IsolatedRuntimeCache.cs diff --git a/src/Umbraco.Core/ApplicationContext.cs b/src/Umbraco.Core/ApplicationContext.cs index a05abe2a50..e47ef04650 100644 --- a/src/Umbraco.Core/ApplicationContext.cs +++ b/src/Umbraco.Core/ApplicationContext.cs @@ -406,7 +406,8 @@ namespace Umbraco.Core //clear the cache if (ApplicationCache != null) { - ApplicationCache.ClearAllCache(); + ApplicationCache.RuntimeCache.ClearAllCache(); + ApplicationCache.IsolatedRuntimeCache.ClearAllCaches(); } //reset all resolvers ResolverCollection.ResetAll(); diff --git a/src/Umbraco.Core/Cache/CacheKeys.cs b/src/Umbraco.Core/Cache/CacheKeys.cs index 88d570beff..0c1a202b66 100644 --- a/src/Umbraco.Core/Cache/CacheKeys.cs +++ b/src/Umbraco.Core/Cache/CacheKeys.cs @@ -1,8 +1,9 @@ using System; +using System.ComponentModel; +using Umbraco.Core.CodeAnnotations; namespace Umbraco.Core.Cache { - /// /// Constants storing cache keys used in caching /// @@ -12,52 +13,78 @@ namespace Umbraco.Core.Cache public const string ApplicationsCacheKey = "ApplicationCache"; [Obsolete("This is no longer used and will be removed from the codebase in the future")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string UserTypeCacheKey = "UserTypeCache"; + [Obsolete("This is no longer used and will be removed from the codebase in the future - it is referenced but no cache is stored against this key")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string ContentItemCacheKey = "contentItem"; + [UmbracoWillObsolete("This cache key is only used for the legacy 'library' caching, remove in v8")] public const string MediaCacheKey = "UL_GetMedia"; public const string MacroXsltCacheKey = "macroXslt_"; + + [UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")] public const string MacroCacheKey = "UmbracoMacroCache"; + public const string MacroHtmlCacheKey = "macroHtml_"; public const string MacroControlCacheKey = "macroControl_"; public const string MacroHtmlDateAddedCacheKey = "macroHtml_DateAdded_"; public const string MacroControlDateAddedCacheKey = "macroControl_DateAdded_"; + [UmbracoWillObsolete("This cache key is only used for legacy 'library' member caching, remove in v8")] public const string MemberLibraryCacheKey = "UL_GetMember"; + + [UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")] public const string MemberBusinessLogicCacheKey = "MemberCacheItem_"; - + + [UmbracoWillObsolete("This cache key is only used for legacy template business logic caching, remove in v8")] public const string TemplateFrontEndCacheKey = "template"; [Obsolete("This is no longer used and will be removed from the codebase in the future")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string TemplateBusinessLogicCacheKey = "UmbracoTemplateCache"; + [Obsolete("This is no longer used and will be removed from the codebase in the future")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string UserContextCacheKey = "UmbracoUserContext"; + public const string UserContextTimeoutCacheKey = "UmbracoUserContextTimeout"; [Obsolete("This is no longer used and will be removed from the codebase in the future")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string UserCacheKey = "UmbracoUser"; public const string UserPermissionsCacheKey = "UmbracoUserPermissions"; + [UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")] public const string ContentTypeCacheKey = "UmbracoContentType"; + [UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")] public const string ContentTypePropertiesCacheKey = "ContentType_PropertyTypes_Content:"; + [UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")] public const string PropertyTypeCacheKey = "UmbracoPropertyTypeCache"; [Obsolete("This is no longer used and will be removed from the codebase in the future")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string LanguageCacheKey = "UmbracoLanguageCache"; [Obsolete("This is no longer used and will be removed from the codebase in the future")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string DomainCacheKey = "UmbracoDomainList"; [Obsolete("This is no longer used and will be removed from the codebase in the future")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string StylesheetCacheKey = "UmbracoStylesheet"; + [Obsolete("This is no longer used and will be removed from the codebase in the future")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string StylesheetPropertyCacheKey = "UmbracoStylesheetProperty"; + [Obsolete("This is no longer used and will be removed from the codebase in the future")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string DataTypeCacheKey = "UmbracoDataTypeDefinition"; public const string DataTypePreValuesCacheKey = "UmbracoPreVal"; diff --git a/src/Umbraco.Core/Cache/CacheRefresherBase.cs b/src/Umbraco.Core/Cache/CacheRefresherBase.cs index 2931805b08..2ee7873ad0 100644 --- a/src/Umbraco.Core/Cache/CacheRefresherBase.cs +++ b/src/Umbraco.Core/Cache/CacheRefresherBase.cs @@ -2,6 +2,7 @@ using Umbraco.Core.Events; using Umbraco.Core.Sync; using umbraco.interfaces; +using Umbraco.Core.Models.EntityBase; namespace Umbraco.Core.Cache { @@ -63,5 +64,15 @@ namespace Umbraco.Core.Cache { OnCacheUpdated(Instance, new CacheRefresherEventArgs(id, MessageType.RefreshById)); } + + /// + /// Clears the cache for all repository entities of this type + /// + /// + protected void ClearAllCacheByRepositoryEntityType() + where TEntity : class, IAggregateRoot + { + ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.ClearCache(); + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Cache/IsolatedRuntimeCache.cs b/src/Umbraco.Core/Cache/IsolatedRuntimeCache.cs new file mode 100644 index 0000000000..103f90345d --- /dev/null +++ b/src/Umbraco.Core/Cache/IsolatedRuntimeCache.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Concurrent; + +namespace Umbraco.Core.Cache +{ + /// + /// Used to get/create/manipulate isolated runtime cache + /// + /// + /// This is useful for repository level caches to ensure that cache lookups by key are fast so + /// that the repository doesn't need to search through all keys on a global scale. + /// + public class IsolatedRuntimeCache + { + private readonly Func _cacheFactory; + + /// + /// Constructor that allows specifying a factory for the type of runtime isolated cache to create + /// + /// + public IsolatedRuntimeCache(Func cacheFactory) + { + _cacheFactory = cacheFactory; + } + + private readonly ConcurrentDictionary _isolatedCache = new ConcurrentDictionary(); + + /// + /// Returns an isolated runtime cache for a given type + /// + /// + /// + public IRuntimeCacheProvider GetOrCreateCache() + { + return _isolatedCache.GetOrAdd(typeof(T), type => _cacheFactory(type)); + } + + /// + /// Returns an isolated runtime cache for a given type + /// + /// + public IRuntimeCacheProvider GetOrCreateCache(Type type) + { + return _isolatedCache.GetOrAdd(type, t => _cacheFactory(t)); + } + + /// + /// Tries to get a cache by the type specified + /// + /// + /// + public Attempt GetCache() + { + IRuntimeCacheProvider cache; + if (_isolatedCache.TryGetValue(typeof(T), out cache)) + { + return Attempt.Succeed(cache); + } + return Attempt.Fail(); + } + + /// + /// Clears all values inside this isolated runtime cache + /// + /// + /// + public void ClearCache() + { + IRuntimeCacheProvider cache; + if (_isolatedCache.TryGetValue(typeof(T), out cache)) + { + cache.ClearAllCache(); + } + } + + /// + /// Clears all of the isolated caches + /// + public void ClearAllCaches() + { + foreach (var key in _isolatedCache.Keys) + { + IRuntimeCacheProvider cache; + if (_isolatedCache.TryRemove(key, out cache)) + { + cache.ClearAllCache(); + } + } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/CacheHelper.cs b/src/Umbraco.Core/CacheHelper.cs index 44a0a35f2b..303cf234fd 100644 --- a/src/Umbraco.Core/CacheHelper.cs +++ b/src/Umbraco.Core/CacheHelper.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Text; using System.Text.RegularExpressions; @@ -17,14 +18,13 @@ namespace Umbraco.Core /// public class CacheHelper { - private readonly bool _enableCache; + private readonly IsolatedRuntimeCache _isolatedCacheManager; private readonly ICacheProvider _requestCache; - private readonly ICacheProvider _nullRequestCache = new NullCacheProvider(); + private static readonly ICacheProvider NullRequestCache = new NullCacheProvider(); private readonly ICacheProvider _staticCache; - private readonly ICacheProvider _nullStaticCache = new NullCacheProvider(); + private static readonly ICacheProvider NullStaticCache = new NullCacheProvider(); private readonly IRuntimeCacheProvider _runtimeCache; - private readonly IRuntimeCacheProvider _nullRuntimeCache = new NullCacheProvider(); - private readonly ConcurrentDictionary _isolatedCache = new ConcurrentDictionary(); + private static readonly IRuntimeCacheProvider NullRuntimeCache = new NullCacheProvider(); /// /// Creates a cache helper with disabled caches @@ -35,7 +35,7 @@ namespace Umbraco.Core /// public static CacheHelper CreateDisabledCacheHelper() { - return new CacheHelper(null, null, null, false); + return new CacheHelper(NullRuntimeCache, NullStaticCache, NullRequestCache, new IsolatedRuntimeCache(t => NullRuntimeCache)); } /// @@ -45,7 +45,8 @@ namespace Umbraco.Core : this( new HttpRuntimeCacheProvider(HttpRuntime.Cache), new StaticCacheProvider(), - new HttpRequestCacheProvider()) + new HttpRequestCacheProvider(), + new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider())) { } @@ -57,83 +58,58 @@ namespace Umbraco.Core : this( new HttpRuntimeCacheProvider(cache), new StaticCacheProvider(), - new HttpRequestCacheProvider()) + new HttpRequestCacheProvider(), + new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider())) { } - /// - /// Initializes a new instance based on the provided providers - /// - /// - /// - /// + [Obsolete("Use the constructor the specifies all dependencies")] + [EditorBrowsable(EditorBrowsableState.Never)] public CacheHelper( IRuntimeCacheProvider httpCacheProvider, ICacheProvider staticCacheProvider, ICacheProvider requestCacheProvider) - : this(httpCacheProvider, staticCacheProvider, requestCacheProvider, true) + : this(httpCacheProvider, staticCacheProvider, requestCacheProvider, new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider())) { } - /// - /// Private ctor used for creating a disabled cache helper - /// - /// - /// - /// - /// - private CacheHelper( + /// + /// Initializes a new instance based on the provided providers + /// + /// + /// + /// + /// + public CacheHelper( IRuntimeCacheProvider httpCacheProvider, ICacheProvider staticCacheProvider, - ICacheProvider requestCacheProvider, - bool enableCache) + ICacheProvider requestCacheProvider, + IsolatedRuntimeCache isolatedCacheManager) { - if (enableCache) - { - _runtimeCache = httpCacheProvider; - _staticCache = staticCacheProvider; - _requestCache = requestCacheProvider; - } - else - { - _runtimeCache = null; - _staticCache = null; - _requestCache = null; - } - - _enableCache = enableCache; + if (httpCacheProvider == null) throw new ArgumentNullException("httpCacheProvider"); + if (staticCacheProvider == null) throw new ArgumentNullException("staticCacheProvider"); + if (requestCacheProvider == null) throw new ArgumentNullException("requestCacheProvider"); + if (isolatedCacheManager == null) throw new ArgumentNullException("isolatedCacheManager"); + _runtimeCache = httpCacheProvider; + _staticCache = staticCacheProvider; + _requestCache = requestCacheProvider; + _isolatedCacheManager = isolatedCacheManager; } /// - /// Returns an isolated runtime cache for a given type - /// - /// - /// - /// - /// This is useful for repository level caches to ensure that cache lookups by key are fast so - /// that the repository doesn't need to search through all keys on a global scale. - /// - public IRuntimeCacheProvider GetIsolatedRuntimeCache() - { - return _enableCache == false - ? _nullRuntimeCache - : _isolatedCache.GetOrAdd(typeof (T), type => new ObjectCacheRuntimeCacheProvider()); - } - - /// /// Returns the current Request cache /// public ICacheProvider RequestCache { - get { return _enableCache ? _requestCache : _nullRequestCache; } + get { return _requestCache; } } - + /// /// Returns the current Runtime cache /// public ICacheProvider StaticCache { - get { return _enableCache ? _staticCache : _nullStaticCache; } + get { return _staticCache; } } /// @@ -141,8 +117,16 @@ namespace Umbraco.Core /// public IRuntimeCacheProvider RuntimeCache { - get { return _enableCache ? _runtimeCache : _nullRuntimeCache; } + get { return _runtimeCache; } } + + /// + /// Returns the current Isolated Runtime cache manager + /// + public IsolatedRuntimeCache IsolatedRuntimeCache + { + get { return _isolatedCacheManager; } + } #region Legacy Runtime/Http Cache accessors @@ -150,16 +134,11 @@ namespace Umbraco.Core /// Clears the item in umbraco's runtime cache /// [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public void ClearAllCache() { - if (_enableCache == false) - { - _nullRuntimeCache.ClearAllCache(); - } - else - { - _runtimeCache.ClearAllCache(); - } + _runtimeCache.ClearAllCache(); + _isolatedCacheManager.ClearAllCaches(); } /// @@ -167,16 +146,10 @@ namespace Umbraco.Core /// /// Key [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public void ClearCacheItem(string key) { - if (_enableCache == false) - { - _nullRuntimeCache.ClearCacheItem(key); - } - else - { - _runtimeCache.ClearCacheItem(key); - } + _runtimeCache.ClearCacheItem(key); } @@ -188,30 +161,17 @@ namespace Umbraco.Core [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] public void ClearCacheObjectTypes(string typeName) { - if (_enableCache == false) - { - _nullRuntimeCache.ClearCacheObjectTypes(typeName); - } - else - { - _runtimeCache.ClearCacheObjectTypes(typeName); - } + _runtimeCache.ClearCacheObjectTypes(typeName); } /// /// Clears all objects in the System.Web.Cache with the System.Type specified /// [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public void ClearCacheObjectTypes() { - if (_enableCache == false) - { - _nullRuntimeCache.ClearCacheObjectTypes(); - } - else - { - _runtimeCache.ClearCacheObjectTypes(); - } + _runtimeCache.ClearCacheObjectTypes(); } /// @@ -219,16 +179,10 @@ namespace Umbraco.Core /// /// The start of the key [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public void ClearCacheByKeySearch(string keyStartsWith) { - if (_enableCache == false) - { - _nullRuntimeCache.ClearCacheByKeySearch(keyStartsWith); - } - else - { - _runtimeCache.ClearCacheByKeySearch(keyStartsWith); - } + _runtimeCache.ClearCacheByKeySearch(keyStartsWith); } /// @@ -236,29 +190,17 @@ namespace Umbraco.Core /// /// [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public void ClearCacheByKeyExpression(string regexString) { - if (_enableCache == false) - { - _nullRuntimeCache.ClearCacheByKeyExpression(regexString); - } - else - { - _runtimeCache.ClearCacheByKeyExpression(regexString); - } + _runtimeCache.ClearCacheByKeyExpression(regexString); } [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public IEnumerable GetCacheItemsByKeySearch(string keyStartsWith) { - if (_enableCache == false) - { - return _nullRuntimeCache.GetCacheItemsByKeySearch(keyStartsWith); - } - else - { - return _runtimeCache.GetCacheItemsByKeySearch(keyStartsWith); - } + return _runtimeCache.GetCacheItemsByKeySearch(keyStartsWith); } /// @@ -268,16 +210,10 @@ namespace Umbraco.Core /// /// [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public TT GetCacheItem(string cacheKey) { - if (_enableCache == false) - { - return _nullRuntimeCache.GetCacheItem(cacheKey); - } - else - { - return _runtimeCache.GetCacheItem(cacheKey); - } + return _runtimeCache.GetCacheItem(cacheKey); } /// @@ -288,16 +224,11 @@ namespace Umbraco.Core /// /// [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public TT GetCacheItem(string cacheKey, Func getCacheItem) { - if (_enableCache == false) - { - return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem); - } - else - { - return _runtimeCache.GetCacheItem(cacheKey, getCacheItem); - } + return _runtimeCache.GetCacheItem(cacheKey, getCacheItem); + } /// @@ -309,17 +240,12 @@ namespace Umbraco.Core /// /// [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public TT GetCacheItem(string cacheKey, TimeSpan timeout, Func getCacheItem) { - if (_enableCache == false) - { - return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, timeout); - } - else - { - return _runtimeCache.GetCacheItem(cacheKey, getCacheItem, timeout); - } + return _runtimeCache.GetCacheItem(cacheKey, getCacheItem, timeout); + } /// @@ -332,18 +258,13 @@ namespace Umbraco.Core /// /// [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public TT GetCacheItem(string cacheKey, CacheItemRemovedCallback refreshAction, TimeSpan timeout, Func getCacheItem) { - if (!_enableCache) - { - return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, removedCallback: refreshAction); - } - else - { - return _runtimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, removedCallback: refreshAction); - } + return _runtimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, removedCallback: refreshAction); + } /// @@ -357,18 +278,13 @@ namespace Umbraco.Core /// /// [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public TT GetCacheItem(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan timeout, Func getCacheItem) { - if (_enableCache == false) - { - return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction); - } - else - { - return _runtimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction); - } + return _runtimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction); + } /// @@ -390,20 +306,13 @@ namespace Umbraco.Core TimeSpan timeout, Func getCacheItem) { - if (_enableCache == false) + var cache = _runtimeCache as HttpRuntimeCacheProvider; + if (cache != null) { - return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction, null); - } - else - { - var cache = _runtimeCache as HttpRuntimeCacheProvider; - if (cache != null) - { - var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency); - return result == null ? default(TT) : result.TryConvertTo().Result; - } - throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider)); + var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency); + return result == null ? default(TT) : result.TryConvertTo().Result; } + throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider)); } /// @@ -421,20 +330,13 @@ namespace Umbraco.Core CacheDependency cacheDependency, Func getCacheItem) { - if (!_enableCache) + var cache = _runtimeCache as HttpRuntimeCacheProvider; + if (cache != null) { - return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, null, false, priority, null, null); - } - else - { - var cache = _runtimeCache as HttpRuntimeCacheProvider; - if (cache != null) - { - var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), null, false, priority, null, cacheDependency); - return result == null ? default(TT) : result.TryConvertTo().Result; - } - throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider)); + var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), null, false, priority, null, cacheDependency); + return result == null ? default(TT) : result.TryConvertTo().Result; } + throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider)); } /// @@ -444,18 +346,14 @@ namespace Umbraco.Core /// /// /// + [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public void InsertCacheItem(string cacheKey, CacheItemPriority priority, Func getCacheItem) { - if (_enableCache == false) - { - _nullRuntimeCache.InsertCacheItem(cacheKey, getCacheItem, priority: priority); - } - else - { - _runtimeCache.InsertCacheItem(cacheKey, getCacheItem, priority: priority); - } + _runtimeCache.InsertCacheItem(cacheKey, getCacheItem, priority: priority); + } /// @@ -466,19 +364,14 @@ namespace Umbraco.Core /// /// This will set an absolute expiration from now until the timeout /// + [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public void InsertCacheItem(string cacheKey, CacheItemPriority priority, TimeSpan timeout, Func getCacheItem) { - if (_enableCache == false) - { - _nullRuntimeCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority); - } - else - { - _runtimeCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority); - } + _runtimeCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority); } /// @@ -497,19 +390,12 @@ namespace Umbraco.Core TimeSpan timeout, Func getCacheItem) { - if (_enableCache == false) + var cache = _runtimeCache as HttpRuntimeCacheProvider; + if (cache != null) { - _nullRuntimeCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority, dependentFiles:null); - } - else - { - var cache = _runtimeCache as HttpRuntimeCacheProvider; - if (cache != null) - { - cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, null, cacheDependency); - } - throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider)); + cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, null, cacheDependency); } + throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider)); } /// @@ -530,19 +416,12 @@ namespace Umbraco.Core TimeSpan? timeout, Func getCacheItem) { - if (_enableCache == false) + var cache = _runtimeCache as HttpRuntimeCacheProvider; + if (cache != null) { - _nullRuntimeCache.InsertCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction, null); - } - else - { - var cache = _runtimeCache as HttpRuntimeCacheProvider; - if (cache != null) - { - cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency); - } - throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider)); + cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency); } + throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider)); } #endregion diff --git a/src/Umbraco.Core/CoreBootManager.cs b/src/Umbraco.Core/CoreBootManager.cs index b4e3d06273..17f909da8a 100644 --- a/src/Umbraco.Core/CoreBootManager.cs +++ b/src/Umbraco.Core/CoreBootManager.cs @@ -188,10 +188,16 @@ namespace Umbraco.Core protected virtual CacheHelper CreateApplicationCache() { var cacheHelper = new CacheHelper( - new ObjectCacheRuntimeCacheProvider(), + //we need to have the dep clone runtime cache provider to ensure + //all entities are cached properly (cloned in and cloned out) + new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()), new StaticCacheProvider(), //we have no request based cache when not running in web-based context - new NullCacheProvider()); + new NullCacheProvider(), + new IsolatedRuntimeCache(type => + //we need to have the dep clone runtime cache provider to ensure + //all entities are cached properly (cloned in and cloned out) + new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()))); return cacheHelper; } diff --git a/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs index 859c4e7ae7..244deaccb8 100644 --- a/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs @@ -24,17 +24,15 @@ namespace Umbraco.Core.Persistence.Repositories /// internal class DataTypeDefinitionRepository : PetaPocoRepositoryBase, IDataTypeDefinitionRepository { - private readonly CacheHelper _cacheHelper; private readonly IContentTypeRepository _contentTypeRepository; private readonly DataTypePreValueRepository _preValRepository; - public DataTypeDefinitionRepository(IDatabaseUnitOfWork work, CacheHelper cache, CacheHelper cacheHelper, ILogger logger, ISqlSyntaxProvider sqlSyntax, + public DataTypeDefinitionRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax, IContentTypeRepository contentTypeRepository) : base(work, cache, logger, sqlSyntax) { - _cacheHelper = cacheHelper; _contentTypeRepository = contentTypeRepository; - _preValRepository = new DataTypePreValueRepository(work, CacheHelper.CreateDisabledCacheHelper(), logger, sqlSyntax); + _preValRepository = new DataTypePreValueRepository(work, CacheHelper.CreateDisabledCacheHelper(), logger, sqlSyntax); } #region Overrides of RepositoryBase @@ -231,7 +229,7 @@ AND umbracoNode.id <> @id", //NOTE: This is a special case, we need to clear the custom cache for pre-values here so they are not stale if devs // are querying for them in the Saved event (before the distributed call cache is clearing it) - _cacheHelper.RuntimeCache.ClearCacheItem(GetPrefixedCacheKey(entity.Id)); + RuntimeCache.ClearCacheItem(GetPrefixedCacheKey(entity.Id)); entity.ResetDirtyProperties(); } @@ -270,7 +268,7 @@ AND umbracoNode.id <> @id", public PreValueCollection GetPreValuesCollectionByDataTypeId(int dataTypeId) { - var cached = _cacheHelper.RuntimeCache.GetCacheItemsByKeySearch(GetPrefixedCacheKey(dataTypeId)); + var cached = RuntimeCache.GetCacheItemsByKeySearch(GetPrefixedCacheKey(dataTypeId)); if (cached != null && cached.Any()) { //return from the cache, ensure it's a cloned result @@ -289,7 +287,7 @@ AND umbracoNode.id <> @id", { //We need to see if we can find the cached PreValueCollection based on the cache key above - var cached = _cacheHelper.RuntimeCache.GetCacheItemsByKeyExpression(GetCacheKeyRegex(preValueId)); + var cached = RuntimeCache.GetCacheItemsByKeyExpression(GetCacheKeyRegex(preValueId)); if (cached != null && cached.Any()) { //return from the cache @@ -408,7 +406,7 @@ AND umbracoNode.id <> @id", + string.Join(",", collection.FormatAsDictionary().Select(x => x.Value.Id).ToArray()); //store into cache - _cacheHelper.RuntimeCache.InsertCacheItem(key, () => collection, + RuntimeCache.InsertCacheItem(key, () => collection, //30 mins new TimeSpan(0, 0, 30), //sliding is true diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs index 264409ddf4..40121223a2 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs @@ -20,13 +20,9 @@ namespace Umbraco.Core.Persistence.Repositories internal class MemberGroupRepository : PetaPocoRepositoryBase, IMemberGroupRepository { - private readonly CacheHelper _cacheHelper; - - public MemberGroupRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax, CacheHelper cacheHelper) + public MemberGroupRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax) : base(work, cache, logger, sqlSyntax) { - if (cacheHelper == null) throw new ArgumentNullException("cacheHelper"); - _cacheHelper = cacheHelper; } private readonly MemberGroupFactory _modelFactory = new MemberGroupFactory(); @@ -135,7 +131,7 @@ namespace Umbraco.Core.Persistence.Repositories public IMemberGroup GetByName(string name) { - return _cacheHelper.RuntimeCache.GetCacheItem( + return RuntimeCache.GetCacheItem( string.Format("{0}.{1}", typeof (IMemberGroup).FullName, name), () => { diff --git a/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs index 0463312982..aa671dccec 100644 --- a/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs @@ -26,13 +26,14 @@ namespace Umbraco.Core.Persistence.Repositories where TEntity : class, IAggregateRoot { private readonly IDatabaseUnitOfWork _unitOfWork; - private readonly CacheHelper _cache; + private readonly IRuntimeCacheProvider _runtimeCache; private readonly ISqlSyntaxProvider _sqlSyntax; internal PermissionRepository(IDatabaseUnitOfWork unitOfWork, CacheHelper cache, ISqlSyntaxProvider sqlSyntax) { _unitOfWork = unitOfWork; - _cache = cache; + //Make this repository use an isolated cache + _runtimeCache = cache.IsolatedRuntimeCache.GetOrCreateCache(); _sqlSyntax = sqlSyntax; } @@ -45,7 +46,7 @@ namespace Umbraco.Core.Persistence.Repositories public IEnumerable GetUserPermissionsForEntities(int userId, params int[] entityIds) { var entityIdKey = string.Join(",", entityIds.Select(x => x.ToString(CultureInfo.InvariantCulture))); - return _cache.RuntimeCache.GetCacheItem>( + return _runtimeCache.GetCacheItem>( string.Format("{0}{1}{2}", CacheKeys.UserPermissionsCacheKey, userId, entityIdKey), () => { diff --git a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs index 2ce3537bb9..da02dcf3b4 100644 --- a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs @@ -89,7 +89,7 @@ namespace Umbraco.Core.Persistence.Repositories /// protected override IRuntimeCacheProvider RuntimeCache { - get { return RepositoryCache.GetIsolatedRuntimeCache(); } + get { return RepositoryCache.IsolatedRuntimeCache.GetOrCreateCache(); } } /// diff --git a/src/Umbraco.Core/Persistence/RepositoryFactory.cs b/src/Umbraco.Core/Persistence/RepositoryFactory.cs index d99ae8f464..e148bbe2fe 100644 --- a/src/Umbraco.Core/Persistence/RepositoryFactory.cs +++ b/src/Umbraco.Core/Persistence/RepositoryFactory.cs @@ -32,12 +32,26 @@ namespace Umbraco.Core.Persistence if (settings == null) throw new ArgumentNullException("settings"); _cacheHelper = cacheHelper; + //IMPORTANT: We will force the DeepCloneRuntimeCacheProvider to be used here which is a wrapper for the underlying // runtime cache to ensure that anything that can be deep cloned in/out is done so, this also ensures that our tracks // changes entities are reset. if ((_cacheHelper.RuntimeCache is DeepCloneRuntimeCacheProvider) == false) { - _cacheHelper = new CacheHelper(new DeepCloneRuntimeCacheProvider(_cacheHelper.RuntimeCache), _cacheHelper.StaticCache, _cacheHelper.RequestCache); + var originalHelper = cacheHelper; + + _cacheHelper = new CacheHelper( + new DeepCloneRuntimeCacheProvider(originalHelper.RuntimeCache), + originalHelper.StaticCache, + originalHelper.RequestCache, + new IsolatedRuntimeCache(type => + { + var cache = originalHelper.IsolatedRuntimeCache.GetOrCreateCache(type); + return (cache is DeepCloneRuntimeCacheProvider) == false + //wrap the original if it's not DeepCloneRuntimeCacheProvider + ? new DeepCloneRuntimeCacheProvider(cache) + : cache; + })); } _noCache = CacheHelper.CreateDisabledCacheHelper(); @@ -140,7 +154,6 @@ namespace Umbraco.Core.Persistence { return new DataTypeDefinitionRepository( uow, - _cacheHelper, _cacheHelper, _logger, _sqlSyntax, CreateContentTypeRepository(uow)); @@ -295,8 +308,7 @@ namespace Umbraco.Core.Persistence { return new MemberGroupRepository(uow, _cacheHelper, - _logger, _sqlSyntax, - _cacheHelper); + _logger, _sqlSyntax); } public virtual IEntityRepository CreateEntityRepository(IDatabaseUnitOfWork uow) diff --git a/src/Umbraco.Core/Services/ApplicationTreeService.cs b/src/Umbraco.Core/Services/ApplicationTreeService.cs index f640fa8d22..c9ce839450 100644 --- a/src/Umbraco.Core/Services/ApplicationTreeService.cs +++ b/src/Umbraco.Core/Services/ApplicationTreeService.cs @@ -315,7 +315,7 @@ namespace Umbraco.Core.Services //remove the cache now that it has changed SD: I'm leaving this here even though it // is taken care of by events as well, I think unit tests may rely on it being cleared here. - _cache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); + _cache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); } } } diff --git a/src/Umbraco.Core/Services/SectionService.cs b/src/Umbraco.Core/Services/SectionService.cs index cc25387a00..b810840873 100644 --- a/src/Umbraco.Core/Services/SectionService.cs +++ b/src/Umbraco.Core/Services/SectionService.cs @@ -171,7 +171,7 @@ namespace Umbraco.Core.Services //remove the cache so it gets re-read ... SD: I'm leaving this here even though it // is taken care of by events as well, I think unit tests may rely on it being cleared here. - _cache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); + _cache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); } } } diff --git a/src/Umbraco.Core/Services/ServiceContext.cs b/src/Umbraco.Core/Services/ServiceContext.cs index f8a78aed3d..9d0da8aca2 100644 --- a/src/Umbraco.Core/Services/ServiceContext.cs +++ b/src/Umbraco.Core/Services/ServiceContext.cs @@ -286,6 +286,7 @@ namespace Umbraco.Core.Services _entityService = new Lazy(() => new EntityService( provider, repositoryFactory, logger, eventMessagesFactory, _contentService.Value, _contentTypeService.Value, _mediaService.Value, _dataTypeService.Value, _memberService.Value, _memberTypeService.Value, + //TODO: Consider making this an isolated cache instead of using the global one cache.RuntimeCache)); if (_relationService == null) diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index d294bdaddf..dd83553074 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -162,6 +162,7 @@ + diff --git a/src/Umbraco.Tests/Macros/MacroTests.cs b/src/Umbraco.Tests/Macros/MacroTests.cs index 4f0b91d4ca..23c1c7f1f1 100644 --- a/src/Umbraco.Tests/Macros/MacroTests.cs +++ b/src/Umbraco.Tests/Macros/MacroTests.cs @@ -27,7 +27,8 @@ namespace Umbraco.Tests.Macros var cacheHelper = new CacheHelper( new ObjectCacheRuntimeCacheProvider(), new StaticCacheProvider(), - new NullCacheProvider()); + new NullCacheProvider(), + new IsolatedRuntimeCache(type => new ObjectCacheRuntimeCacheProvider())); ApplicationContext.Current = new ApplicationContext(cacheHelper, new ProfilingLogger(Mock.Of(), Mock.Of())); UmbracoConfig.For.SetUmbracoSettings(SettingsForTests.GetDefault()); @@ -36,7 +37,7 @@ namespace Umbraco.Tests.Macros [TearDown] public void TearDown() { - ApplicationContext.Current.ApplicationCache.ClearAllCache(); + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearAllCache(); ApplicationContext.Current.DisposeIfDisposable(); ApplicationContext.Current = null; } @@ -136,11 +137,11 @@ namespace Umbraco.Tests.Macros public void Macro_Needs_Removing_Based_On_Macro_File(int minutesToNow, bool expectedResult) { var now = DateTime.Now; - ApplicationContext.Current.ApplicationCache.InsertCacheItem( + ApplicationContext.Current.ApplicationCache.RuntimeCache.InsertCacheItem( "TestDate", - CacheItemPriority.NotRemovable, - new TimeSpan(0, 0, 60), - () => now.AddMinutes(minutesToNow)); //add a datetime value of 'now' with the minutes offset + priority: CacheItemPriority.NotRemovable, + timeout: new TimeSpan(0, 0, 60), + getCacheItem: () => now.AddMinutes(minutesToNow)); //add a datetime value of 'now' with the minutes offset //now we need to update a file's date to 'now' to compare var path = Path.Combine(TestHelpers.TestHelper.CurrentAssemblyDirectory, "temp.txt"); diff --git a/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs index 289bd628ee..f20de479a7 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs @@ -34,7 +34,6 @@ namespace Umbraco.Tests.Persistence.Repositories { var dataTypeDefinitionRepository = new DataTypeDefinitionRepository( unitOfWork, CacheHelper.CreateDisabledCacheHelper(), - CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax, new ContentTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax, new TemplateRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax, Mock.Of(), Mock.Of(), Mock.Of()))); @@ -376,10 +375,14 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = new PetaPocoUnitOfWorkProvider(Logger); var unitOfWork = provider.GetUnitOfWork(); - var cache = new CacheHelper(new ObjectCacheRuntimeCacheProvider(), new StaticCacheProvider(), new StaticCacheProvider()); + var cache = new CacheHelper( + new ObjectCacheRuntimeCacheProvider(), + new StaticCacheProvider(), + new StaticCacheProvider(), + new IsolatedRuntimeCache(type => new ObjectCacheRuntimeCacheProvider())); Func creator = () => new DataTypeDefinitionRepository( - unitOfWork, CacheHelper.CreateDisabledCacheHelper(), + unitOfWork, cache, Mock.Of(), SqlSyntax, new ContentTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax, @@ -402,7 +405,8 @@ namespace Umbraco.Tests.Persistence.Repositories var collection = repository.GetPreValuesCollectionByDataTypeId(dtd.Id); } - var cached = cache.RuntimeCache.GetCacheItemsByKeySearch(CacheKeys.DataTypePreValuesCacheKey + dtd.Id + "-"); + var cached = cache.IsolatedRuntimeCache.GetCache().Result + .GetCacheItemsByKeySearch(CacheKeys.DataTypePreValuesCacheKey + dtd.Id + "-"); Assert.IsNotNull(cached); Assert.AreEqual(1, cached.Count()); @@ -415,10 +419,14 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = new PetaPocoUnitOfWorkProvider(Logger); var unitOfWork = provider.GetUnitOfWork(); - var cache = new CacheHelper(new ObjectCacheRuntimeCacheProvider(), new StaticCacheProvider(), new StaticCacheProvider()); + var cache = new CacheHelper( + new ObjectCacheRuntimeCacheProvider(), + new StaticCacheProvider(), + new StaticCacheProvider(), + new IsolatedRuntimeCache(type => new ObjectCacheRuntimeCacheProvider())); Func creator = () => new DataTypeDefinitionRepository( - unitOfWork, CacheHelper.CreateDisabledCacheHelper(), + unitOfWork, cache, Mock.Of(), SqlSyntax, new ContentTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax, @@ -441,7 +449,8 @@ namespace Umbraco.Tests.Persistence.Repositories var val = repository.GetPreValueAsString(Convert.ToInt32(id)); } - var cached = cache.RuntimeCache.GetCacheItemsByKeySearch(CacheKeys.DataTypePreValuesCacheKey + dtd.Id + "-"); + var cached = cache.IsolatedRuntimeCache.GetCache().Result + .GetCacheItemsByKeySearch(CacheKeys.DataTypePreValuesCacheKey + dtd.Id + "-"); Assert.IsNotNull(cached); Assert.AreEqual(1, cached.Count()); diff --git a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs index 64e8587e00..0d3b4e4e47 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs @@ -37,7 +37,7 @@ namespace Umbraco.Tests.Persistence.Repositories private MemberRepository CreateRepository(IDatabaseUnitOfWork unitOfWork, out MemberTypeRepository memberTypeRepository, out MemberGroupRepository memberGroupRepository) { memberTypeRepository = new MemberTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax); - memberGroupRepository = new MemberGroupRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax, CacheHelper.CreateDisabledCacheHelper()); + memberGroupRepository = new MemberGroupRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax); var tagRepo = new TagRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax); var repository = new MemberRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax, memberTypeRepository, memberGroupRepository, tagRepo, Mock.Of()); return repository; diff --git a/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs b/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs index 8b742b1b2c..5c1ec9e1d4 100644 --- a/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs @@ -26,7 +26,7 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); base.RefreshAll(); } @@ -38,7 +38,7 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); base.Remove(id); } diff --git a/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs b/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs index e267b441a2..2f1ab4b891 100644 --- a/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs @@ -26,7 +26,7 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); base.RefreshAll(); } @@ -38,7 +38,7 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); base.Remove(id); } diff --git a/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs index 502e215c90..03b7e0ee59 100644 --- a/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs @@ -126,9 +126,9 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); + //all property type cache ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.PropertyTypeCacheKey); //all content type property cache @@ -179,7 +179,7 @@ namespace Umbraco.Web.Cache /// - InMemoryCacheProvider.Current.Clear(); /// - RoutesCache.Clear(); /// - private static void ClearContentTypeCache(JsonPayload[] payloads) + private void ClearContentTypeCache(JsonPayload[] payloads) { var needsContentRefresh = false; @@ -214,18 +214,18 @@ namespace Umbraco.Web.Cache { if (payloads.Any(x => x.Type == typeof (IContentType).Name)) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); } if (payloads.Any(x => x.Type == typeof(IMediaType).Name)) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); } if (payloads.Any(x => x.Type == typeof(IMemberType).Name)) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); } @@ -291,7 +291,7 @@ namespace Umbraco.Web.Cache /// /// true if the entity was deleted, false if it is just an update /// - private static void ClearContentTypeCache(bool isDeleted, params int[] ids) + private void ClearContentTypeCache(bool isDeleted, params int[] ids) { ClearContentTypeCache( ids.Select( diff --git a/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs index 86114d5f77..6a813df2fd 100644 --- a/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs @@ -92,27 +92,22 @@ namespace Umbraco.Web.Cache // db data type to store the value against and anytime a datatype changes, this also might change // we basically need to clear all sorts of runtime caches here because so many things depend upon a data type - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.IdToKeyCacheKey); ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.KeyToIdCacheKey); payloads.ForEach(payload => { - //clear both the Id and Unique Id cache since we cache both in the legacy classes :( - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch( - string.Format("{0}{1}", CacheKeys.DataTypeCacheKey, payload.Id)); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch( - string.Format("{0}{1}", CacheKeys.DataTypeCacheKey, payload.UniqueId)); - //clears the prevalue cache - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch( - string.Format("{0}{1}", CacheKeys.DataTypePreValuesCacheKey, payload.Id)); - + var dataTypeCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); + if (dataTypeCache) + dataTypeCache.Result.ClearCacheByKeySearch(string.Format("{0}{1}", CacheKeys.DataTypePreValuesCacheKey, payload.Id)); + PublishedContentType.ClearDataType(payload.Id); }); diff --git a/src/Umbraco.Web/Cache/DictionaryCacheRefresher.cs b/src/Umbraco.Web/Cache/DictionaryCacheRefresher.cs index 8209d247a2..6dff68544a 100644 --- a/src/Umbraco.Web/Cache/DictionaryCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/DictionaryCacheRefresher.cs @@ -28,13 +28,13 @@ namespace Umbraco.Web.Cache public override void Refresh(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Refresh(id); } public override void Remove(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Remove(id); } } diff --git a/src/Umbraco.Web/Cache/DistributedCache.cs b/src/Umbraco.Web/Cache/DistributedCache.cs index 27c30d89e8..6848ce2496 100644 --- a/src/Umbraco.Web/Cache/DistributedCache.cs +++ b/src/Umbraco.Web/Cache/DistributedCache.cs @@ -38,6 +38,9 @@ namespace Umbraco.Web.Cache public const string ContentTypeCacheRefresherId = "6902E22C-9C10-483C-91F3-66B7CAE9E2F5"; public const string LanguageCacheRefresherId = "3E0F95D8-0BE5-44B8-8394-2B8750B62654"; public const string DomainCacheRefresherId = "11290A79-4B57-4C99-AD72-7748A3CF38AF"; + + [Obsolete("This is no longer used and will be removed in future versions")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string StylesheetCacheRefresherId = "E0633648-0DEB-44AE-9A48-75C3A55CB670"; public const string StylesheetPropertyCacheRefresherId = "2BC7A3A4-6EB1-4FBC-BAA3-C9E7B6D36D38"; public const string DataTypeCacheRefresherId = "35B16C25-A17E-45D7-BC8F-EDAB1DCC28D2"; diff --git a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs index 66cb82ff7c..750872d8af 100644 --- a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs +++ b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs @@ -442,7 +442,7 @@ namespace Umbraco.Web.Cache public static void ClearXsltCacheOnCurrentServer(this DistributedCache dc) { if (UmbracoConfig.For.UmbracoSettings().Content.UmbracoLibraryCacheDuration <= 0) return; - ApplicationContext.Current.ApplicationCache.ClearCacheObjectTypes("MS.Internal.Xml.XPath.XPathSelectionIterator"); + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes("MS.Internal.Xml.XPath.XPathSelectionIterator"); } #endregion diff --git a/src/Umbraco.Web/Cache/DomainCacheRefresher.cs b/src/Umbraco.Web/Cache/DomainCacheRefresher.cs index 51a2c79b2d..e5b1d9365d 100644 --- a/src/Umbraco.Web/Cache/DomainCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/DomainCacheRefresher.cs @@ -41,8 +41,8 @@ namespace Umbraco.Web.Cache } private void ClearCache() - { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + { + ClearAllCacheByRepositoryEntityType(); // SD: we need to clear the routes cache here! // diff --git a/src/Umbraco.Web/Cache/LanguageCacheRefresher.cs b/src/Umbraco.Web/Cache/LanguageCacheRefresher.cs index 019be66b15..13edcb3b68 100644 --- a/src/Umbraco.Web/Cache/LanguageCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/LanguageCacheRefresher.cs @@ -28,13 +28,13 @@ namespace Umbraco.Web.Cache public override void Refresh(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Refresh(id); } public override void Remove(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Remove(id); } } diff --git a/src/Umbraco.Web/Cache/MacroCacheRefresher.cs b/src/Umbraco.Web/Cache/MacroCacheRefresher.cs index a06501032f..6dd8aa9805 100644 --- a/src/Umbraco.Web/Cache/MacroCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MacroCacheRefresher.cs @@ -176,7 +176,7 @@ namespace Umbraco.Web.Cache prefix => ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(prefix)); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.RefreshAll(); } @@ -191,7 +191,11 @@ namespace Umbraco.Web.Cache alias => ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(alias)); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(payload.Id)); + var macroRepoCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); + if (macroRepoCache) + { + macroRepoCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(payload.Id)); + } }); base.Refresh(jsonPayload); diff --git a/src/Umbraco.Web/Cache/MediaCacheRefresher.cs b/src/Umbraco.Web/Cache/MediaCacheRefresher.cs index dce512b1dc..a0e037e110 100644 --- a/src/Umbraco.Web/Cache/MediaCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MediaCacheRefresher.cs @@ -24,7 +24,7 @@ namespace Umbraco.Web.Cache public class MediaCacheRefresher : JsonCacheRefresherBase { #region Static helpers - + /// /// Converts the json to a JsonPayload object /// @@ -143,13 +143,13 @@ namespace Umbraco.Web.Cache } public override void Remove(int id) - { + { ClearCache(FromMedia(ApplicationContext.Current.Services.MediaService.GetById(id), //NOTE: we'll just default to trashed for this one. OperationType.Trashed)); base.Remove(id); } - + private static void ClearCache(params JsonPayload[] payloads) { if (payloads == null) return; @@ -159,40 +159,40 @@ namespace Umbraco.Web.Cache ApplicationContext.Current.ApplicationCache.ClearPartialViewCache(); payloads.ForEach(payload => + { + var mediaCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); + + //if there's no path, then just use id (this will occur on permanent deletion like emptying recycle bin) + if (payload.Path.IsNullOrWhiteSpace()) { - - //if there's no path, then just use id (this will occur on permanent deletion like emptying recycle bin) - if (payload.Path.IsNullOrWhiteSpace()) + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch( + string.Format("{0}_{1}", CacheKeys.MediaCacheKey, payload.Id)); + } + else + { + foreach (var idPart in payload.Path.Split(',')) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch( - string.Format("{0}_{1}", CacheKeys.MediaCacheKey, payload.Id)); - } - else - { - foreach (var idPart in payload.Path.Split(',')) + int idPartAsInt; + if (int.TryParse(idPart, out idPartAsInt) && mediaCache) { - int idPartAsInt; - if (int.TryParse(idPart, out idPartAsInt)) - { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem( - RepositoryBase.GetCacheIdKey(idPartAsInt)); - } + mediaCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(idPartAsInt)); + } + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch( + string.Format("{0}_{1}_True", CacheKeys.MediaCacheKey, idPart)); + + // Also clear calls that only query this specific item! + if (idPart == payload.Id.ToString(CultureInfo.InvariantCulture)) ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch( - string.Format("{0}_{1}_True", CacheKeys.MediaCacheKey, idPart)); - - // Also clear calls that only query this specific item! - if (idPart == payload.Id.ToString(CultureInfo.InvariantCulture)) - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch( - string.Format("{0}_{1}", CacheKeys.MediaCacheKey, payload.Id)); - } + string.Format("{0}_{1}", CacheKeys.MediaCacheKey, payload.Id)); } + } + + // published cache... + PublishedMediaCache.ClearCache(payload.Id); + }); - // published cache... - PublishedMediaCache.ClearCache(payload.Id); - }); - } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/MemberCacheRefresher.cs b/src/Umbraco.Web/Cache/MemberCacheRefresher.cs index a0167454a5..32e6a69717 100644 --- a/src/Umbraco.Web/Cache/MemberCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MemberCacheRefresher.cs @@ -69,7 +69,9 @@ namespace Umbraco.Web.Cache ApplicationContext.Current.ApplicationCache.RuntimeCache. ClearCacheByKeySearch(string.Format("{0}{1}", CacheKeys.MemberBusinessLogicCacheKey, id)); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); + var memberCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); + if (memberCache) + memberCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs b/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs index e410ab560c..dc2ba39b9d 100644 --- a/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs @@ -104,13 +104,13 @@ namespace Umbraco.Web.Cache { if (payloads == null) return; + var memberGroupCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); payloads.ForEach(payload => { - if (payload != null) + if (payload != null && memberGroupCache) { - ApplicationContext.Current.ApplicationCache.RuntimeCache - .ClearCacheByKeySearch(string.Format("{0}.{1}", typeof(IMemberGroup).FullName, payload.Name)); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(payload.Id)); + memberGroupCache.Result.ClearCacheByKeySearch(string.Format("{0}.{1}", typeof(IMemberGroup).FullName, payload.Name)); + memberGroupCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(payload.Id)); } }); diff --git a/src/Umbraco.Web/Cache/PageCacheRefresher.cs b/src/Umbraco.Web/Cache/PageCacheRefresher.cs index 73f525383e..8461f57d64 100644 --- a/src/Umbraco.Web/Cache/PageCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/PageCacheRefresher.cs @@ -76,7 +76,7 @@ namespace Umbraco.Web.Cache content.Instance.ClearDocumentCache(id); DistributedCache.Instance.ClearAllMacroCacheOnCurrentServer(); DistributedCache.Instance.ClearXsltCacheOnCurrentServer(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Remove(id); } @@ -86,7 +86,7 @@ namespace Umbraco.Web.Cache content.Instance.UpdateDocumentCache(new Document(instance)); DistributedCache.Instance.ClearAllMacroCacheOnCurrentServer(); DistributedCache.Instance.ClearXsltCacheOnCurrentServer(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Refresh(instance); } @@ -96,7 +96,7 @@ namespace Umbraco.Web.Cache content.Instance.ClearDocumentCache(new Document(instance)); DistributedCache.Instance.ClearAllMacroCacheOnCurrentServer(); DistributedCache.Instance.ClearXsltCacheOnCurrentServer(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Remove(instance); } } diff --git a/src/Umbraco.Web/Cache/PublicAccessCacheRefresher.cs b/src/Umbraco.Web/Cache/PublicAccessCacheRefresher.cs index 09b38f1ac3..77d7314941 100644 --- a/src/Umbraco.Web/Cache/PublicAccessCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/PublicAccessCacheRefresher.cs @@ -27,25 +27,25 @@ namespace Umbraco.Web.Cache public override void Refresh(Guid id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Refresh(id); } public override void Refresh(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Refresh(id); } public override void RefreshAll() { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.RefreshAll(); } public override void Remove(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Remove(id); } } diff --git a/src/Umbraco.Web/Cache/StylesheetCacheRefresher.cs b/src/Umbraco.Web/Cache/StylesheetCacheRefresher.cs index 5d98671a76..959a937e7b 100644 --- a/src/Umbraco.Web/Cache/StylesheetCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/StylesheetCacheRefresher.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using Umbraco.Core; using Umbraco.Core.Cache; @@ -7,6 +8,8 @@ namespace Umbraco.Web.Cache /// /// A cache refresher to ensure stylesheet cache is refreshed when stylesheets change /// + [Obsolete("This is no longer used and will be removed in future versions")] + [EditorBrowsable(EditorBrowsableState.Never)] public sealed class StylesheetCacheRefresher : CacheRefresherBase { protected override StylesheetCacheRefresher Instance @@ -24,27 +27,5 @@ namespace Umbraco.Web.Cache get { return "Stylesheet cache refresher"; } } - public override void RefreshAll() - { - ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(CacheKeys.StylesheetCacheKey); - base.RefreshAll(); - } - - public override void Refresh(int id) - { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(GetStylesheetCacheKey(id)); - base.Refresh(id); - } - - public override void Remove(int id) - { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(GetStylesheetCacheKey(id)); - base.Remove(id); - } - - private static string GetStylesheetCacheKey(int id) - { - return CacheKeys.StylesheetCacheKey + id; - } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/StylesheetPropertyCacheRefresher.cs b/src/Umbraco.Web/Cache/StylesheetPropertyCacheRefresher.cs index d7006c8531..5b72e0384b 100644 --- a/src/Umbraco.Web/Cache/StylesheetPropertyCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/StylesheetPropertyCacheRefresher.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using Umbraco.Core; using Umbraco.Core.Cache; @@ -7,6 +8,8 @@ namespace Umbraco.Web.Cache /// /// A cache refresher to ensure stylesheet property cache is refreshed when stylesheet properties change /// + [Obsolete("This is no longer used and will be removed in future versions")] + [EditorBrowsable(EditorBrowsableState.Never)] public sealed class StylesheetPropertyCacheRefresher : CacheRefresherBase { protected override StylesheetPropertyCacheRefresher Instance @@ -23,28 +26,6 @@ namespace Umbraco.Web.Cache { get { return "Stylesheet property cache refresher"; } } - - public override void RefreshAll() - { - ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(CacheKeys.StylesheetPropertyCacheKey); - base.RefreshAll(); - } - - public override void Refresh(int id) - { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(GetStylesheetPropertyCacheKey(id)); - base.Refresh(id); - } - - public override void Remove(int id) - { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(GetStylesheetPropertyCacheKey(id)); - base.Remove(id); - } - - private static string GetStylesheetPropertyCacheKey(int id) - { - return CacheKeys.StylesheetPropertyCacheKey + id; - } + } } \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/TemplateCacheRefresher.cs b/src/Umbraco.Web/Cache/TemplateCacheRefresher.cs index 22bce3d5bf..12988e921c 100644 --- a/src/Umbraco.Web/Cache/TemplateCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/TemplateCacheRefresher.cs @@ -52,8 +52,8 @@ namespace Umbraco.Web.Cache // all three of these types are referenced by templates, and the cache needs to be cleared on every server, // otherwise things like looking up content type's after a template is removed is still going to show that // it has an associated template. - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); base.Remove(id); } @@ -66,7 +66,7 @@ namespace Umbraco.Web.Cache string.Format("{0}{1}", CacheKeys.TemplateFrontEndCacheKey, id)); //need to clear the runtime cache for templates - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); } } diff --git a/src/Umbraco.Web/Cache/UnpublishedPageCacheRefresher.cs b/src/Umbraco.Web/Cache/UnpublishedPageCacheRefresher.cs index e3601188f4..d4efcb96c7 100644 --- a/src/Umbraco.Web/Cache/UnpublishedPageCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/UnpublishedPageCacheRefresher.cs @@ -77,16 +77,16 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); DistributedCache.Instance.ClearDomainCacheOnCurrentServer(); base.RefreshAll(); } public override void Refresh(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearRepositoryCacheItemById(id); + ClearAllCacheByRepositoryEntityType(); content.Instance.UpdateSortOrder(id); DistributedCache.Instance.ClearDomainCacheOnCurrentServer(); base.Refresh(id); @@ -94,8 +94,8 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearRepositoryCacheItemById(id); + ClearAllCacheByRepositoryEntityType(); DistributedCache.Instance.ClearDomainCacheOnCurrentServer(); base.Remove(id); } @@ -103,8 +103,8 @@ namespace Umbraco.Web.Cache public override void Refresh(IContent instance) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(instance.Id)); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearRepositoryCacheItemById(instance.Id); + ClearAllCacheByRepositoryEntityType(); content.Instance.UpdateSortOrder(instance); DistributedCache.Instance.ClearDomainCacheOnCurrentServer(); base.Refresh(instance); @@ -112,8 +112,8 @@ namespace Umbraco.Web.Cache public override void Remove(IContent instance) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(instance.Id)); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearRepositoryCacheItemById(instance.Id); + ClearAllCacheByRepositoryEntityType(); DistributedCache.Instance.ClearDomainCacheOnCurrentServer(); base.Remove(instance); } @@ -124,11 +124,11 @@ namespace Umbraco.Web.Cache /// public void Refresh(string jsonPayload) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); foreach (var payload in DeserializeFromJsonPayload(jsonPayload)) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(payload.Id)); + ClearRepositoryCacheItemById(payload.Id); content.Instance.UpdateSortOrder(payload.Id); } @@ -136,6 +136,15 @@ namespace Umbraco.Web.Cache OnCacheUpdated(Instance, new CacheRefresherEventArgs(jsonPayload, MessageType.RefreshByJson)); } + + private void ClearRepositoryCacheItemById(int id) + { + var contentCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); + if (contentCache) + { + contentCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); + } + } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/UserCacheRefresher.cs b/src/Umbraco.Web/Cache/UserCacheRefresher.cs index 95a7fdac49..7efbef5f9a 100644 --- a/src/Umbraco.Web/Cache/UserCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/UserCacheRefresher.cs @@ -30,9 +30,9 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.UserPermissionsCacheKey); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.UserContextCacheKey); + ClearAllCacheByRepositoryEntityType(); + if (UserPermissionsCache) + UserPermissionsCache.Result.ClearCacheByKeySearch(CacheKeys.UserPermissionsCacheKey); base.RefreshAll(); } @@ -44,16 +44,20 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); - - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(string.Format("{0}{1}", CacheKeys.UserPermissionsCacheKey, id)); - - //we need to clear all UserContextCacheKey since we cannot invalidate based on ID since the cache is done so based - //on the current contextId stored in the database - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.UserContextCacheKey); + var userCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); + if (userCache) + userCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); + if (UserPermissionsCache) + UserPermissionsCache.Result.ClearCacheItem(string.Format("{0}{1}", CacheKeys.UserPermissionsCacheKey, id)); + base.Remove(id); } + private Attempt UserPermissionsCache + { + get { return ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); } + } + } } \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/UserPermissionsCacheRefresher.cs b/src/Umbraco.Web/Cache/UserPermissionsCacheRefresher.cs index db1baf1bcd..64744024ed 100644 --- a/src/Umbraco.Web/Cache/UserPermissionsCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/UserPermissionsCacheRefresher.cs @@ -1,6 +1,7 @@ using System; using Umbraco.Core; using Umbraco.Core.Cache; +using Umbraco.Core.Models.Membership; namespace Umbraco.Web.Cache { @@ -31,7 +32,8 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { - ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(CacheKeys.UserPermissionsCacheKey); + if (UserPermissionsCache) + UserPermissionsCache.Result.ClearCacheByKeySearch(CacheKeys.UserPermissionsCacheKey); base.RefreshAll(); } @@ -43,8 +45,14 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(string.Format("{0}{1}", CacheKeys.UserPermissionsCacheKey, id)); + if (UserPermissionsCache) + UserPermissionsCache.Result.ClearCacheItem(string.Format("{0}{1}", CacheKeys.UserPermissionsCacheKey, id)); base.Remove(id); } + + private Attempt UserPermissionsCache + { + get { return ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); } + } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/UserTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/UserTypeCacheRefresher.cs index 2beaa4347d..d67865a188 100644 --- a/src/Umbraco.Web/Cache/UserTypeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/UserTypeCacheRefresher.cs @@ -29,19 +29,23 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.RefreshAll(); } public override void Refresh(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); + var userTypeCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); + if (userTypeCache) + userTypeCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); base.Refresh(id); } public override void Remove(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); + var userTypeCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); + if (userTypeCache) + userTypeCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); base.Remove(id); } diff --git a/src/Umbraco.Web/CacheHelperExtensions.cs b/src/Umbraco.Web/CacheHelperExtensions.cs index f23bb6d070..1b0451a999 100644 --- a/src/Umbraco.Web/CacheHelperExtensions.cs +++ b/src/Umbraco.Web/CacheHelperExtensions.cs @@ -58,7 +58,7 @@ namespace Umbraco.Web /// public static void ClearPartialViewCache(this CacheHelper cacheHelper) { - cacheHelper.ClearCacheByKeySearch(PartialViewCacheKey); + cacheHelper.RuntimeCache.ClearCacheByKeySearch(PartialViewCacheKey); } } } diff --git a/src/Umbraco.Web/Media/ImageUrl.cs b/src/Umbraco.Web/Media/ImageUrl.cs index 8f56d8bfa4..dff9358a38 100644 --- a/src/Umbraco.Web/Media/ImageUrl.cs +++ b/src/Umbraco.Web/Media/ImageUrl.cs @@ -87,7 +87,7 @@ namespace Umbraco.Web.Media private static object GetContentFromCache(int nodeIdInt, string field) { - var content = ApplicationContext.Current.ApplicationCache.GetCacheItem( + var content = ApplicationContext.Current.ApplicationCache.RuntimeCache.GetCacheItem( string.Format("{0}{1}_{2}", CacheKeys.ContentItemCacheKey, nodeIdInt.ToString(CultureInfo.InvariantCulture), field)); return content; } diff --git a/src/Umbraco.Web/umbraco.presentation/content.cs b/src/Umbraco.Web/umbraco.presentation/content.cs index 23e44896f4..0bee9e631a 100644 --- a/src/Umbraco.Web/umbraco.presentation/content.cs +++ b/src/Umbraco.Web/umbraco.presentation/content.cs @@ -297,7 +297,7 @@ namespace umbraco ClearContextCache(); var cachedFieldKeyStart = string.Format("{0}{1}_", CacheKeys.ContentItemCacheKey, d.Id); - ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(cachedFieldKeyStart); + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(cachedFieldKeyStart); FireAfterUpdateDocumentCache(d, e); } diff --git a/src/Umbraco.Web/umbraco.presentation/library.cs b/src/Umbraco.Web/umbraco.presentation/library.cs index cbfdafc56a..d9b1d520ed 100644 --- a/src/Umbraco.Web/umbraco.presentation/library.cs +++ b/src/Umbraco.Web/umbraco.presentation/library.cs @@ -493,11 +493,11 @@ namespace umbraco { if (UmbracoConfig.For.UmbracoSettings().Content.UmbracoLibraryCacheDuration > 0) { - var xml = ApplicationContext.Current.ApplicationCache.GetCacheItem( + var xml = ApplicationContext.Current.ApplicationCache.RuntimeCache.GetCacheItem( string.Format( "{0}_{1}_{2}", CacheKeys.MediaCacheKey, MediaId, Deep), - TimeSpan.FromSeconds(UmbracoConfig.For.UmbracoSettings().Content.UmbracoLibraryCacheDuration), - () => GetMediaDo(MediaId, Deep)); + timeout: TimeSpan.FromSeconds(UmbracoConfig.For.UmbracoSettings().Content.UmbracoLibraryCacheDuration), + getCacheItem: () => GetMediaDo(MediaId, Deep)); if (xml != null) { @@ -552,11 +552,11 @@ namespace umbraco { if (UmbracoConfig.For.UmbracoSettings().Content.UmbracoLibraryCacheDuration > 0) { - var xml = ApplicationContext.Current.ApplicationCache.GetCacheItem( + var xml = ApplicationContext.Current.ApplicationCache.RuntimeCache.GetCacheItem( string.Format( "{0}_{1}", CacheKeys.MemberLibraryCacheKey, MemberId), - TimeSpan.FromSeconds(UmbracoConfig.For.UmbracoSettings().Content.UmbracoLibraryCacheDuration), - () => GetMemberDo(MemberId)); + timeout: TimeSpan.FromSeconds(UmbracoConfig.For.UmbracoSettings().Content.UmbracoLibraryCacheDuration), + getCacheItem: () => GetMemberDo(MemberId)); if (xml != null) { diff --git a/src/Umbraco.Web/umbraco.presentation/macro.cs b/src/Umbraco.Web/umbraco.presentation/macro.cs index e14cef4eb1..66ba6fea15 100644 --- a/src/Umbraco.Web/umbraco.presentation/macro.cs +++ b/src/Umbraco.Web/umbraco.presentation/macro.cs @@ -571,11 +571,11 @@ namespace umbraco } //insert the cache string result - ApplicationContext.Current.ApplicationCache.InsertCacheItem( + ApplicationContext.Current.ApplicationCache.RuntimeCache.InsertCacheItem( CacheKeys.MacroHtmlCacheKey + Model.CacheIdentifier, - CacheItemPriority.NotRemovable, - new TimeSpan(0, 0, Model.CacheDuration), - () => outputCacheString); + priority: CacheItemPriority.NotRemovable, + timeout: new TimeSpan(0, 0, Model.CacheDuration), + getCacheItem: () => outputCacheString); dateAddedCacheKey = CacheKeys.MacroHtmlDateAddedCacheKey + Model.CacheIdentifier; @@ -590,11 +590,11 @@ namespace umbraco else { //insert the cache control result - ApplicationContext.Current.ApplicationCache.InsertCacheItem( + ApplicationContext.Current.ApplicationCache.RuntimeCache.InsertCacheItem( CacheKeys.MacroControlCacheKey + Model.CacheIdentifier, - CacheItemPriority.NotRemovable, - new TimeSpan(0, 0, Model.CacheDuration), - () => new MacroCacheContent(macroControl, macroControl.ID)); + priority: CacheItemPriority.NotRemovable, + timeout: new TimeSpan(0, 0, Model.CacheDuration), + getCacheItem: () => new MacroCacheContent(macroControl, macroControl.ID)); dateAddedCacheKey = CacheKeys.MacroControlDateAddedCacheKey + Model.CacheIdentifier; @@ -603,11 +603,11 @@ namespace umbraco } //insert the date inserted (so we can check file modification date) - ApplicationContext.Current.ApplicationCache.InsertCacheItem( + ApplicationContext.Current.ApplicationCache.RuntimeCache.InsertCacheItem( dateAddedCacheKey, - CacheItemPriority.NotRemovable, - new TimeSpan(0, 0, Model.CacheDuration), - () => DateTime.Now); + priority: CacheItemPriority.NotRemovable, + timeout: new TimeSpan(0, 0, Model.CacheDuration), + getCacheItem: () => DateTime.Now); } @@ -640,7 +640,7 @@ namespace umbraco if (CacheMacroAsString(Model)) { - macroHtml = ApplicationContext.Current.ApplicationCache.GetCacheItem( + macroHtml = ApplicationContext.Current.ApplicationCache.RuntimeCache.GetCacheItem( CacheKeys.MacroHtmlCacheKey + Model.CacheIdentifier); // FlorisRobbemont: @@ -666,7 +666,7 @@ namespace umbraco } else { - var cacheContent = ApplicationContext.Current.ApplicationCache.GetCacheItem( + var cacheContent = ApplicationContext.Current.ApplicationCache.RuntimeCache.GetCacheItem( CacheKeys.MacroControlCacheKey + Model.CacheIdentifier); if (cacheContent != null) @@ -730,7 +730,7 @@ namespace umbraco { if (MacroIsFileBased(model)) { - var cacheResult = ApplicationContext.Current.ApplicationCache.GetCacheItem(dateAddedKey); + var cacheResult = ApplicationContext.Current.ApplicationCache.RuntimeCache.GetCacheItem(dateAddedKey); if (cacheResult != null) { @@ -864,7 +864,7 @@ namespace umbraco [Obsolete("This is no longer used in the codebase and will be removed in future versions")] public static void unloadXslt(string XsltFile) { - ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(CacheKeys.MacroXsltCacheKey + XsltFile); + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.MacroXsltCacheKey + XsltFile); } #region LoadMacroXslt diff --git a/src/Umbraco.Web/umbraco.presentation/template.cs b/src/Umbraco.Web/umbraco.presentation/template.cs index 6c1e23a13e..dfdad324e2 100644 --- a/src/Umbraco.Web/umbraco.presentation/template.cs +++ b/src/Umbraco.Web/umbraco.presentation/template.cs @@ -494,7 +494,7 @@ namespace umbraco { var tId = templateID; - var t = ApplicationContext.Current.ApplicationCache.GetCacheItem( + var t = ApplicationContext.Current.ApplicationCache.RuntimeCache.GetCacheItem