using System; using System.Collections.Generic; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Logging; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Services.Implement; namespace Umbraco.Cms.Infrastructure.PublishedCache.Persistence { public class NuCacheContentService : RepositoryService, INuCacheContentService { private readonly INuCacheContentRepository _repository; private readonly IKeyValueService _keyValueService; private readonly IProfilingLogger _profilingLogger; private readonly IOptions _nucacheSettings; private readonly ILogger _logger; private const string NuCacheSerializerKey = "Umbraco.Web.PublishedCache.NuCache.Serializer"; public NuCacheContentService( INuCacheContentRepository repository, IKeyValueService keyValueService, IScopeProvider provider, ILoggerFactory loggerFactory, IProfilingLogger profilingLogger, IEventMessagesFactory eventMessagesFactory, IOptions nucacheSettings) : base(provider, loggerFactory, eventMessagesFactory) { _repository = repository; _keyValueService = keyValueService; _profilingLogger = profilingLogger; _nucacheSettings = nucacheSettings; _logger = loggerFactory.CreateLogger(); } public void RebuildDatabaseCacheIfSerializerChanged() { NuCacheSerializerType serializer = _nucacheSettings.Value.NuCacheSerializerType; var currentSerializerValue = _keyValueService.GetValue(NuCacheSerializerKey); if (!Enum.TryParse(currentSerializerValue, out NuCacheSerializerType currentSerializer) || serializer != currentSerializer) { _logger.LogWarning("Database NuCache was serialized using {CurrentSerializer}. Currently configured NuCache serializer {Serializer}. Rebuilding Nucache", currentSerializer, serializer); using (_profilingLogger.TraceDuration($"Rebuilding NuCache database with {serializer} serializer")) { Rebuild(); _keyValueService.SetValue(NuCacheSerializerKey, serializer.ToString()); } } } /// public IEnumerable GetAllContentSources() => _repository.GetAllContentSources(); /// public IEnumerable GetAllMediaSources() => _repository.GetAllMediaSources(); /// public IEnumerable GetBranchContentSources(int id) => _repository.GetBranchContentSources(id); /// public IEnumerable GetBranchMediaSources(int id) => _repository.GetBranchMediaSources(id); /// public ContentNodeKit GetContentSource(int id) => _repository.GetContentSource(id); /// public ContentNodeKit GetMediaSource(int id) => _repository.GetMediaSource(id); /// public IEnumerable GetTypeContentSources(IEnumerable ids) => _repository.GetTypeContentSources(ids); /// public IEnumerable GetTypeMediaSources(IEnumerable ids) => _repository.GetTypeContentSources(ids); /// public void DeleteContentItem(IContentBase item) => _repository.DeleteContentItem(item); public void DeleteContentItems(IEnumerable items) { foreach (IContentBase item in items) { _repository.DeleteContentItem(item); } } /// public void RefreshContent(IContent content) => _repository.RefreshContent(content); /// public void RefreshMedia(IMedia media) => _repository.RefreshMedia(media); /// public void RefreshMember(IMember member) => _repository.RefreshMember(member); /// public void Rebuild( IReadOnlyCollection contentTypeIds = null, IReadOnlyCollection mediaTypeIds = null, IReadOnlyCollection memberTypeIds = null) { using (IScope scope = ScopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.Scoped)) { scope.ReadLock(Constants.Locks.ContentTree); scope.ReadLock(Constants.Locks.MediaTree); scope.ReadLock(Constants.Locks.MemberTree); _repository.Rebuild(contentTypeIds, mediaTypeIds, memberTypeIds); // Save a key/value of the serialized type. This is used during startup to see // if the serialized type changed and if so it will rebuild with the correct type. _keyValueService.SetValue(NuCacheSerializerKey, _nucacheSettings.Value.NuCacheSerializerType.ToString()); scope.Complete(); } } /// public bool VerifyContentDbCache() { using IScope scope = ScopeProvider.CreateScope(autoComplete: true); scope.ReadLock(Constants.Locks.ContentTree); return _repository.VerifyContentDbCache(); } /// public bool VerifyMediaDbCache() { using IScope scope = ScopeProvider.CreateScope(autoComplete: true); scope.ReadLock(Constants.Locks.MediaTree); return _repository.VerifyMediaDbCache(); } /// public bool VerifyMemberDbCache() { using IScope scope = ScopeProvider.CreateScope(autoComplete: true); scope.ReadLock(Constants.Locks.MemberTree); return _repository.VerifyMemberDbCache(); } } }