From b441c73604ec6e2266cbe6e72748e127bc297f74 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 9 Nov 2016 13:05:23 +0100 Subject: [PATCH] U4-9077 - relation type cache refresher + policy --- .../Repositories/RelationTypeRepository.cs | 69 ++++++++++--------- .../Cache/CacheRefresherEventHandler.cs | 27 +++++++- src/Umbraco.Web/Cache/DistributedCache.cs | 2 + .../Cache/DistributedCacheExtensions.cs | 14 ++++ .../Cache/RelationTypeCacheRefresher.cs | 52 ++++++++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 1 + 6 files changed, 128 insertions(+), 37 deletions(-) create mode 100644 src/Umbraco.Web/Cache/RelationTypeCacheRefresher.cs diff --git a/src/Umbraco.Core/Persistence/Repositories/RelationTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/RelationTypeRepository.cs index df0ae0b224..c0a110feca 100644 --- a/src/Umbraco.Core/Persistence/Repositories/RelationTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/RelationTypeRepository.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Umbraco.Core.Cache; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.EntityBase; @@ -18,50 +19,42 @@ namespace Umbraco.Core.Persistence.Repositories /// internal class RelationTypeRepository : PetaPocoRepositoryBase, IRelationTypeRepository { - public RelationTypeRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax) : base(work, cache, logger, sqlSyntax) + { } + + // assuming we don't have tons of relation types, use a FullDataSet policy, ie + // cache the entire GetAll result once in a single collection - which can expire + private FullDataSetRepositoryCachePolicyFactory _cachePolicyFactory; + protected override IRepositoryCachePolicyFactory CachePolicyFactory { + get + { + return _cachePolicyFactory + ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory( + RuntimeCache, GetEntityId, () => PerformGetAll(), expires: true)); + } } #region Overrides of RepositoryBase protected override IRelationType PerformGet(int id) { - var sql = GetBaseQuery(false); - sql.Where(GetBaseWhereClause(), new { Id = id }); - - var dto = Database.Fetch(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault(); - if (dto == null) - return null; - - var factory = new RelationTypeFactory(); - var entity = factory.BuildEntity(dto); - - //on initial construction we don't want to have dirty properties tracked - // http://issues.umbraco.org/issue/U4-1946 - ((TracksChangesEntityBase)entity).ResetDirtyProperties(false); - - return entity; + // use the underlying GetAll which will force cache all content types + return GetAll().FirstOrDefault(x => x.Id == id); } protected override IEnumerable PerformGetAll(params int[] ids) { + var sql = GetBaseQuery(false); + + // should not happen due to the cache policy if (ids.Any()) - { - foreach (var id in ids) - { - yield return Get(id); - } - } - else - { - var dtos = Database.Fetch("WHERE id > 0"); - foreach (var dto in dtos) - { - yield return Get(dto.Id); - } - } + throw new NotImplementedException(); + + var dtos = Database.Fetch(sql); + var factory = new RelationTypeFactory(); + return dtos.Select(x => DtoToEntity(x, factory)); } protected override IEnumerable PerformGetByQuery(IQuery query) @@ -71,11 +64,19 @@ namespace Umbraco.Core.Persistence.Repositories var sql = translator.Translate(); var dtos = Database.Fetch(sql); + var factory = new RelationTypeFactory(); + return dtos.Select(x => DtoToEntity(x, factory)); + } - foreach (var dto in dtos) - { - yield return Get(dto.Id); - } + private static IRelationType DtoToEntity(RelationTypeDto dto, RelationTypeFactory factory) + { + var entity = factory.BuildEntity(dto); + + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + ((TracksChangesEntityBase) entity).ResetDirtyProperties(false); + + return entity; } #endregion diff --git a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs index 15e01fd430..791318d8ab 100644 --- a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs +++ b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs @@ -125,9 +125,12 @@ namespace Umbraco.Web.Cache //public access events PublicAccessService.Saved += PublicAccessService_Saved; - PublicAccessService.Deleted += PublicAccessService_Deleted; ; + PublicAccessService.Deleted += PublicAccessService_Deleted; + + RelationService.SavedRelationType += RelationType_Saved; + RelationService.DeletedRelationType += RelationType_Deleted; } - + #region Publishing void PublishingStrategy_UnPublished(IPublishingStrategy sender, PublishEventArgs e) @@ -661,7 +664,25 @@ namespace Umbraco.Web.Cache { DistributedCache.Instance.RemoveMemberGroupCache(m.Id); } - } + } + #endregion + + #region Relation type event handlers + + private static void RelationType_Saved(IRelationService sender, SaveEventArgs args) + { + var dc = DistributedCache.Instance; + foreach (var e in args.SavedEntities) + dc.RefreshRelationTypeCache(e.Id); + } + + private static void RelationType_Deleted(IRelationService sender, DeleteEventArgs args) + { + var dc = DistributedCache.Instance; + foreach (var e in args.DeletedEntities) + dc.RemoveRelationTypeCache(e.Id); + } + #endregion } } \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/DistributedCache.cs b/src/Umbraco.Web/Cache/DistributedCache.cs index 6848ce2496..01eaf4cdd3 100644 --- a/src/Umbraco.Web/Cache/DistributedCache.cs +++ b/src/Umbraco.Web/Cache/DistributedCache.cs @@ -38,6 +38,7 @@ 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"; + public const string RelationTypeCacheRefresherId = "D8375ABA-4FB3-4F86-B505-92FBA1B6F7C9"; [Obsolete("This is no longer used and will be removed in future versions")] [EditorBrowsable(EditorBrowsableState.Never)] @@ -67,6 +68,7 @@ namespace Umbraco.Web.Cache public static readonly Guid DataTypeCacheRefresherGuid = new Guid(DataTypeCacheRefresherId); public static readonly Guid DictionaryCacheRefresherGuid = new Guid(DictionaryCacheRefresherId); public static readonly Guid PublicAccessCacheRefresherGuid = new Guid(PublicAccessCacheRefresherId); + public static readonly Guid RelationTypeCacheRefresherGuid = new Guid(RelationTypeCacheRefresherId); #endregion diff --git a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs index 750872d8af..50fd53ce09 100644 --- a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs +++ b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs @@ -446,5 +446,19 @@ namespace Umbraco.Web.Cache } #endregion + + #region Relation type cache + + public static void RefreshRelationTypeCache(this DistributedCache dc, int id) + { + dc.Refresh(DistributedCache.RelationTypeCacheRefresherGuid, id); + } + + public static void RemoveRelationTypeCache(this DistributedCache dc, int id) + { + dc.Remove(DistributedCache.RelationTypeCacheRefresherGuid, id); + } + + #endregion } } \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/RelationTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/RelationTypeCacheRefresher.cs new file mode 100644 index 0000000000..cef308c52b --- /dev/null +++ b/src/Umbraco.Web/Cache/RelationTypeCacheRefresher.cs @@ -0,0 +1,52 @@ +using System; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Models; +using Umbraco.Core.Persistence.Repositories; + +namespace Umbraco.Web.Cache +{ + public sealed class RelationTypeCacheRefresher : CacheRefresherBase + { + protected override RelationTypeCacheRefresher Instance + { + get { return this; } + } + + public override Guid UniqueIdentifier + { + get { return DistributedCache.RelationTypeCacheRefresherGuid; } + } + + public override string Name + { + get { return "Relation Type Cache Refresher"; } + } + + public override void RefreshAll() + { + ClearAllIsolatedCacheByEntityType(); + base.RefreshAll(); + } + + public override void Refresh(int id) + { + var cache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); + if (cache) cache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); + base.Refresh(id); + } + + public override void Refresh(Guid id) + { + throw new NotSupportedException(); + //base.Refresh(id); + } + + public override void Remove(int id) + { + var cache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); + if (cache) cache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); + base.Remove(id); + } + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 7fb022e848..a620a6716c 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -310,6 +310,7 @@ +