Merge remote-tracking branch 'origin/temp8' into feature/IContentType-removale-from-IContent

# Conflicts:
#	src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs
This commit is contained in:
Bjarke Berg
2019-02-01 12:52:20 +01:00
1566 changed files with 18277 additions and 26409 deletions

View File

@@ -21,20 +21,20 @@ namespace Umbraco.Web.PublishedCache.NuCache
internal class ContentCache : PublishedCacheBase, IPublishedContentCache, INavigableData, IDisposable
{
private readonly ContentStore.Snapshot _snapshot;
private readonly ICacheProvider _snapshotCache;
private readonly ICacheProvider _elementsCache;
private readonly IAppCache _snapshotCache;
private readonly IAppCache _elementsCache;
private readonly DomainHelper _domainHelper;
private readonly IGlobalSettings _globalSettings;
private readonly ILocalizationService _localizationService;
#region Constructor
// fixme ISSUE
// TODO: figure this out
// after the current snapshot has been resync-ed
// it's too late for UmbracoContext which has captured previewDefault and stuff into these ctor vars
// but, no, UmbracoContext returns snapshot.Content which comes from elements SO a resync should create a new cache
public ContentCache(bool previewDefault, ContentStore.Snapshot snapshot, ICacheProvider snapshotCache, ICacheProvider elementsCache, DomainHelper domainHelper, IGlobalSettings globalSettings, ILocalizationService localizationService)
public ContentCache(bool previewDefault, ContentStore.Snapshot snapshot, IAppCache snapshotCache, IAppCache elementsCache, DomainHelper domainHelper, IGlobalSettings globalSettings, ILocalizationService localizationService)
: base(previewDefault)
{
_snapshot = snapshot;
@@ -93,7 +93,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
// if in a domain then start with the root node of the domain
// and follow the path
// note: if domain has a path (eg example.com/en) which is not recommended anymore
// then then /en part of the domain is basically ignored here...
// then /en part of the domain is basically ignored here...
content = GetById(preview, startNodeId);
content = FollowRoute(content, parts, 0, culture);
}
@@ -243,7 +243,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
var n = _snapshot.Get(contentId);
if (n == null) return false;
return preview || n.Published != null;
return preview || n.PublishedModel != null;
}
public override IEnumerable<IPublishedContent> GetAtRoot(bool preview)
@@ -259,7 +259,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
return GetAtRootNoCache(preview);
// note: ToArray is important here, we want to cache the result, not the function!
return (IEnumerable<IPublishedContent>)cache.GetCacheItem(
return (IEnumerable<IPublishedContent>)cache.Get(
CacheKeys.ContentCacheRoots(preview),
() => GetAtRootNoCache(preview).ToArray());
}
@@ -280,8 +280,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
// both .Draft and .Published cannot be null at the same time
return preview
? node.Draft ?? GetPublishedContentAsDraft(node.Published)
: node.Published;
? node.DraftModel ?? GetPublishedContentAsDraft(node.PublishedModel)
: node.PublishedModel;
}
// gets a published content as a previewing draft, if preview is true
@@ -302,7 +302,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
return preview
? _snapshot.IsEmpty == false
: _snapshot.GetAtRoot().Any(x => x.Published != null);
: _snapshot.GetAtRoot().Any(x => x.PublishedModel != null);
}
#endregion

View File

@@ -34,10 +34,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
DateTime createDate, int creatorId,
ContentData draftData, ContentData publishedData,
IPublishedSnapshotAccessor publishedSnapshotAccessor,
IVariationContextAccessor variationContextAccessor)
IVariationContextAccessor variationContextAccessor,
IUmbracoContextAccessor umbracoContextAccessor)
: this(id, uid, level, path, sortOrder, parentContentId, createDate, creatorId)
{
SetContentTypeAndData(contentType, draftData, publishedData, publishedSnapshotAccessor, variationContextAccessor);
SetContentTypeAndData(contentType, draftData, publishedData, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor);
}
// 2-phases ctor, phase 1
@@ -59,7 +60,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
// two-phase ctor, phase 2
public void SetContentTypeAndData(PublishedContentType contentType, ContentData draftData, ContentData publishedData, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor)
public void SetContentTypeAndData(PublishedContentType contentType, ContentData draftData, ContentData publishedData, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IUmbracoContextAccessor umbracoContextAccessor)
{
ContentType = contentType;
@@ -67,13 +68,20 @@ namespace Umbraco.Web.PublishedCache.NuCache
throw new ArgumentException("Both draftData and publishedData cannot be null at the same time.");
if (draftData != null)
Draft = new PublishedContent(this, draftData, publishedSnapshotAccessor, variationContextAccessor).CreateModel();
{
DraftContent = new PublishedContent(this, draftData, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor);
DraftModel = DraftContent.CreateModel();
}
if (publishedData != null)
Published = new PublishedContent(this, publishedData, publishedSnapshotAccessor, variationContextAccessor).CreateModel();
{
PublishedContent = new PublishedContent(this, publishedData, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor);
PublishedModel = PublishedContent.CreateModel();
}
}
// clone parent
private ContentNode(ContentNode origin)
private ContentNode(ContentNode origin, IUmbracoContextAccessor umbracoContextAccessor)
{
// everything is the same, except for the child items
// list which is a clone of the original list
@@ -88,17 +96,20 @@ namespace Umbraco.Web.PublishedCache.NuCache
CreateDate = origin.CreateDate;
CreatorId = origin.CreatorId;
var originDraft = origin.Draft == null ? null : PublishedContent.UnwrapIPublishedContent(origin.Draft);
var originPublished = origin.Published == null ? null : PublishedContent.UnwrapIPublishedContent(origin.Published);
var originDraft = origin.DraftContent;
var originPublished = origin.PublishedContent;
Draft = originDraft == null ? null : new PublishedContent(this, originDraft).CreateModel();
Published = originPublished == null ? null : new PublishedContent(this, originPublished).CreateModel();
DraftContent = originDraft == null ? null : new PublishedContent(this, originDraft, umbracoContextAccessor);
PublishedContent = originPublished == null ? null : new PublishedContent(this, originPublished, umbracoContextAccessor);
DraftModel = DraftContent?.CreateModel();
PublishedModel = PublishedContent?.CreateModel();
ChildContentIds = new List<int>(origin.ChildContentIds); // needs to be *another* list
}
// clone with new content type
public ContentNode(ContentNode origin, PublishedContentType contentType, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor)
public ContentNode(ContentNode origin, PublishedContentType contentType, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IUmbracoContextAccessor umbracoContextAccessor)
{
Id = origin.Id;
Uid = origin.Uid;
@@ -110,13 +121,15 @@ namespace Umbraco.Web.PublishedCache.NuCache
CreateDate = origin.CreateDate;
CreatorId = origin.CreatorId;
var originDraft = origin.Draft == null ? null : PublishedContent.UnwrapIPublishedContent(origin.Draft);
var originPublished = origin.Published == null ? null : PublishedContent.UnwrapIPublishedContent(origin.Published);
var originDraft = origin.DraftContent;
var originPublished = origin.PublishedContent;
Draft = originDraft == null ? null : new PublishedContent(this, originDraft._contentData, publishedSnapshotAccessor, variationContextAccessor).CreateModel();
Published = originPublished == null ? null : new PublishedContent(this, originPublished._contentData, publishedSnapshotAccessor, variationContextAccessor).CreateModel();
DraftContent = originDraft == null ? null : new PublishedContent(this, originDraft.ContentData, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor);
DraftModel = DraftContent?.CreateModel();
PublishedContent = originPublished == null ? null : new PublishedContent(this, originPublished.ContentData, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor);
PublishedModel = PublishedContent?.CreateModel();
ChildContentIds = origin.ChildContentIds; // can be the *same* list FIXME oh really?
ChildContentIds = origin.ChildContentIds; // can be the *same* list
}
// everything that is common to both draft and published versions
@@ -133,32 +146,31 @@ namespace Umbraco.Web.PublishedCache.NuCache
public readonly int CreatorId;
// draft and published version (either can be null, but not both)
// are models not direct PublishedContent instances
public IPublishedContent Draft;
public IPublishedContent Published;
// are the direct PublishedContent instances
public PublishedContent DraftContent;
public PublishedContent PublishedContent;
public ContentNode CloneParent(IPublishedSnapshotAccessor publishedSnapshotAccessor)
// draft and published version (either can be null, but not both)
// are models not direct PublishedContent instances
public IPublishedContent DraftModel;
public IPublishedContent PublishedModel;
public ContentNode CloneParent(
IPublishedSnapshotAccessor publishedSnapshotAccessor,
IUmbracoContextAccessor umbracoContextAccessor)
{
return new ContentNode(this);
return new ContentNode(this, umbracoContextAccessor);
}
public ContentNodeKit ToKit()
{
var draft = Draft is PublishedContentModel draftModel
? (PublishedContent) draftModel.Unwrap()
: (PublishedContent) Draft;
var published = Published is PublishedContentModel publishedModel
? (PublishedContent) publishedModel.Unwrap()
: (PublishedContent) Published;
return new ContentNodeKit
{
Node = this,
ContentTypeId = ContentType.Id,
DraftData = draft?._contentData,
PublishedData = published?._contentData
DraftData = DraftContent?.ContentData,
PublishedData = PublishedContent?.ContentData
};
}
}

View File

@@ -17,9 +17,14 @@ namespace Umbraco.Web.PublishedCache.NuCache
public static ContentNodeKit Null { get; } = new ContentNodeKit { ContentTypeId = -1 };
public void Build(PublishedContentType contentType, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, bool canBePublished)
public void Build(
PublishedContentType contentType,
IPublishedSnapshotAccessor publishedSnapshotAccessor,
IVariationContextAccessor variationContextAccessor,
bool canBePublished,
IUmbracoContextAccessor umbracoContextAccessor)
{
Node.SetContentTypeAndData(contentType, DraftData, canBePublished ? PublishedData : null, publishedSnapshotAccessor, variationContextAccessor);
Node.SetContentTypeAndData(contentType, DraftData, canBePublished ? PublishedData : null, publishedSnapshotAccessor, variationContextAccessor,umbracoContextAccessor);
}
}
}

View File

@@ -20,6 +20,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
private readonly IVariationContextAccessor _variationContextAccessor;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly ConcurrentDictionary<int, LinkedNode<ContentNode>> _contentNodes;
private readonly ConcurrentDictionary<int, LinkedNode<object>> _contentRootNodes;
private readonly ConcurrentDictionary<int, LinkedNode<PublishedContentType>> _contentTypesById;
@@ -38,16 +39,22 @@ namespace Umbraco.Web.PublishedCache.NuCache
private volatile int _wlocked;
private List<KeyValuePair<int, ContentNodeKit>> _wchanges;
// fixme - collection trigger (ok for now)
// TODO: collection trigger (ok for now)
// see SnapDictionary notes
private const long CollectMinGenDelta = 8;
#region Ctor
public ContentStore(IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, ILogger logger, BPlusTree<int, ContentNodeKit> localDb = null)
public ContentStore(
IPublishedSnapshotAccessor publishedSnapshotAccessor,
IVariationContextAccessor variationContextAccessor,
IUmbracoContextAccessor umbracoContextAccessor,
ILogger logger,
BPlusTree<int, ContentNodeKit> localDb = null)
{
_publishedSnapshotAccessor = publishedSnapshotAccessor;
_variationContextAccessor = variationContextAccessor;
_umbracoContextAccessor = umbracoContextAccessor;
_logger = logger;
_localDb = localDb;
@@ -104,7 +111,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
// gets a scope contextual representing a locked writer to the dictionary
// fixme GetScopedWriter? should the dict have a ref onto the scope provider?
// TODO: GetScopedWriter? should the dict have a ref onto the scope provider?
public IDisposable GetWriter(IScopeProvider scopeProvider)
{
return ScopeContextualBase.Get(scopeProvider, _instanceId, scoped => new ContentStoreWriter(this, scoped));
@@ -279,7 +286,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
if (node == null) continue;
var contentTypeId = node.ContentType.Id;
if (index.TryGetValue(contentTypeId, out PublishedContentType contentType) == false) continue;
SetValueLocked(_contentNodes, node.Id, new ContentNode(node, contentType, _publishedSnapshotAccessor, _variationContextAccessor));
SetValueLocked(_contentNodes, node.Id, new ContentNode(node, contentType, _publishedSnapshotAccessor, _variationContextAccessor, _umbracoContextAccessor));
}
}
finally
@@ -393,7 +400,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
_contentNodes.TryGetValue(id, out LinkedNode<ContentNode> link);
if (link?.Value == null)
continue;
var node = new ContentNode(link.Value, contentType, _publishedSnapshotAccessor, _variationContextAccessor);
var node = new ContentNode(link.Value, contentType, _publishedSnapshotAccessor, _variationContextAccessor, _umbracoContextAccessor);
SetValueLocked(_contentNodes, id, node);
if (_localDb != null) RegisterChange(id, node.ToKit());
}
@@ -419,7 +426,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
var canBePublished = ParentPublishedLocked(kit);
// and use
kit.Build(link.Value, _publishedSnapshotAccessor, _variationContextAccessor, canBePublished);
kit.Build(link.Value, _publishedSnapshotAccessor, _variationContextAccessor, canBePublished, _umbracoContextAccessor);
return true;
}
@@ -631,7 +638,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
var link = GetParentLink(content);
var parent = link.Value;
if (link.Gen < _liveGen)
parent = parent.CloneParent(_publishedSnapshotAccessor);
parent = parent.CloneParent(_publishedSnapshotAccessor, _umbracoContextAccessor);
parent.ChildContentIds.Remove(content.Id);
if (link.Gen < _liveGen)
SetValueLocked(_contentNodes, parent.Id, parent);
@@ -652,7 +659,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
return true;
var link = GetParentLink(kit.Node);
var node = link?.Value;
return node?.Published != null;
return node?.PublishedModel != null;
}
private void AddToParentLocked(ContentNode content)
@@ -670,7 +677,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
var link = GetParentLink(content);
var parent = link.Value;
if (link.Gen < _liveGen)
parent = parent.CloneParent(_publishedSnapshotAccessor);
parent = parent.CloneParent(_publishedSnapshotAccessor, _umbracoContextAccessor);
parent.ChildContentIds.Add(content.Id);
if (link.Gen < _liveGen)
SetValueLocked(_contentNodes, parent.Id, parent);

View File

@@ -36,7 +36,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
// write each variation
foreach (var (culture, variation) in variations)
{
// fixme - it's weird we're dealing with cultures here, and languageId in properties
// TODO: it's weird we're dealing with cultures here, and languageId in properties
PrimitiveSerializer.String.WriteTo(culture, stream); // should never be null
WriteObject(variation.Name, stream); // write an object in case it's null (though... should not happen)

View File

@@ -15,7 +15,7 @@ using static Umbraco.Core.Persistence.NPocoSqlExtensions.Statics;
namespace Umbraco.Web.PublishedCache.NuCache.DataSource
{
// fixme - use SqlTemplate for these queries else it's going to be horribly slow!
// TODO: use SqlTemplate for these queries else it's going to be horribly slow!
// provides efficient database access for NuCache
internal class DatabaseDataSource : IDataSource

View File

@@ -12,14 +12,14 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
public string Culture
{
get => _culture;
set => _culture = value ?? throw new ArgumentNullException(nameof(value)); // fixme or fallback to string.Empty? CANNOT be null
set => _culture = value ?? throw new ArgumentNullException(nameof(value)); // TODO: or fallback to string.Empty? CANNOT be null
}
[JsonProperty("seg")]
public string Segment
{
get => _segment;
set => _segment = value ?? throw new ArgumentNullException(nameof(value)); // fixme or fallback to string.Empty? CANNOT be null
set => _segment = value ?? throw new ArgumentNullException(nameof(value)); // TODO: or fallback to string.Empty? CANNOT be null
}
[JsonProperty("val")]

View File

@@ -60,7 +60,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
case 'D':
return PrimitiveSerializer.DateTime.ReadFrom(stream);
default:
throw new NotSupportedException($"Cannot deserialize unknow type '{type}'.");
throw new NotSupportedException($"Cannot deserialize unknown type '{type}'.");
}
}

View File

@@ -13,12 +13,12 @@ namespace Umbraco.Web.PublishedCache.NuCache
internal class MediaCache : PublishedCacheBase, IPublishedMediaCache, INavigableData, IDisposable
{
private readonly ContentStore.Snapshot _snapshot;
private readonly ICacheProvider _snapshotCache;
private readonly ICacheProvider _elementsCache;
private readonly IAppCache _snapshotCache;
private readonly IAppCache _elementsCache;
#region Constructors
public MediaCache(bool previewDefault, ContentStore.Snapshot snapshot, ICacheProvider snapshotCache, ICacheProvider elementsCache)
public MediaCache(bool previewDefault, ContentStore.Snapshot snapshot, IAppCache snapshotCache, IAppCache elementsCache)
: base(previewDefault)
{
_snapshot = snapshot;
@@ -34,14 +34,14 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
// ignore preview, there's only draft for media
var n = _snapshot.Get(contentId);
return n?.Published;
return n?.PublishedModel;
}
public override IPublishedContent GetById(bool preview, Guid contentId)
{
// ignore preview, there's only draft for media
var n = _snapshot.Get(contentId);
return n?.Published;
return n?.PublishedModel;
}
public override bool HasById(bool preview, int contentId)
@@ -63,7 +63,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
return GetAtRootNoCache();
// note: ToArray is important here, we want to cache the result, not the function!
return (IEnumerable<IPublishedContent>)cache.GetCacheItem(
return (IEnumerable<IPublishedContent>)cache.Get(
CacheKeys.MediaCacheRoots(false), // ignore preview, only 1 key!
() => GetAtRootNoCache().ToArray());
}
@@ -73,7 +73,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
var c = _snapshot.GetAtRoot();
// ignore preview, there's only draft for media
return c.Select(n => n.Published);
return c.Select(n => n.PublishedModel);
}
public override bool HasContent(bool preview)

View File

@@ -17,18 +17,22 @@ namespace Umbraco.Web.PublishedCache.NuCache
internal class MemberCache : IPublishedMemberCache, INavigableData
{
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
public readonly IVariationContextAccessor VariationContextAccessor;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IEntityXmlSerializer _entitySerializer;
private readonly ICacheProvider _snapshotCache;
private readonly IAppCache _snapshotCache;
private readonly IMemberService _memberService;
private readonly PublishedContentTypeCache _contentTypeCache;
private readonly bool _previewDefault;
public MemberCache(bool previewDefault, ICacheProvider snapshotCache, IMemberService memberService, PublishedContentTypeCache contentTypeCache, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IEntityXmlSerializer entitySerializer)
public MemberCache(bool previewDefault, IAppCache snapshotCache, IMemberService memberService, PublishedContentTypeCache contentTypeCache,
IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IUmbracoContextAccessor umbracoContextAccessor, IEntityXmlSerializer entitySerializer)
{
_snapshotCache = snapshotCache;
_publishedSnapshotAccessor = publishedSnapshotAccessor;
VariationContextAccessor = variationContextAccessor;
_umbracoContextAccessor = umbracoContextAccessor;
_entitySerializer = entitySerializer;
_memberService = memberService;
_previewDefault = previewDefault;
@@ -64,14 +68,14 @@ namespace Umbraco.Web.PublishedCache.NuCache
var member = _memberService.GetById(memberId);
return member == null
? null
: PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor, VariationContextAccessor);
: PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor, VariationContextAccessor, _umbracoContextAccessor);
});
}
private IPublishedContent /*IPublishedMember*/ GetById(IMember member, bool previewing)
{
return GetCacheItem(CacheKeys.MemberCacheMember("ById", _previewDefault, member.Id), () =>
PublishedMember.Create(member, GetContentType(member.ContentTypeId), previewing, _publishedSnapshotAccessor, VariationContextAccessor));
PublishedMember.Create(member, GetContentType(member.ContentTypeId), previewing, _publishedSnapshotAccessor, VariationContextAccessor, _umbracoContextAccessor));
}
public IPublishedContent /*IPublishedMember*/ GetByProviderKey(object key)
@@ -106,7 +110,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
public IPublishedContent /*IPublishedMember*/ GetByMember(IMember member)
{
return PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor, VariationContextAccessor);
return PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor, VariationContextAccessor, _umbracoContextAccessor);
}
public IEnumerable<IPublishedContent> GetAtRoot(bool preview)
@@ -114,7 +118,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
// because members are flat (not a tree) everything is at root
// because we're loading everything... let's just not cache?
var members = _memberService.GetAllMembers();
return members.Select(m => PublishedMember.Create(m, GetContentType(m.ContentTypeId), preview, _publishedSnapshotAccessor, VariationContextAccessor));
return members.Select(m => PublishedMember.Create(m, GetContentType(m.ContentTypeId), preview, _publishedSnapshotAccessor, VariationContextAccessor, _umbracoContextAccessor));
}
public XPathNavigator CreateNavigator()

View File

@@ -20,7 +20,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.Navigable
// note - PublishedContentType are immutable ie they do not _change_ when the actual IContentTypeComposition
// changes, but they are replaced by a new instance, so our map here will clean itself automatically and
// we don't have to manage cache - ConditionalWeakTable does not prevent keys from beeing GCed
// we don't have to manage cache - ConditionalWeakTable does not prevent keys from being GCed
private static readonly ConditionalWeakTable<PublishedContentType, NavigableContentType> TypesMap
= new ConditionalWeakTable<PublishedContentType,NavigableContentType>();

View File

@@ -19,7 +19,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
composition.SetPublishedSnapshotService<PublishedSnapshotService>();
// add the NuCache health check (hidden from type finder)
// todo - no NuCache health check yet
// TODO: no NuCache health check yet
//composition.HealthChecks().Add<NuCacheIntegrityHealthCheck>();
}
}

View File

@@ -125,7 +125,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
CacheValues cacheValues;
PublishedSnapshot publishedSnapshot;
ICacheProvider cache;
IAppCache cache;
switch (cacheLevel)
{
case PropertyCacheLevel.None:
@@ -161,11 +161,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
return cacheValues;
}
private CacheValues GetCacheValues(ICacheProvider cache)
private CacheValues GetCacheValues(IAppCache cache)
{
if (cache == null) // no cache, don't cache
return new CacheValues();
return (CacheValues) cache.GetCacheItem(ValuesCacheKey, () => new CacheValues());
return (CacheValues) cache.Get(ValuesCacheKey, () => new CacheValues());
}
// this is always invoked from within a lock, so does not require its own lock

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Composing;
using Umbraco.Web.Models;
@@ -14,23 +13,27 @@ namespace Umbraco.Web.PublishedCache.NuCache
internal class PublishedContent : PublishedContentBase
{
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly ContentNode _contentNode;
// ReSharper disable once InconsistentNaming
internal readonly ContentData _contentData; // internal for ContentNode cloning
private readonly string _urlSegment;
#region Constructors
public PublishedContent(ContentNode contentNode, ContentData contentData, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor)
public PublishedContent(
ContentNode contentNode,
ContentData contentData,
IPublishedSnapshotAccessor publishedSnapshotAccessor,
IVariationContextAccessor variationContextAccessor,
IUmbracoContextAccessor umbracoContextAccessor) :base(umbracoContextAccessor)
{
_contentNode = contentNode;
_contentData = contentData;
ContentData = contentData;
_publishedSnapshotAccessor = publishedSnapshotAccessor;
_umbracoContextAccessor = umbracoContextAccessor;
VariationContextAccessor = variationContextAccessor;
_urlSegment = _contentData.Name.ToUrlSegment();
IsPreviewing = _contentData.Published == false;
_urlSegment = ContentData.Name.ToUrlSegment();
IsPreviewing = ContentData.Published == false;
var properties = new List<IPublishedProperty>();
foreach (var propertyType in _contentNode.ContentType.PropertyTypes)
@@ -48,7 +51,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
var cache = GetCurrentSnapshotCache();
return cache == null
? GetProfileNameByIdNoCache(id)
: (string)cache.GetCacheItem(CacheKeys.ProfileName(id), () => GetProfileNameByIdNoCache(id));
: (string)cache.Get(CacheKeys.ProfileName(id), () => GetProfileNameByIdNoCache(id));
}
private static string GetProfileNameByIdNoCache(int id)
@@ -66,12 +69,15 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
// (see ContentNode.CloneParent)
public PublishedContent(ContentNode contentNode, PublishedContent origin)
public PublishedContent(
ContentNode contentNode,
PublishedContent origin,
IUmbracoContextAccessor umbracoContextAccessor) :base(umbracoContextAccessor)
{
_contentNode = contentNode;
_publishedSnapshotAccessor = origin._publishedSnapshotAccessor;
VariationContextAccessor = origin.VariationContextAccessor;
_contentData = origin._contentData;
ContentData = origin.ContentData;
_urlSegment = origin._urlSegment;
IsPreviewing = origin.IsPreviewing;
@@ -83,12 +89,14 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
// clone for previewing as draft a published content that is published and has no draft
private PublishedContent(PublishedContent origin)
private PublishedContent(
PublishedContent origin,
IUmbracoContextAccessor umbracoContextAccessor) :base(umbracoContextAccessor)
{
_publishedSnapshotAccessor = origin._publishedSnapshotAccessor;
VariationContextAccessor = origin.VariationContextAccessor;
_contentNode = origin._contentNode;
_contentData = origin._contentData;
ContentData = origin.ContentData;
_urlSegment = origin._urlSegment;
IsPreviewing = true;
@@ -170,6 +178,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
#region PublishedContent
internal ContentData ContentData { get; }
/// <inheritdoc />
public override int Id => _contentNode.Id;
@@ -179,11 +189,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
get
{
if (!ContentType.VariesByCulture())
return _contentData.Name;
return ContentData.Name;
var culture = VariationContextAccessor?.VariationContext?.Culture ?? "";
if (culture == "")
return _contentData.Name;
return ContentData.Name;
return Cultures.TryGetValue(culture, out var cultureInfos) ? cultureInfos.Name : null;
}
@@ -215,7 +225,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
public override string Path => _contentNode.Path;
/// <inheritdoc />
public override int? TemplateId => _contentData.TemplateId;
public override int? TemplateId => ContentData.TemplateId;
/// <inheritdoc />
public override int CreatorId => _contentNode.CreatorId;
@@ -227,13 +237,13 @@ namespace Umbraco.Web.PublishedCache.NuCache
public override DateTime CreateDate => _contentNode.CreateDate;
/// <inheritdoc />
public override int WriterId => _contentData.WriterId;
public override int WriterId => ContentData.WriterId;
/// <inheritdoc />
public override string WriterName => GetProfileNameById(_contentData.WriterId);
public override string WriterName => GetProfileNameById(ContentData.WriterId);
/// <inheritdoc />
public override DateTime UpdateDate => _contentData.VersionDate;
public override DateTime UpdateDate => ContentData.VersionDate;
private IReadOnlyDictionary<string, PublishedCultureInfo> _cultureInfos;
@@ -263,9 +273,9 @@ namespace Umbraco.Web.PublishedCache.NuCache
if (_cultureInfos != null) return _cultureInfos;
if (_contentData.CultureInfos == null)
if (ContentData.CultureInfos == null)
throw new Exception("oops: _contentDate.CultureInfos is null.");
return _cultureInfos = _contentData.CultureInfos
return _cultureInfos = ContentData.CultureInfos
.ToDictionary(x => x.Key, x => new PublishedCultureInfo(x.Key, x.Value.Name, x.Value.Date), StringComparer.OrdinalIgnoreCase);
}
}
@@ -273,13 +283,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
/// <inheritdoc />
public override PublishedItemType ItemType => _contentNode.ContentType.ItemType;
// fixme
// was => _contentData.Published == false;
/// <inheritdoc />
public override bool IsDraft(string culture = null)
{
// if this is the 'published' published content, nothing can be draft
if (_contentData.Published)
if (ContentData.Published)
return false;
// not the 'published' published content, and does not vary = must be draft
@@ -292,7 +300,32 @@ namespace Umbraco.Web.PublishedCache.NuCache
// not the 'published' published content, and varies
// = depends on the culture
return _contentData.CultureInfos.TryGetValue(culture, out var cvar) && cvar.IsDraft;
return ContentData.CultureInfos.TryGetValue(culture, out var cvar) && cvar.IsDraft;
}
/// <inheritdoc />
public override bool IsPublished(string culture = null)
{
// whether we are the 'draft' or 'published' content, need to determine whether
// there is a 'published' version for the specified culture (or at all, for
// invariant content items)
// if there is no 'published' published content, no culture can be published
var hasPublished = _contentNode.PublishedContent != null;
if (!hasPublished)
return false;
// if there is a 'published' published content, and does not vary = published
if (!ContentType.VariesByCulture())
return true;
// handle context culture
if (culture == null)
culture = VariationContextAccessor?.VariationContext?.Culture ?? "";
// there is a 'published' published content, and varies
// = depends on the culture
return _contentNode.PublishedContent.ContentData.CultureInfos.ContainsKey(culture);
}
#endregion
@@ -328,7 +361,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
return GetChildren();
// note: ToArray is important here, we want to cache the result, not the function!
return (IEnumerable<IPublishedContent>)cache.GetCacheItem(ChildrenCacheKey, () => GetChildren().ToArray());
return (IEnumerable<IPublishedContent>)cache.Get(ChildrenCacheKey, () => GetChildren().ToArray());
}
}
@@ -355,7 +388,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
// notes:
// _contentNode.ChildContentIds is an unordered int[]
// need needs to fetch & sort - do it only once, lazyily, though
// needs to fetch & sort - do it only once, lazily, though
// Q: perfs-wise, is it better than having the store managed an ordered list
}
@@ -383,7 +416,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
#region Caching
// beware what you use that one for - you don't want to cache its result
private ICacheProvider GetAppropriateCache()
private IAppCache GetAppropriateCache()
{
var publishedSnapshot = (PublishedSnapshot)_publishedSnapshotAccessor.PublishedSnapshot;
var cache = publishedSnapshot == null
@@ -394,7 +427,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
return cache;
}
private ICacheProvider GetCurrentSnapshotCache()
private IAppCache GetCurrentSnapshotCache()
{
var publishedSnapshot = (PublishedSnapshot)_publishedSnapshotAccessor.PublishedSnapshot;
return publishedSnapshot?.SnapshotCache;
@@ -435,8 +468,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
return this;
var cache = GetAppropriateCache();
if (cache == null) return new PublishedContent(this).CreateModel();
return (IPublishedContent)cache.GetCacheItem(AsPreviewingCacheKey, () => new PublishedContent(this).CreateModel());
if (cache == null) return new PublishedContent(this, _umbracoContextAccessor).CreateModel();
return (IPublishedContent)cache.Get(AsPreviewingCacheKey, () => new PublishedContent(this, _umbracoContextAccessor).CreateModel());
}
// used by Navigable.Source,...

View File

@@ -15,13 +15,26 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
private readonly IMember _member;
private PublishedMember(IMember member, ContentNode contentNode, ContentData contentData, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor)
: base(contentNode, contentData, publishedSnapshotAccessor, variationContextAccessor)
private PublishedMember(
IMember member,
ContentNode contentNode,
ContentData contentData,
IPublishedSnapshotAccessor publishedSnapshotAccessor,
IVariationContextAccessor variationContextAccessor,
IUmbracoContextAccessor umbracoContextAccessor
)
: base(contentNode, contentData, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor)
{
_member = member;
}
public static IPublishedContent Create(IMember member, PublishedContentType contentType, bool previewing, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor)
public static IPublishedContent Create(
IMember member,
PublishedContentType contentType,
bool previewing,
IPublishedSnapshotAccessor publishedSnapshotAccessor,
IVariationContextAccessor variationContextAccessor,
IUmbracoContextAccessor umbracoContextAccessor)
{
var d = new ContentData
{
@@ -37,7 +50,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
member.Level, member.Path, member.SortOrder,
member.ParentId,
member.CreateDate, member.CreatorId);
return new PublishedMember(member, n, d, publishedSnapshotAccessor, variationContextAccessor).CreateModel();
return new PublishedMember(member, n, d, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor).CreateModel();
}
private static Dictionary<string, PropertyData[]> GetPropertyValues(PublishedContentType contentType, IMember member)

View File

@@ -25,8 +25,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
public MediaCache MediaCache;
public MemberCache MemberCache;
public DomainCache DomainCache;
public ICacheProvider SnapshotCache;
public ICacheProvider ElementsCache;
public IAppCache SnapshotCache;
public IAppCache ElementsCache;
public void Dispose()
{
@@ -48,9 +48,9 @@ namespace Umbraco.Web.PublishedCache.NuCache
#region Caches
public ICacheProvider SnapshotCache => Elements.SnapshotCache;
public IAppCache SnapshotCache => Elements.SnapshotCache;
public ICacheProvider ElementsCache => Elements.ElementsCache;
public IAppCache ElementsCache => Elements.ElementsCache;
#endregion

View File

@@ -32,6 +32,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
private readonly ServiceContext _serviceContext;
private readonly IPublishedContentTypeFactory _publishedContentTypeFactory;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IScopeProvider _scopeProvider;
private readonly IDataSource _dataSource;
private readonly ILogger _logger;
@@ -59,18 +60,18 @@ namespace Umbraco.Web.PublishedCache.NuCache
// define constant - determines whether to use cache when previewing
// to store eg routes, property converted values, anything - caching
// means faster execution, but uses memory - not sure if we want it
// so making it configureable.
// so making it configurable.
public static readonly bool FullCacheWhenPreviewing = true;
// define constant - determines whether to cache the published content
// objects (in the elements cache, or snapshot cache, depending on preview)
// or to refetch them all the time. caching is faster but uses more
// or to re-fetch them all the time. caching is faster but uses more
// memory. not sure what we want.
public static readonly bool CachePublishedContentChildren = true;
// define constant - determines whether to cache the content cache root
// objects (in the elements cache, or snapshot cache, depending on preview)
// or to refecth them all the time. caching is faster but uses more
// or to re-fetch them all the time. caching is faster but uses more
// memory - not sure what we want.
public static readonly bool CacheContentCacheRoots = true;
@@ -81,7 +82,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
public PublishedSnapshotService(Options options, IMainDom mainDom, IRuntimeState runtime,
ServiceContext serviceContext, IPublishedContentTypeFactory publishedContentTypeFactory, IdkMap idkMap,
IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor,
ILogger logger, IScopeProvider scopeProvider,
IUmbracoContextAccessor umbracoContextAccessor, ILogger logger, IScopeProvider scopeProvider,
IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository,
IDefaultCultureAccessor defaultCultureAccessor,
IDataSource dataSource, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper, IContentTypeService contentTypeService,
@@ -89,10 +90,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
: base(publishedSnapshotAccessor, variationContextAccessor)
{
//if (Interlocked.Increment(ref _singletonCheck) > 1)
// throw new Exception("Singleton must be instancianted only once!");
// throw new Exception("Singleton must be instantiated only once!");
_serviceContext = serviceContext;
_publishedContentTypeFactory = publishedContentTypeFactory;
_umbracoContextAccessor = umbracoContextAccessor;
_dataSource = dataSource;
_logger = logger;
_scopeProvider = scopeProvider;
@@ -142,21 +144,21 @@ namespace Umbraco.Web.PublishedCache.NuCache
var localMediaDbPath = IOHelper.MapPath("~/App_Data/NuCache.Media.db");
_localDbExists = System.IO.File.Exists(localContentDbPath) && System.IO.File.Exists(localMediaDbPath);
// if both local dbs exist then GetTree will open them, else new dbs will be created
// if both local databases exist then GetTree will open them, else new databases will be created
_localContentDb = BTree.GetTree(localContentDbPath, _localDbExists);
_localMediaDb = BTree.GetTree(localMediaDbPath, _localDbExists);
}
// stores are created with a db so they can write to it, but they do not read from it,
// stores need to be populated, happens in OnResolutionFrozen which uses _localDbExists to
// figure out whether it can read the dbs or it should populate them from sql
_contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger, _localContentDb);
_mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger, _localMediaDb);
// figure out whether it can read the databases or it should populate them from sql
_contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _umbracoContextAccessor, logger, _localContentDb);
_mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _umbracoContextAccessor, logger, _localMediaDb);
}
else
{
_contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger);
_mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger);
_contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _umbracoContextAccessor, logger);
_mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _umbracoContextAccessor, logger);
}
_domainStore = new SnapDictionary<int, Domain>();
@@ -196,14 +198,14 @@ namespace Umbraco.Web.PublishedCache.NuCache
_logger.Fatal<PublishedSnapshotService>(ex, "Panic, exception while loading cache data.");
}
// finaly, cache is ready!
// finally, cache is ready!
_isReady = true;
}
}
private void InitializeRepositoryEvents()
{
//fixme: The reason these events are in the repository is for legacy, the events should exist at the service
// TODO: The reason these events are in the repository is for legacy, the events should exist at the service
// level now since we can fire these events within the transaction... so move the events to service level
// plug repository event handlers
@@ -255,7 +257,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
//
//// indicates that the snapshot cache should reuse the application request cache
//// otherwise a new cache object would be created for the snapshot specifically,
//// which is the default - web boot manager uses this to optimze facades
//// which is the default - web boot manager uses this to optimize facades
//public bool PublishedSnapshotCacheIsApplicationRequestCache;
public bool IgnoreLocalDb;
@@ -586,7 +588,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
continue;
}
// fixme - should we do some RV check here? (later)
// TODO: should we do some RV check here? (later)
var capture = payload;
using (var scope = _scopeProvider.CreateScope())
@@ -676,7 +678,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
continue;
}
// fixme - should we do some RV checks here? (later)
// TODO: should we do some RV checks here? (later)
var capture = payload;
using (var scope = _scopeProvider.CreateScope())
@@ -775,7 +777,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
using (_contentStore.GetWriter(_scopeProvider))
using (_mediaStore.GetWriter(_scopeProvider))
{
// fixme - need to add a datatype lock
// TODO: need to add a datatype lock
// this is triggering datatypes reload in the factory, and right after we create some
// content types by loading them ... there's a race condition here, which would require
// some locking on datatypes
@@ -934,7 +936,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
#region Create, Get Published Snapshot
private long _contentGen, _mediaGen, _domainGen;
private ICacheProvider _elementsCache;
private IAppCache _elementsCache;
public override IPublishedSnapshot CreatePublishedSnapshot(string previewToken)
{
@@ -951,18 +953,19 @@ namespace Umbraco.Web.PublishedCache.NuCache
// even though the underlying elements may not change (store snapshots)
public PublishedSnapshot.PublishedSnapshotElements GetElements(bool previewDefault)
{
// note: using ObjectCacheRuntimeCacheProvider for elements and snapshot caches
// note: using ObjectCacheAppCache for elements and snapshot caches
// is not recommended because it creates an inner MemoryCache which is a heavy
// thing - better use a StaticCacheProvider which "just" creates a concurrent
// thing - better use a dictionary-based cache which "just" creates a concurrent
// dictionary
// for snapshot cache, StaticCacheProvider MAY be OK but it is not thread-safe,
// for snapshot cache, DictionaryAppCache MAY be OK but it is not thread-safe,
// nothing like that...
// for elements cache, StaticCacheProvider is a No-No, use something better.
// for elements cache, DictionaryAppCache is a No-No, use something better.
// ie FastDictionaryAppCache (thread safe and all)
ContentStore.Snapshot contentSnap, mediaSnap;
SnapDictionary<int, Domain>.Snapshot domainSnap;
ICacheProvider elementsCache;
IAppCache elementsCache;
lock (_storesLock)
{
var scopeContext = _scopeProvider.Context;
@@ -1000,11 +1003,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
_contentGen = contentSnap.Gen;
_mediaGen = mediaSnap.Gen;
_domainGen = domainSnap.Gen;
elementsCache = _elementsCache = new DictionaryCacheProvider();
elementsCache = _elementsCache = new FastDictionaryAppCache();
}
}
var snapshotCache = new StaticCacheProvider();
var snapshotCache = new DictionaryAppCache();
var memberTypeCache = new PublishedContentTypeCache(null, null, _serviceContext.MemberTypeService, _publishedContentTypeFactory, _logger);
@@ -1016,7 +1019,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
ContentCache = new ContentCache(previewDefault, contentSnap, snapshotCache, elementsCache, domainHelper, _globalSettings, _serviceContext.LocalizationService),
MediaCache = new MediaCache(previewDefault, mediaSnap, snapshotCache, elementsCache),
MemberCache = new MemberCache(previewDefault, snapshotCache, _serviceContext.MemberService, memberTypeCache, PublishedSnapshotAccessor, VariationContextAccessor, _entitySerializer),
MemberCache = new MemberCache(previewDefault, snapshotCache, _serviceContext.MemberService, memberTypeCache, PublishedSnapshotAccessor, VariationContextAccessor, _umbracoContextAccessor, _entitySerializer),
DomainCache = domainCache,
SnapshotCache = snapshotCache,
ElementsCache = elementsCache

View File

@@ -30,7 +30,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
private Task _collectTask;
private volatile int _wlocked;
// fixme - collection trigger (ok for now)
// minGenDelta to be adjusted
// we may want to throttle collects even if delta is reached
// we may want to force collect if delta is not reached but very old
@@ -59,7 +58,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
//
// so when getting a read-lock,
// either we are write-locked or not, but if not, we won't be write-locked
// otoh the write-lock may be released in the meantime
// on the other hand the write-lock may be released in the meantime
// Lock has a 'forceGen' parameter:
// used to start a set of changes that may not commit, to isolate the set from any pending
@@ -107,7 +106,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
// gets a scope contextual representing a locked writer to the dictionary
// fixme GetScopedWriter? should the dict have a ref onto the scope provider?
// GetScopedWriter? should the dict have a ref onto the scope provider?
public IDisposable GetWriter(IScopeProvider scopeProvider)
{
return ScopeContextualBase.Get(scopeProvider, _instanceId, scoped => new SnapDictionaryWriter(this, scoped));