Bugfix exception during install, live models collision

This commit is contained in:
Stephan
2019-02-22 19:13:25 +01:00
parent 04e916b41c
commit aa86dfa956
9 changed files with 58 additions and 40 deletions

View File

@@ -30,7 +30,7 @@ namespace Umbraco.Core.Composing
protected override IComponent CreateItem(IFactory factory, Type itemType)
{
using (_logger.DebugDuration<Composers>($"Creating {itemType.FullName}.", $"Created {itemType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
using (_logger.DebugDuration<ComponentCollectionBuilder>($"Creating {itemType.FullName}.", $"Created {itemType.FullName}.", thresholdMilliseconds: LogThresholdMilliseconds))
{
return base.CreateItem(factory, itemType);
}

View File

@@ -0,0 +1,33 @@
using System;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core
{
/// <summary>
/// Provides extension methods for <see cref="IPublishedModelFactory"/>.
/// </summary>
public static class PublishedModelFactoryExtensions
{
/// <summary>
/// Executes an action with a safe live factory/
/// </summary>
/// <remarks>
/// <para>If the factory is a live factory, ensures it is refreshed and locked while executing the action.</para>
/// </remarks>
public static void WithSafeLiveFactory(this IPublishedModelFactory factory, Action action)
{
if (factory is ILivePublishedModelFactory liveFactory)
{
lock (liveFactory.SyncRoot)
{
liveFactory.Refresh();
action();
}
}
else
{
action();
}
}
}
}

View File

@@ -212,6 +212,7 @@
<Compile Include="Models\PublishedContent\ILivePublishedModelFactory.cs" />
<Compile Include="PropertyEditors\DateTimeConfiguration.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\RenameLabelAndRichTextPropertyEditorAliases.cs" />
<Compile Include="PublishedModelFactoryExtensions.cs" />
<Compile Include="Services\PropertyValidationService.cs" />
<Compile Include="TypeLoaderExtensions.cs" />
<Compile Include="Composing\WeightAttribute.cs" />

View File

@@ -180,8 +180,8 @@ namespace Umbraco.Tests.PublishedContent
dataSource,
globalSettings,
new SiteDomainHelper(),
contentTypeServiceBaseFactory,
Mock.Of<IEntityXmlSerializer>());
Mock.Of<IEntityXmlSerializer>(),
Mock.Of<IPublishedModelFactory>());
// invariant is the current default
_variationAccesor.VariationContext = new VariationContext();

View File

@@ -97,8 +97,9 @@ namespace Umbraco.Tests.Scoping
documentRepository, mediaRepository, memberRepository,
DefaultCultureAccessor,
new DatabaseDataSource(),
Factory.GetInstance<IGlobalSettings>(), new SiteDomainHelper(), contentTypeServiceBaseFactory,
Factory.GetInstance<IEntityXmlSerializer>());
Factory.GetInstance<IGlobalSettings>(), new SiteDomainHelper(),
Factory.GetInstance<IEntityXmlSerializer>(),
Mock.Of<IPublishedModelFactory>());
}
protected UmbracoContext GetUmbracoContextNu(string url, int templateId = 1234, RouteData routeData = null, bool setSingleton = false, IUmbracoSettingsSection umbracoSettings = null, IEnumerable<IUrlProvider> urlProviders = null)

View File

@@ -70,8 +70,9 @@ namespace Umbraco.Tests.Services
documentRepository, mediaRepository, memberRepository,
DefaultCultureAccessor,
new DatabaseDataSource(),
Factory.GetInstance<IGlobalSettings>(), new SiteDomainHelper(), contentTypeServiceBaseFactory,
Factory.GetInstance<IEntityXmlSerializer>());
Factory.GetInstance<IGlobalSettings>(), new SiteDomainHelper(),
Factory.GetInstance<IEntityXmlSerializer>(),
Mock.Of<IPublishedModelFactory>());
}
public class LocalServerMessenger : ServerMessengerBase

View File

@@ -1,5 +1,6 @@
using System;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
@@ -82,20 +83,8 @@ namespace Umbraco.Web.Cache
// service of changes, else factories may try to rebuild models while
// we are using the database to load content into caches
// ReSharper disable once SuspiciousTypeConversion.Global
if (_publishedModelFactory is ILivePublishedModelFactory live)
{
lock (live.SyncRoot)
{
live.Refresh();
_publishedSnapshotService.Notify(payloads);
}
}
else
{
// ReSharper disable once InconsistentlySynchronizedField
_publishedSnapshotService.Notify(payloads);
}
_publishedModelFactory.WithSafeLiveFactory(() =>
_publishedSnapshotService.Notify(payloads));
// now we can trigger the event
base.Refresh(payloads);

View File

@@ -1,4 +1,5 @@
using System;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
@@ -65,20 +66,8 @@ namespace Umbraco.Web.Cache
// service of changes, else factories may try to rebuild models while
// we are using the database to load content into caches
// ReSharper disable once SuspiciousTypeConversion.Global
if (_publishedModelFactory is ILivePublishedModelFactory live)
{
lock (live.SyncRoot)
{
live.Refresh();
_publishedSnapshotService.Notify(payloads);
}
}
else
{
// ReSharper disable once InconsistentlySynchronizedField
_publishedSnapshotService.Notify(payloads);
}
_publishedModelFactory.WithSafeLiveFactory(() =>
_publishedSnapshotService.Notify(payloads));
base.Refresh(payloads);
}

View File

@@ -44,9 +44,9 @@ namespace Umbraco.Web.PublishedCache.NuCache
private readonly IMemberRepository _memberRepository;
private readonly IGlobalSettings _globalSettings;
private readonly ISiteDomainHelper _siteDomainHelper;
private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider;
private readonly IEntityXmlSerializer _entitySerializer;
private readonly IDefaultCultureAccessor _defaultCultureAccessor;
private readonly IPublishedModelFactory _publishedModelFactory;
// volatile because we read it with no lock
private volatile bool _isReady;
@@ -88,8 +88,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
IUmbracoContextAccessor umbracoContextAccessor, ILogger logger, IScopeProvider scopeProvider,
IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository,
IDefaultCultureAccessor defaultCultureAccessor,
IDataSource dataSource, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider,
IEntityXmlSerializer entitySerializer)
IDataSource dataSource, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper,
IEntityXmlSerializer entitySerializer, IPublishedModelFactory publishedModelFactory)
: base(publishedSnapshotAccessor, variationContextAccessor)
{
//if (Interlocked.Increment(ref _singletonCheck) > 1)
@@ -107,7 +107,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
_defaultCultureAccessor = defaultCultureAccessor;
_globalSettings = globalSettings;
_siteDomainHelper = siteDomainHelper;
_contentTypeBaseServiceProvider = contentTypeBaseServiceProvider;
_publishedModelFactory = publishedModelFactory;
// we need an Xml serializer here so that the member cache can support XPath,
// for members this is done by navigating the serialized-to-xml member
@@ -167,7 +167,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
_domainStore = new SnapDictionary<int, Domain>();
LoadCaches();
_publishedModelFactory.WithSafeLiveFactory(LoadCaches);
Guid GetUid(ContentStore store, int id) => store.LiveSnapshot.Get(id)?.Uid ?? default;
int GetId(ContentStore store, Guid uid) => store.LiveSnapshot.Get(uid)?.Id ?? default;
@@ -571,6 +571,10 @@ namespace Umbraco.Web.PublishedCache.NuCache
// because now we should ALWAYS run with the database server messenger, and then the RefreshAll will
// be processed as soon as we are configured and the messenger processes instructions.
// note: notifications for content type and data type changes should be invoked with the
// pure live model factory, if any, locked and refreshed - see ContentTypeCacheRefresher and
// DataTypeCacheRefresher
public override void Notify(ContentCacheRefresher.JsonPayload[] payloads, out bool draftChanged, out bool publishedChanged)
{
// no cache, trash everything