Removes Booting event, backports lazy changes for PublishedSnapshotService from v9.
This commit is contained in:
@@ -12,10 +12,5 @@ namespace Umbraco.Core.Sync
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
SyncBootState GetSyncBootState();
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the boot state is known
|
||||
/// </summary>
|
||||
event EventHandler<SyncBootState> Booting; // TODO: This should be removed in netcore
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
|
||||
internal class PublishedSnapshotService : PublishedSnapshotServiceBase
|
||||
{
|
||||
private readonly PublishedSnapshotServiceOptions _options;
|
||||
private readonly IMainDom _mainDom;
|
||||
private readonly ServiceContext _serviceContext;
|
||||
private readonly IPublishedContentTypeFactory _publishedContentTypeFactory;
|
||||
private readonly IScopeProvider _scopeProvider;
|
||||
@@ -50,12 +52,13 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
private readonly IDefaultCultureAccessor _defaultCultureAccessor;
|
||||
private readonly UrlSegmentProviderCollection _urlSegmentProviders;
|
||||
|
||||
// volatile because we read it with no lock
|
||||
private volatile bool _isReady;
|
||||
private bool _isReady;
|
||||
private bool _isReadSet;
|
||||
private object _isReadyLock;
|
||||
|
||||
private readonly ContentStore _contentStore;
|
||||
private readonly ContentStore _mediaStore;
|
||||
private readonly SnapDictionary<int, Domain> _domainStore;
|
||||
private ContentStore _contentStore;
|
||||
private ContentStore _mediaStore;
|
||||
private SnapDictionary<int, Domain> _domainStore;
|
||||
private readonly object _storesLock = new object();
|
||||
private readonly object _elementsLock = new object();
|
||||
|
||||
@@ -88,9 +91,12 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
ISyncBootStateAccessor syncBootStateAccessor)
|
||||
: base(publishedSnapshotAccessor, variationContextAccessor)
|
||||
{
|
||||
|
||||
//if (Interlocked.Increment(ref _singletonCheck) > 1)
|
||||
// throw new Exception("Singleton must be instantiated only once!");
|
||||
|
||||
_options = options;
|
||||
_mainDom = mainDom;
|
||||
_serviceContext = serviceContext;
|
||||
_publishedContentTypeFactory = publishedContentTypeFactory;
|
||||
_dataSource = dataSource;
|
||||
@@ -123,44 +129,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
if (runtime.Level != RuntimeLevel.Run)
|
||||
return;
|
||||
|
||||
// lock this entire call, we only want a single thread to be accessing the stores at once and within
|
||||
// the call below to mainDom.Register, a callback may occur on a threadpool thread to MainDomRelease
|
||||
// at the same time as we are trying to write to the stores. MainDomRelease also locks on _storesLock so
|
||||
// it will not be able to close the stores until we are done populating (if the store is empty)
|
||||
lock (_storesLock)
|
||||
{
|
||||
if (options.IgnoreLocalDb == false)
|
||||
{
|
||||
var registered = mainDom.Register(MainDomRegister, MainDomRelease);
|
||||
|
||||
// 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 databases or it should populate them from sql
|
||||
|
||||
_logger.Info<PublishedSnapshotService,bool>("Creating the content store, localContentDbExists? {LocalContentDbExists}", _localContentDbExists);
|
||||
_contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger, _localContentDb);
|
||||
_logger.Info<PublishedSnapshotService,bool>("Creating the media store, localMediaDbExists? {LocalMediaDbExists}", _localMediaDbExists);
|
||||
_mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger, _localMediaDb);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Info<PublishedSnapshotService>("Creating the content store (local db ignored)");
|
||||
_contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger);
|
||||
_logger.Info<PublishedSnapshotService>("Creating the media store (local db ignored)");
|
||||
_mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger);
|
||||
}
|
||||
|
||||
_domainStore = new SnapDictionary<int, Domain>();
|
||||
|
||||
_syncBootStateAccessor.Booting += (sender, args) =>
|
||||
{
|
||||
LoadCachesOnStartup(args);
|
||||
};
|
||||
}
|
||||
|
||||
Guid GetUid(ContentStore store, int id) => store.LiveSnapshot.Get(id)?.Uid ?? default;
|
||||
int GetId(ContentStore store, Guid uid) => store.LiveSnapshot.Get(uid)?.Id ?? default;
|
||||
|
||||
if (idkMap != null)
|
||||
{
|
||||
idkMap.SetMapper(UmbracoObjectTypes.Document, id => GetUid(_contentStore, id), uid => GetId(_contentStore, uid));
|
||||
@@ -168,6 +136,18 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
}
|
||||
}
|
||||
|
||||
private int GetId(ContentStore store, Guid uid)
|
||||
{
|
||||
EnsureCaches();
|
||||
return store.LiveSnapshot.Get(uid)?.Id ?? default;
|
||||
}
|
||||
|
||||
private Guid GetUid(ContentStore store, int id)
|
||||
{
|
||||
EnsureCaches();
|
||||
return store.LiveSnapshot.Get(id)?.Uid ?? default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Install phase of <see cref="IMainDom"/>
|
||||
/// </summary>
|
||||
@@ -219,51 +199,82 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates the stores
|
||||
/// Lazily populates the stores only when they are first requested
|
||||
/// </summary>
|
||||
/// <remarks>This is called inside of a lock for _storesLock</remarks>
|
||||
private void LoadCachesOnStartup(SyncBootState bootState)
|
||||
{
|
||||
// TODO: This is super ugly that this does this as part of the ctor.
|
||||
// In netcore this will be different, the initialization will happen
|
||||
// outside of the ctor.
|
||||
|
||||
var okContent = false;
|
||||
var okMedia = false;
|
||||
|
||||
try
|
||||
internal void EnsureCaches() => LazyInitializer.EnsureInitialized(
|
||||
ref _isReady,
|
||||
ref _isReadSet,
|
||||
ref _isReadyLock,
|
||||
() =>
|
||||
{
|
||||
if (bootState != SyncBootState.ColdBoot && _localContentDbExists)
|
||||
// lock this entire call, we only want a single thread to be accessing the stores at once and within
|
||||
// the call below to mainDom.Register, a callback may occur on a threadpool thread to MainDomRelease
|
||||
// at the same time as we are trying to write to the stores. MainDomRelease also locks on _storesLock so
|
||||
// it will not be able to close the stores until we are done populating (if the store is empty)
|
||||
lock (_storesLock)
|
||||
{
|
||||
okContent = LockAndLoadContent(scope => LoadContentFromLocalDbLocked(true));
|
||||
if (!okContent)
|
||||
_logger.Warn<PublishedSnapshotService>("Loading content from local db raised warnings, will reload from database.");
|
||||
if (!_options.IgnoreLocalDb)
|
||||
{
|
||||
var registered = _mainDom.Register(MainDomRegister, MainDomRelease);
|
||||
|
||||
// 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 databases or it should populate them from sql
|
||||
|
||||
_logger.Info<PublishedSnapshotService, bool>("Creating the content store, localContentDbExists? {LocalContentDbExists}", _localContentDbExists);
|
||||
_contentStore = new ContentStore(PublishedSnapshotAccessor, VariationContextAccessor, _logger, _localContentDb);
|
||||
_logger.Info<PublishedSnapshotService, bool>("Creating the media store, localMediaDbExists? {LocalMediaDbExists}", _localMediaDbExists);
|
||||
_mediaStore = new ContentStore(PublishedSnapshotAccessor, VariationContextAccessor, _logger, _localMediaDb);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Info<PublishedSnapshotService>("Creating the content store (local db ignored)");
|
||||
_contentStore = new ContentStore(PublishedSnapshotAccessor, VariationContextAccessor, _logger);
|
||||
_logger.Info<PublishedSnapshotService>("Creating the media store (local db ignored)");
|
||||
_mediaStore = new ContentStore(PublishedSnapshotAccessor, VariationContextAccessor, _logger);
|
||||
}
|
||||
|
||||
_domainStore = new SnapDictionary<int, Domain>();
|
||||
|
||||
SyncBootState bootState = _syncBootStateAccessor.GetSyncBootState();
|
||||
|
||||
var okContent = false;
|
||||
var okMedia = false;
|
||||
|
||||
try
|
||||
{
|
||||
if (bootState != SyncBootState.ColdBoot && _localContentDbExists)
|
||||
{
|
||||
okContent = LockAndLoadContent(scope => LoadContentFromLocalDbLocked(true));
|
||||
if (!okContent)
|
||||
_logger.Warn<PublishedSnapshotService>("Loading content from local db raised warnings, will reload from database.");
|
||||
}
|
||||
|
||||
if (bootState != SyncBootState.ColdBoot && _localMediaDbExists)
|
||||
{
|
||||
okMedia = LockAndLoadMedia(scope => LoadMediaFromLocalDbLocked(true));
|
||||
if (!okMedia)
|
||||
_logger.Warn<PublishedSnapshotService>("Loading media from local db raised warnings, will reload from database.");
|
||||
}
|
||||
|
||||
if (!okContent)
|
||||
LockAndLoadContent(scope => LoadContentFromDatabaseLocked(scope, true));
|
||||
|
||||
if (!okMedia)
|
||||
LockAndLoadMedia(scope => LoadMediaFromDatabaseLocked(scope, true));
|
||||
|
||||
LockAndLoadDomains();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Fatal<PublishedSnapshotService>(ex, "Panic, exception while loading cache data.");
|
||||
throw;
|
||||
}
|
||||
|
||||
// finally, cache is ready!
|
||||
return true;
|
||||
}
|
||||
|
||||
if (bootState != SyncBootState.ColdBoot && _localMediaDbExists)
|
||||
{
|
||||
okMedia = LockAndLoadMedia(scope => LoadMediaFromLocalDbLocked(true));
|
||||
if (!okMedia)
|
||||
_logger.Warn<PublishedSnapshotService>("Loading media from local db raised warnings, will reload from database.");
|
||||
}
|
||||
|
||||
if (!okContent)
|
||||
LockAndLoadContent(scope => LoadContentFromDatabaseLocked(scope, true));
|
||||
|
||||
if (!okMedia)
|
||||
LockAndLoadMedia(scope => LoadMediaFromDatabaseLocked(scope, true));
|
||||
|
||||
LockAndLoadDomains();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Fatal<PublishedSnapshotService>(ex, "Panic, exception while loading cache data.");
|
||||
throw;
|
||||
}
|
||||
|
||||
// finally, cache is ready!
|
||||
_isReady = true;
|
||||
}
|
||||
});
|
||||
|
||||
private void InitializeRepositoryEvents()
|
||||
{
|
||||
@@ -1146,9 +1157,13 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
|
||||
public override IPublishedSnapshot CreatePublishedSnapshot(string previewToken)
|
||||
{
|
||||
EnsureCaches();
|
||||
|
||||
// no cache, no joy
|
||||
if (_isReady == false)
|
||||
if (Volatile.Read(ref _isReady) == false)
|
||||
{
|
||||
throw new InvalidOperationException("The published snapshot service has not properly initialized.");
|
||||
}
|
||||
|
||||
var preview = previewToken.IsNullOrWhiteSpace() == false;
|
||||
return new PublishedSnapshot(this, preview);
|
||||
@@ -1159,6 +1174,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
// even though the underlying elements may not change (store snapshots)
|
||||
public PublishedSnapshot.PublishedSnapshotElements GetElements(bool previewDefault)
|
||||
{
|
||||
EnsureCaches();
|
||||
|
||||
// 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 dictionary-based cache which "just" creates a concurrent
|
||||
@@ -1805,6 +1822,8 @@ AND cmsContentNu.nodeId IS NULL
|
||||
|
||||
public void Collect()
|
||||
{
|
||||
EnsureCaches();
|
||||
|
||||
var contentCollect = _contentStore.CollectAsync();
|
||||
var mediaCollect = _mediaStore.CollectAsync();
|
||||
System.Threading.Tasks.Task.WaitAll(contentCollect, mediaCollect);
|
||||
@@ -1814,8 +1833,17 @@ AND cmsContentNu.nodeId IS NULL
|
||||
|
||||
#region Internals/Testing
|
||||
|
||||
internal ContentStore GetContentStore() => _contentStore;
|
||||
internal ContentStore GetMediaStore() => _mediaStore;
|
||||
internal ContentStore GetContentStore()
|
||||
{
|
||||
EnsureCaches();
|
||||
return _contentStore;
|
||||
}
|
||||
|
||||
internal ContentStore GetMediaStore()
|
||||
{
|
||||
EnsureCaches();
|
||||
return _mediaStore;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -29,26 +29,10 @@ namespace Umbraco.Web.Search
|
||||
_indexRebuilder = indexRebuilder;
|
||||
_mainDom = mainDom;
|
||||
_syncBootStateAccessor = syncBootStateAccessor;
|
||||
|
||||
// must add the handler in the ctor because it will be too late in Initialize
|
||||
// TODO: All of this boot synchronization for cold boot logic needs should be fixed in netcore
|
||||
_syncBootStateAccessor.Booting += _syncBootStateAccessor_Booting;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Once the boot state is known we can see if we require rebuilds
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void _syncBootStateAccessor_Booting(object sender, SyncBootState e)
|
||||
{
|
||||
UmbracoModule.RouteAttempt += UmbracoModule_RouteAttempt;
|
||||
}
|
||||
|
||||
private void UmbracoModule_RouteAttempt(object sender, RoutableAttemptEventArgs e)
|
||||
{
|
||||
UmbracoModule.RouteAttempt -= UmbracoModule_RouteAttempt;
|
||||
|
||||
if (!_initialized)
|
||||
{
|
||||
lock (_locker)
|
||||
@@ -58,6 +42,8 @@ namespace Umbraco.Web.Search
|
||||
{
|
||||
_initialized = true;
|
||||
|
||||
UmbracoModule.RouteAttempt -= UmbracoModule_RouteAttempt;
|
||||
|
||||
if (!_mainDom.IsMainDom) return;
|
||||
|
||||
var bootState = _syncBootStateAccessor.GetSyncBootState();
|
||||
@@ -74,12 +60,12 @@ namespace Umbraco.Web.Search
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
{
|
||||
UmbracoModule.RouteAttempt += UmbracoModule_RouteAttempt;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
_syncBootStateAccessor.Booting -= _syncBootStateAccessor_Booting;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user