U4-9422 - complete implementing scoped xml cache
This commit is contained in:
@@ -30,8 +30,9 @@ namespace Umbraco.Core.Cache
|
||||
private void RegisterDirty()
|
||||
{
|
||||
// use unique names to de-duplicate
|
||||
_scope.OnExit("dirty_" + typeof (TEntity).Name,
|
||||
() => _globalIsolatedCache.ClearAllCache());
|
||||
// enlisting multiple times is not a problem
|
||||
_scope.Enlist("dirty_" + typeof (TEntity).Name, ActionTime.BeforeDispose,
|
||||
(actionTime, completed) => { if (completed) _globalIsolatedCache.ClearAllCache(); });
|
||||
}
|
||||
|
||||
public TEntity Get(TId id, Func<TId, TEntity> performGet, Func<TId[], IEnumerable<TEntity>> performGetAll)
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
namespace Umbraco.Core.Scoping
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Scoping
|
||||
{
|
||||
[Flags]
|
||||
public enum ActionTime
|
||||
{
|
||||
BeforeCommit,
|
||||
BeforeEvent,
|
||||
BeforeDispose
|
||||
None = 0,
|
||||
BeforeCommit = 1,
|
||||
BeforeEvent = 2,
|
||||
BeforeDispose = 4
|
||||
}
|
||||
}
|
||||
@@ -36,25 +36,50 @@ namespace Umbraco.Core.Scoping
|
||||
/// </summary>
|
||||
void Complete();
|
||||
|
||||
///// <summary>
|
||||
///// Registers an action to execute on exit.
|
||||
///// </summary>
|
||||
///// <param name="key">The unique key of the action.</param>
|
||||
///// <param name="action">The action.</param>
|
||||
///// <remarks>
|
||||
///// <para>The key is unique (as in, dictionary key).</para>
|
||||
///// <para>The action will execute only if the scope completes.</para>
|
||||
///// </remarks>
|
||||
//void OnExit(string key, Action action);
|
||||
|
||||
///// <remarks>
|
||||
///// <para>The key is unique (as in, dictionary key).</para>
|
||||
///// <para>The action always executes, with an argument indicating whether the scope completed.</para>
|
||||
///// </remarks>
|
||||
//void OnExit(string key, Action<bool> action);
|
||||
|
||||
/// <summary>
|
||||
/// Registers an action to execute on exit.
|
||||
/// Enlists an object into the scope.
|
||||
/// </summary>
|
||||
/// <param name="key">The unique key of the action.</param>
|
||||
/// <param name="action">The action.</param>
|
||||
/// <remarks>
|
||||
/// <para>The key is unique (as in, dictionary key).</para>
|
||||
/// <para>The action will execute only if the scope completes.</para>
|
||||
/// </remarks>
|
||||
void OnExit(string key, Action action);
|
||||
/// <typeparam name="T">The type of the object.</typeparam>
|
||||
/// <param name="key">The unique key.</param>
|
||||
/// <param name="creator">A method creating the object.</param>
|
||||
/// <returns>The object.</returns>
|
||||
T Enlist<T>(string key, Func<T> creator);
|
||||
|
||||
/// <remarks>
|
||||
/// <para>The key is unique (as in, dictionary key).</para>
|
||||
/// <para>The action always executes, with an argument indicating whether the scope completed.</para>
|
||||
/// </remarks>
|
||||
void OnExit(string key, Action<bool> action);
|
||||
/// <summary>
|
||||
/// Enlists an action into the scope.
|
||||
/// </summary>
|
||||
/// <param name="key">The unique key.</param>
|
||||
/// <param name="actionTimes">When to execute the action.</param>
|
||||
/// <param name="action">The action to execute.</param>
|
||||
void Enlist(string key, ActionTime actionTimes, Action<ActionTime, bool> action);
|
||||
|
||||
// fixme
|
||||
T Enlist<T>(string key, Func<T> creator, Action<ActionTime, bool, T> action);
|
||||
/// <summary>
|
||||
/// Enlists an object and an action into the scope.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object.</typeparam>
|
||||
/// <param name="key">The unique key.</param>
|
||||
/// <param name="creator">A method creating the object.</param>
|
||||
/// <param name="actionTimes">When to execute the action.</param>
|
||||
/// <param name="action">The action to execute.</param>
|
||||
/// <returns>The object.</returns>
|
||||
T Enlist<T>(string key, Func<T> creator, ActionTime actionTimes, Action<ActionTime, bool, T> action);
|
||||
|
||||
#if DEBUG_SCOPES
|
||||
Guid InstanceId { get; }
|
||||
|
||||
@@ -84,19 +84,19 @@ namespace Umbraco.Core.Scoping
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnExit(string key, Action action)
|
||||
public T Enlist<T>(string key, Func<T> creator)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnExit(string key, Action<bool> action)
|
||||
public T Enlist<T>(string key, Func<T> creator, ActionTime actionTimes, Action<ActionTime, bool, T> action)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
// fixme
|
||||
public T Enlist<T>(string key, Func<T> creator, Action<ActionTime, bool, T> action)
|
||||
/// <inheritdoc />
|
||||
public void Enlist(string key, ActionTime actionTimes, Action<ActionTime, bool> action)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Umbraco.Core.Scoping
|
||||
private IsolatedRuntimeCache _isolatedRuntimeCache;
|
||||
private UmbracoDatabase _database;
|
||||
private IList<EventMessage> _messages;
|
||||
private IDictionary<string, Action<bool>> _exitActions;
|
||||
private IDictionary<string, IEnlistedObject> _enlisted;
|
||||
|
||||
// this is v7, in v8 this has to change to RepeatableRead
|
||||
private const IsolationLevel DefaultIsolationLevel = IsolationLevel.ReadCommitted;
|
||||
@@ -258,31 +258,18 @@ namespace Umbraco.Core.Scoping
|
||||
}
|
||||
}
|
||||
|
||||
// run everything we need to run when completing
|
||||
List<Exception> exceptions = null;
|
||||
foreach (var action in ExitActions.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
action(completed); // fixme try catch and everything
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (exceptions == null)
|
||||
exceptions = new List<Exception>();
|
||||
exceptions.Add(e);
|
||||
}
|
||||
}
|
||||
if (exceptions != null)
|
||||
throw new AggregateException("Exceptions were throws by complete actions.", exceptions);
|
||||
|
||||
// run enlisted actions
|
||||
exceptions = null;
|
||||
RunEnlisted(ActionTime.BeforeDispose, completed);
|
||||
}
|
||||
|
||||
private void RunEnlisted(ActionTime actionTime, bool completed)
|
||||
{
|
||||
List<Exception> exceptions = null;
|
||||
foreach (var enlisted in Enlisted.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
enlisted.Execute(ActionTime.BeforeDispose, completed);
|
||||
enlisted.Execute(actionTime, completed);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -292,34 +279,9 @@ namespace Umbraco.Core.Scoping
|
||||
}
|
||||
}
|
||||
if (exceptions != null)
|
||||
throw new AggregateException("Exceptions were thrown by listed actions at ActionTime.BeforeDispose.", exceptions);
|
||||
throw new AggregateException("Exceptions were thrown by listed actions at ActionTime " + actionTime + ".", exceptions);
|
||||
}
|
||||
|
||||
private IDictionary<string, Action<bool>> ExitActions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ParentScope != null) return ParentScope.ExitActions;
|
||||
|
||||
return _exitActions ?? (_exitActions
|
||||
= new Dictionary<string, Action<bool>>());
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnExit(string key, Action action)
|
||||
{
|
||||
ExitActions[key] = completed => { if (completed) action(); };
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnExit(string key, Action<bool> action)
|
||||
{
|
||||
ExitActions[key] = action;
|
||||
}
|
||||
|
||||
private IDictionary<string, IEnlistedObject> _enlisted;
|
||||
|
||||
private IDictionary<string, IEnlistedObject> Enlisted
|
||||
{
|
||||
get
|
||||
@@ -338,11 +300,19 @@ namespace Umbraco.Core.Scoping
|
||||
|
||||
private class EnlistedObject<T> : IEnlistedObject
|
||||
{
|
||||
private readonly ActionTime _actionTimes;
|
||||
private readonly Action<ActionTime, bool, T> _action;
|
||||
|
||||
public EnlistedObject(T item, Action<ActionTime, bool, T> action)
|
||||
public EnlistedObject(T item)
|
||||
{
|
||||
Item = item;
|
||||
_actionTimes = ActionTime.None;
|
||||
}
|
||||
|
||||
public EnlistedObject(T item, ActionTime actionTimes, Action<ActionTime, bool, T> action)
|
||||
{
|
||||
Item = item;
|
||||
_actionTimes = actionTimes;
|
||||
_action = action;
|
||||
}
|
||||
|
||||
@@ -350,11 +320,13 @@ namespace Umbraco.Core.Scoping
|
||||
|
||||
public void Execute(ActionTime actionTime, bool completed)
|
||||
{
|
||||
_action(actionTime, completed, Item);
|
||||
if (_actionTimes.HasFlag(actionTime))
|
||||
_action(actionTime, completed, Item);
|
||||
}
|
||||
}
|
||||
|
||||
public T Enlist<T>(string key, Func<T> creator, Action<ActionTime, bool, T> action)
|
||||
/// <inheritdoc />
|
||||
public T Enlist<T>(string key, Func<T> creator)
|
||||
{
|
||||
IEnlistedObject enlisted;
|
||||
if (Enlisted.TryGetValue(key, out enlisted))
|
||||
@@ -363,9 +335,38 @@ namespace Umbraco.Core.Scoping
|
||||
if (enlistedAs == null) throw new Exception("An item with a different type has already been enlisted with the same key.");
|
||||
return enlistedAs.Item;
|
||||
}
|
||||
var enlistedOfT = new EnlistedObject<T>(creator(), action);
|
||||
var enlistedOfT = new EnlistedObject<T>(creator());
|
||||
Enlisted[key] = enlistedOfT;
|
||||
return enlistedOfT.Item;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public T Enlist<T>(string key, Func<T> creator, ActionTime actionTimes, Action<ActionTime, bool, T> action)
|
||||
{
|
||||
IEnlistedObject enlisted;
|
||||
if (Enlisted.TryGetValue(key, out enlisted))
|
||||
{
|
||||
var enlistedAs = enlisted as EnlistedObject<T>;
|
||||
if (enlistedAs == null) throw new Exception("An item with a different type has already been enlisted with the same key.");
|
||||
return enlistedAs.Item;
|
||||
}
|
||||
var enlistedOfT = new EnlistedObject<T>(creator(), actionTimes, action);
|
||||
Enlisted[key] = enlistedOfT;
|
||||
return enlistedOfT.Item;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Enlist(string key, ActionTime actionTimes, Action<ActionTime, bool> action)
|
||||
{
|
||||
IEnlistedObject enlisted;
|
||||
if (Enlisted.TryGetValue(key, out enlisted))
|
||||
{
|
||||
var enlistedAs = enlisted as EnlistedObject<object>;
|
||||
if (enlistedAs == null) throw new Exception("An item with a different type has already been enlisted with the same key.");
|
||||
return;
|
||||
}
|
||||
var enlistedOfT = new EnlistedObject<object>(null, actionTimes, (actionTime, completed, item) => action(actionTime, completed));
|
||||
Enlisted[key] = enlistedOfT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -421,7 +421,7 @@ namespace Umbraco.Tests.Scoping
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void ScopeAction(bool complete)
|
||||
public void ScopeEnlist(bool complete)
|
||||
{
|
||||
var scopeProvider = DatabaseContext.ScopeProvider;
|
||||
|
||||
@@ -430,7 +430,7 @@ namespace Umbraco.Tests.Scoping
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
using (var scope = scopeProvider.CreateScope())
|
||||
{
|
||||
((Scope) scope).OnExit("name", x => completed = x);
|
||||
scope.Enlist("name", ActionTime.BeforeDispose, (a, c) => { completed = c; });
|
||||
if (complete)
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
@@ -759,9 +759,9 @@ namespace umbraco
|
||||
var releaser = instance._xmlLock.Lock();
|
||||
return new SafeXmlReaderWriter(instance, releaser, writer, true);
|
||||
},
|
||||
ActionTime.BeforeDispose,
|
||||
(actionTime, completed, item) => // action
|
||||
{
|
||||
if (actionTime != ActionTime.BeforeDispose) return;
|
||||
item.DisposeForReal(completed);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user