NuCache: cleanup scoped objects

This commit is contained in:
Stephan
2019-02-22 15:27:22 +01:00
parent edb8340b32
commit 541c7e6955
2 changed files with 48 additions and 21 deletions

View File

@@ -2,24 +2,43 @@
namespace Umbraco.Core.Scoping
{
// base class for an object that will be enlisted in scope context, if any. it
// must be used in a 'using' block, and if not scoped, released when disposed,
// else when scope context runs enlisted actions
/// <summary>
/// Provides a base class for scope contextual objects.
/// </summary>
/// <remarks>
/// <para>A scope contextual object is enlisted in the current scope context,
/// if any, and released when the context exists. It must be used in a 'using'
/// block, and will be released when disposed, if not part of a scope.</para>
/// </remarks>
public abstract class ScopeContextualBase : IDisposable
{
private bool _using, _scoped;
/// <summary>
/// Gets a contextual object.
/// </summary>
/// <typeparam name="T">The type of the object.</typeparam>
/// <param name="scopeProvider">A scope provider.</param>
/// <param name="key">A context key for the object.</param>
/// <param name="ctor">A function producing the contextual object.</param>
/// <returns>The contextual object.</returns>
/// <remarks>
/// <para></para>
/// </remarks>
public static T Get<T>(IScopeProvider scopeProvider, string key, Func<bool, T> ctor)
where T : ScopeContextualBase
{
// no scope context = create a non-scoped object
var scopeContext = scopeProvider.Context;
if (scopeContext == null)
return ctor(false);
// create & enlist the scoped object
var w = scopeContext.Enlist("ScopeContextualBase_" + key,
() => ctor(true),
(completed, item) => { item.Release(completed); });
// the object can be 'used' only once at a time
if (w._using) throw new InvalidOperationException("panic: used.");
w._using = true;
w._scoped = true;
@@ -27,6 +46,10 @@ namespace Umbraco.Core.Scoping
return w;
}
/// <inheritdoc />
/// <remarks>
/// <para>If not scoped, then this releases the contextual object.</para>
/// </remarks>
public void Dispose()
{
_using = false;
@@ -35,6 +58,10 @@ namespace Umbraco.Core.Scoping
Release(true);
}
/// <summary>
/// Releases the contextual object.
/// </summary>
/// <param name="completed">A value indicating whether the scoped operation completed.</param>
public abstract void Release(bool completed);
}
}

View File

@@ -330,14 +330,15 @@ namespace Umbraco.Web.PublishedCache.NuCache
private void LockAndLoadContent(Action<IScope> action)
{
// first get a writer, then a scope
// if there already is a scope, the writer will attach to it
// otherwise, it will only exist here - cheap
using (_contentStore.GetWriter(_scopeProvider))
using (var scope = _scopeProvider.CreateScope())
{
using (var scope = _scopeProvider.CreateScope())
{
scope.ReadLock(Constants.Locks.ContentTree);
action(scope);
scope.Complete();
}
scope.ReadLock(Constants.Locks.ContentTree);
action(scope);
scope.Complete();
}
}
@@ -399,14 +400,13 @@ namespace Umbraco.Web.PublishedCache.NuCache
private void LockAndLoadMedia(Action<IScope> action)
{
// see note in LockAndLoadContent
using (_mediaStore.GetWriter(_scopeProvider))
using (var scope = _scopeProvider.CreateScope())
{
using (var scope = _scopeProvider.CreateScope())
{
scope.ReadLock(Constants.Locks.MediaTree);
action(scope);
scope.Complete();
}
scope.ReadLock(Constants.Locks.MediaTree);
action(scope);
scope.Complete();
}
}
@@ -528,14 +528,13 @@ namespace Umbraco.Web.PublishedCache.NuCache
private void LockAndLoadDomains()
{
// see note in LockAndLoadContent
using (_domainStore.GetWriter(_scopeProvider))
using (var scope = _scopeProvider.CreateScope())
{
using (var scope = _scopeProvider.CreateScope())
{
scope.ReadLock(Constants.Locks.Domains);
LoadDomainsLocked();
scope.Complete();
}
scope.ReadLock(Constants.Locks.Domains);
LoadDomainsLocked();
scope.Complete();
}
}
@@ -858,6 +857,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
if (_isReady == false)
return;
// see note in LockAndLoadContent
using (_domainStore.GetWriter(_scopeProvider))
{
foreach (var payload in payloads)