From 6e8fc27c130dbd504d820747cafc4386e2e69daa Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 8 Jun 2016 13:38:40 +0200 Subject: [PATCH] U4-8397 - Cleanup server registration db & cache --- .../ServerRegistrationRepository.cs | 46 +++++------------ .../Services/IServerRegistrationService.cs | 7 ++- .../Services/ServerRegistrationService.cs | 51 ++++--------------- 3 files changed, 28 insertions(+), 76 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/ServerRegistrationRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ServerRegistrationRepository.cs index 356bc78ab0..8c3bfdfb83 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ServerRegistrationRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ServerRegistrationRepository.cs @@ -10,19 +10,24 @@ using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence.Factories; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.Querying; -using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Persistence.UnitOfWork; namespace Umbraco.Core.Persistence.Repositories { internal class ServerRegistrationRepository : NPocoRepositoryBase, IServerRegistrationRepository { - private readonly ICacheProvider _staticCache; + private IRepositoryCachePolicy _cachePolicy; public ServerRegistrationRepository(IDatabaseUnitOfWork work, CacheHelper cacheHelper, ILogger logger, IMappingResolver mappingResolver) : base(work, CacheHelper.CreateDisabledCacheHelper(), logger, mappingResolver) + { } + + protected override IRepositoryCachePolicy CachePolicy => _cachePolicy + ?? (_cachePolicy = new FullDataSetRepositoryCachePolicy(RuntimeCache, GetEntityId, /*expires:*/ false)); + + public void ClearCache() { - _staticCache = cacheHelper.StaticCache; + CachePolicy.ClearAll(); } protected override int PerformCount(IQuery query) @@ -44,15 +49,9 @@ namespace Umbraco.Core.Persistence.Repositories protected override IEnumerable PerformGetAll(params int[] ids) { - // we do NOT want to populate the cache on-demand, because then it might happen - // during a ReadCommited transaction, and reading the registrations under ReadCommited - // is NOT safe because they could be updated in the middle of the read. - // - // the cache is populated by ReloadCache which should only be called from methods - // that ensure proper locking (at least, read-lock in ReadCommited) of the repo. - - var all = _staticCache.GetCacheItem>(CacheKey, Enumerable.Empty); - return ids.Length == 0 ? all : all.Where(x => ids.Contains(x.Id)); + var factory = new ServerRegistrationFactory(); + return Database.Fetch("WHERE id > 0") + .Select(x => factory.BuildEntity(x)); } protected override IEnumerable PerformGetByQuery(IQuery query) @@ -104,7 +103,6 @@ namespace Umbraco.Core.Persistence.Repositories entity.Id = id; entity.ResetDirtyProperties(); - ReloadCache(); } protected override void PersistUpdatedItem(IServerRegistration entity) @@ -117,26 +115,6 @@ namespace Umbraco.Core.Persistence.Repositories Database.Update(dto); entity.ResetDirtyProperties(); - ReloadCache(); - } - - public override void PersistDeletedItem(IEntity entity) - { - base.PersistDeletedItem(entity); - ReloadCache(); - } - - private static readonly string CacheKey = GetCacheTypeKey() + "all"; - - public void ReloadCache() - { - var factory = new ServerRegistrationFactory(); - var all = Database.Fetch("WHERE id > 0") - .Select(x => factory.BuildEntity(x)) - .Cast() - .ToArray(); - _staticCache.ClearCacheItem(CacheKey); - _staticCache.GetCacheItem(CacheKey, () => all); } public void DeactiveStaleServers(TimeSpan staleTimeout) @@ -144,7 +122,7 @@ namespace Umbraco.Core.Persistence.Repositories var timeoutDate = DateTime.Now.Subtract(staleTimeout); Database.Update("SET isActive=0, isMaster=0 WHERE lastNotifiedDate < @timeoutDate", new { /*timeoutDate =*/ timeoutDate }); - ReloadCache(); + ClearCache(); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/IServerRegistrationService.cs b/src/Umbraco.Core/Services/IServerRegistrationService.cs index cc40e09ceb..a852029f74 100644 --- a/src/Umbraco.Core/Services/IServerRegistrationService.cs +++ b/src/Umbraco.Core/Services/IServerRegistrationService.cs @@ -30,8 +30,13 @@ namespace Umbraco.Core.Services /// /// Return all active servers. /// + /// A value indicating whether to force-refresh the cache. /// All active servers. - IEnumerable GetActiveServers(); + /// By default this method will rely on the repository's cache, which is updated each + /// time the current server is touched, and the period depends on the configuration. Use the + /// parameter to force a cache refresh and reload active servers + /// from the database. + IEnumerable GetActiveServers(bool refresh = false); /// /// Gets the current server identity. diff --git a/src/Umbraco.Core/Services/ServerRegistrationService.cs b/src/Umbraco.Core/Services/ServerRegistrationService.cs index 22f0ad474c..d0721bac2f 100644 --- a/src/Umbraco.Core/Services/ServerRegistrationService.cs +++ b/src/Umbraco.Core/Services/ServerRegistrationService.cs @@ -5,7 +5,6 @@ using System.Web; using Umbraco.Core.Events; using Umbraco.Core.Logging; using Umbraco.Core.Models; -using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.UnitOfWork; using Umbraco.Core.Sync; @@ -45,7 +44,7 @@ namespace Umbraco.Core.Services uow.WriteLock(Constants.Locks.Servers); var repo = uow.CreateRepository(); - ((ServerRegistrationRepository) repo).ReloadCache(); // ensure we have up-to-date cache + ((ServerRegistrationRepository) repo).ClearCache(); // ensure we have up-to-date cache var regs = repo.GetAll().ToArray(); var hasMaster = regs.Any(x => ((ServerRegistration)x).IsMaster); @@ -88,17 +87,6 @@ namespace Umbraco.Core.Services /// The server unique identity. public void DeactiveServer(string serverIdentity) { - //_lrepo.WithWriteLocked(xr => - //{ - // var query = Query.Builder.Where(x => x.ServerIdentity.ToUpper() == serverIdentity.ToUpper()); - // var server = xr.Repository.GetByQuery(query).FirstOrDefault(); - // if (server == null) return; - - // server.IsActive = false; - // server.IsMaster = false; - // xr.Repository.AddOrUpdate(server); - //}); - // because the repository caches "all" and has queries disabled... using (var uow = UowProvider.CreateUnitOfWork()) @@ -106,7 +94,7 @@ namespace Umbraco.Core.Services uow.WriteLock(Constants.Locks.Servers); var repo = uow.CreateRepository(); - ((ServerRegistrationRepository) repo).ReloadCache(); // ensure we have up-to-date cache + ((ServerRegistrationRepository) repo).ClearCache(); // ensure we have up-to-date cache var server = repo.GetAll().FirstOrDefault(x => x.ServerIdentity.InvariantEquals(serverIdentity)); if (server == null) return; @@ -135,38 +123,19 @@ namespace Umbraco.Core.Services /// /// Return all active servers. /// - /// - public IEnumerable GetActiveServers() + /// A value indicating whether to force-refresh the cache. + /// All active servers. + /// By default this method will rely on the repository's cache, which is updated each + /// time the current server is touched, and the period depends on the configuration. Use the + /// parameter to force a cache refresh and reload active servers + /// from the database. + public IEnumerable GetActiveServers(bool refresh = false) { - // fixme - this needs to be refactored entirely now that we have repeatable read everywhere - - //return _lrepo.WithReadLocked(xr => - //{ - // var query = Query.Builder.Where(x => x.IsActive); - // return xr.Repository.GetByQuery(query).ToArray(); - //}); - - // because the repository caches "all" we should use the following code - // in order to ensure we use the cache and not hit the database each time - - //return _lrepo.WithReadLocked(xr => xr.Repository.GetAll().Where(x => x.IsActive).ToArray()); - - // however, WithReadLocked (as any other LockingRepository methods) will attempt - // to properly lock the repository using a database-level lock, which wants - // the transaction isolation level to be RepeatableRead, which it is not by default, - // and then, see U4-7046. - // - // in addition, LockingRepository methods need to hit the database in order to - // ensure proper locking, and so if we know that the repository might not need the - // database, we cannot use these methods - and then what? - // - // this raises a good number of questions, including whether caching anything in - // repositories works at all in a LB environment - TODO: figure it out - using (var uow = UowProvider.CreateUnitOfWork()) { uow.ReadLock(Constants.Locks.Servers); var repo = uow.CreateRepository(); + if (refresh) ((ServerRegistrationRepository) repo).ClearCache(); var servers = repo.GetAll().Where(x => x.IsActive).ToArray(); // fast, cached uow.Complete(); return servers;