From e5634d13f1070d5eb4817be47592127c3386dbe7 Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 13 Sep 2019 09:55:53 +0200 Subject: [PATCH] Lazily create content and models in NuCache --- .../PublishedCache/NuCache/ContentNode.cs | 66 +++++++++++-------- .../NuCache/PublishedContent.cs | 5 +- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/src/Umbraco.Web/PublishedCache/NuCache/ContentNode.cs b/src/Umbraco.Web/PublishedCache/NuCache/ContentNode.cs index 7379277be4a0..fad402a0ebe8 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/ContentNode.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/ContentNode.cs @@ -75,17 +75,11 @@ public void SetContentTypeAndData(IPublishedContentType contentType, ContentData if (draftData == null && publishedData == null) throw new ArgumentException("Both draftData and publishedData cannot be null at the same time."); - if (draftData != null) - { - DraftContent = new PublishedContent(this, draftData, publishedSnapshotAccessor, variationContextAccessor); - DraftModel = DraftContent.CreateModel(); - } + _publishedSnapshotAccessor = publishedSnapshotAccessor; + _variationContextAccessor = variationContextAccessor; - if (publishedData != null) - { - PublishedContent = new PublishedContent(this, publishedData, publishedSnapshotAccessor, variationContextAccessor); - PublishedModel = PublishedContent.CreateModel(); - } + _draftData = draftData; + _publishedData = publishedData; } // clone @@ -105,14 +99,8 @@ public ContentNode(ContentNode origin, IPublishedContentType contentType = null) CreateDate = origin.CreateDate; CreatorId = origin.CreatorId; - var originDraft = origin.DraftContent; - var originPublished = origin.PublishedContent; - - DraftContent = originDraft == null ? null : new PublishedContent(this, originDraft); - PublishedContent = originPublished == null ? null : new PublishedContent(this, originPublished); - - DraftModel = DraftContent?.CreateModel(); - PublishedModel = PublishedContent?.CreateModel(); + _draftData = origin._draftData; + _publishedData = origin._publishedData; } // everything that is common to both draft and published versions @@ -131,15 +119,41 @@ public ContentNode(ContentNode origin, IPublishedContentType contentType = null) public readonly DateTime CreateDate; public readonly int CreatorId; - // draft and published version (either can be null, but not both) - // are the direct PublishedContent instances - public PublishedContent DraftContent; - public PublishedContent PublishedContent; + private ContentData _draftData; + private ContentData _publishedData; + private IVariationContextAccessor _variationContextAccessor; + private IPublishedSnapshotAccessor _publishedSnapshotAccessor; + + public bool HasPublished => _publishedData != null; + public bool HasPublishedCulture(string culture) => _publishedData != null && _publishedData.CultureInfos.ContainsKey(culture); // draft and published version (either can be null, but not both) // are models not direct PublishedContent instances - public IPublishedContent DraftModel; - public IPublishedContent PublishedModel; + private IPublishedContent _draftModel; + private IPublishedContent _publishedModel; + + private IPublishedContent GetModel(ref IPublishedContent model, ContentData contentData) + { + if (model != null) return model; + if (contentData == null) return null; + + // create the model - we want to be fast, so no lock here: we may create + // more than 1 instance, but the lock below ensures we only ever return + // 1 unique instance - and locking is a nice explicit way to ensure this + + var m = new PublishedContent(this, contentData, _publishedSnapshotAccessor, _variationContextAccessor).CreateModel(); + + // locking 'this' is not a best-practice but ContentNode is internal and + // we know what we do, so it is fine here and avoids allocating an object + lock (this) + { + return model = model ?? m; + } + } + + public IPublishedContent DraftModel => GetModel(ref _draftModel, _draftData); + + public IPublishedContent PublishedModel => GetModel(ref _publishedModel, _publishedData); public ContentNodeKit ToKit() => new ContentNodeKit @@ -147,8 +161,8 @@ public ContentNodeKit ToKit() Node = this, ContentTypeId = ContentType.Id, - DraftData = DraftContent?.ContentData, - PublishedData = PublishedContent?.ContentData + DraftData = _draftData, + PublishedData = _publishedData }; } } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs index 8fc2dc10069d..bf4975714d67 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs @@ -233,8 +233,7 @@ public override bool IsPublished(string culture = null) // invariant content items) // if there is no 'published' published content, no culture can be published - var hasPublished = _contentNode.PublishedContent != null; - if (!hasPublished) + if (!_contentNode.HasPublished) return false; // if there is a 'published' published content, and does not vary = published @@ -247,7 +246,7 @@ public override bool IsPublished(string culture = null) // there is a 'published' published content, and varies // = depends on the culture - return _contentNode.PublishedContent.ContentData.CultureInfos.ContainsKey(culture); + return _contentNode.HasPublishedCulture(culture); } #endregion