Fixes deadlock

This commit is contained in:
Shannon
2020-01-03 12:39:17 +11:00
parent a46e9124d2
commit 3d8e9a78e3

View File

@@ -4,6 +4,7 @@ using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using CSharpTest.Net.Collections;
using Newtonsoft.Json;
using Umbraco.Core;
@@ -54,6 +55,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
private readonly ContentStore _mediaStore;
private readonly SnapDictionary<int, Domain> _domainStore;
private readonly object _storesLock = new object();
private readonly object _elementsLock = new object();
private BPlusTree<int, ContentNodeKit> _localContentDb;
private BPlusTree<int, ContentNodeKit> _localMediaDb;
@@ -143,7 +145,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
_domainStore = new SnapDictionary<int, Domain>();
LoadCachesOnStartup();
LoadCachesOnStartup();
}
Guid GetUid(ContentStore store, int id) => store.LiveSnapshot.Get(id)?.Uid ?? default;
@@ -171,7 +173,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
var path = GetLocalFilesPath();
var localContentDbPath = Path.Combine(path, "NuCache.Content.db");
var localMediaDbPath = Path.Combine(path, "NuCache.Media.db");
_localContentDbExists = File.Exists(localContentDbPath);
_localMediaDbExists = File.Exists(localMediaDbPath);
@@ -221,7 +223,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
okContent = LockAndLoadContent(scope => LoadContentFromLocalDbLocked(true));
if (!okContent)
_logger.Warn<PublishedSnapshotService>("Loading content from local db raised warnings, will reload from database.");
_logger.Warn<PublishedSnapshotService>("Loading content from local db raised warnings, will reload from database.");
}
if (_localMediaDbExists)
@@ -1147,12 +1149,12 @@ namespace Umbraco.Web.PublishedCache.NuCache
SnapDictionary<int, Domain>.Snapshot domainSnap;
IAppCache elementsCache;
// TODO: Idea... TryGetElements? Might check if we are shutting down and return false and callers to this could handle it?
// Else does a readerwriterlockslim work here? (i don't think so)
// Else we have 2x locks, one for startup/shutdown, the other for getting elements and then we can maybe do a Monitor.Try?
// That is sort of the same as a TryGetElements
// Here we are reading/writing to shared objects so we need to lock (can't be _storesLock which manages the actual nucache files
// and would result in a deadlock). Even though we are locking around underlying readlocks (within CreateSnapshot) it's because
// we need to ensure that the result of contentSnap.Gen (etc) and the re-assignment of these values and _elements cache
// are done atomically.
lock (_storesLock)
lock (_elementsLock)
{
var scopeContext = _scopeProvider.Context;
@@ -1177,14 +1179,14 @@ namespace Umbraco.Web.PublishedCache.NuCache
// elements
// just need to make sure nothing gets elements in another enlisted action... so using
// a MaxValue to make sure this one runs last, and it should be ok
// ... else there is potential to deadlock since this would recursively go back into trying
// lock on _storesLock but another thread may have already tried that
scopeContext.Enlist("Umbraco.Web.PublishedCache.NuCache.PublishedSnapshotService.Resync", () => this, (completed, svc) =>
{
((PublishedSnapshot)svc.CurrentPublishedSnapshot)?.Resync();
}, int.MaxValue);
}
// create a new snapshot cache if snapshots are different gens
if (contentSnap.Gen != _contentGen || mediaSnap.Gen != _mediaGen || domainSnap.Gen != _domainGen || _elementsCache == null)
{
@@ -1351,7 +1353,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
//culture changed on an existing language
var cultureChanged = e.SavedEntities.Any(x => !x.WasPropertyDirty(nameof(ILanguage.Id)) && x.WasPropertyDirty(nameof(ILanguage.IsoCode)));
if(cultureChanged)
if (cultureChanged)
{
RebuildContentDbCache();
}