Core.Resolution - fix concurrency issues
Conflicts: src/Umbraco.Core/ObjectResolution/Resolution.cs
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
@@ -12,9 +14,10 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// </remarks>
|
||||
internal static class Resolution
|
||||
{
|
||||
private static readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
|
||||
private static readonly ReaderWriterLockSlim ConfigurationLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
|
||||
private volatile static bool _isFrozen;
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Occurs when resolution is frozen.
|
||||
/// </summary>
|
||||
/// <remarks>Occurs only once, since resolution can be frozen only once.</remarks>
|
||||
@@ -23,14 +26,27 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether resolution of objects is frozen.
|
||||
/// </summary>
|
||||
public static bool IsFrozen { get; private set; }
|
||||
|
||||
public static void EnsureIsFrozen()
|
||||
// internal for unit tests, use ReadFrozen if you want to be sure
|
||||
internal static bool IsFrozen
|
||||
{
|
||||
if (!IsFrozen)
|
||||
throw new InvalidOperationException("Resolution is not frozen, it is not yet possible to get values from it.");
|
||||
get
|
||||
{
|
||||
using (new ReadLock(ConfigurationLock))
|
||||
{
|
||||
return _isFrozen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IDisposable Reader(bool canReadUnfrozen = false)
|
||||
{
|
||||
IDisposable l = new ReadLock(ConfigurationLock);
|
||||
if (canReadUnfrozen || _isFrozen) return l;
|
||||
|
||||
l.Dispose();
|
||||
throw new InvalidOperationException("Resolution is not frozen, it is not yet possible to get values from it.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a disposable object that represents safe access to unfrozen resolution configuration.
|
||||
/// </summary>
|
||||
@@ -39,13 +55,11 @@ namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
get
|
||||
{
|
||||
IDisposable l = new WriteLock(_lock);
|
||||
if (Resolution.IsFrozen)
|
||||
{
|
||||
l.Dispose();
|
||||
throw new InvalidOperationException("Resolution is frozen, it is not possible to configure it anymore.");
|
||||
}
|
||||
return l;
|
||||
IDisposable l = new WriteLock(ConfigurationLock);
|
||||
if (_isFrozen == false) return l;
|
||||
|
||||
l.Dispose();
|
||||
throw new InvalidOperationException("Resolution is frozen, it is not possible to configure it anymore.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,21 +79,24 @@ namespace Umbraco.Core.ObjectResolution
|
||||
// keep the class here because it needs write-access to Resolution.IsFrozen
|
||||
private class DirtyBackdoor : IDisposable
|
||||
{
|
||||
private static readonly System.Threading.ReaderWriterLockSlim _dirtyLock = new ReaderWriterLockSlim();
|
||||
|
||||
private IDisposable _lock;
|
||||
private bool _frozen;
|
||||
private readonly IDisposable _lock;
|
||||
private readonly bool _frozen;
|
||||
|
||||
public DirtyBackdoor()
|
||||
{
|
||||
_lock = new WriteLock(_dirtyLock);
|
||||
_frozen = Resolution.IsFrozen;
|
||||
Resolution.IsFrozen = false;
|
||||
LogHelper.Debug(typeof(DirtyBackdoor), "Creating back door for resolution");
|
||||
|
||||
_lock = new WriteLock(ConfigurationLock);
|
||||
_frozen = _isFrozen;
|
||||
_isFrozen = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Resolution.IsFrozen = _frozen;
|
||||
LogHelper.Debug(typeof(DirtyBackdoor), "Disposing back door for resolution");
|
||||
|
||||
_isFrozen = _frozen;
|
||||
_lock.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -90,11 +107,17 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// <exception cref="InvalidOperationException">resolution is already frozen.</exception>
|
||||
public static void Freeze()
|
||||
{
|
||||
if (Resolution.IsFrozen)
|
||||
throw new InvalidOperationException("Resolution is frozen. It is not possible to freeze it again.");
|
||||
LogHelper.Debug(typeof(Resolution), "Freezing resolution");
|
||||
|
||||
IsFrozen = true;
|
||||
if (Frozen != null)
|
||||
using (new WriteLock(ConfigurationLock))
|
||||
{
|
||||
if (_isFrozen)
|
||||
throw new InvalidOperationException("Resolution is frozen. It is not possible to freeze it again.");
|
||||
|
||||
_isFrozen = true;
|
||||
}
|
||||
|
||||
if (Frozen != null)
|
||||
Frozen(null, null);
|
||||
}
|
||||
|
||||
@@ -104,7 +127,20 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// <remarks>To be used in unit tests.</remarks>
|
||||
internal static void Reset()
|
||||
{
|
||||
IsFrozen = false;
|
||||
LogHelper.Debug(typeof(Resolution), "Resetting resolution");
|
||||
|
||||
/*
|
||||
var trace = new System.Diagnostics.StackTrace();
|
||||
var testing = trace.GetFrames().Any(frame =>
|
||||
frame.GetMethod().DeclaringType.FullName.StartsWith("Umbraco.Tests"));
|
||||
if (testing == false)
|
||||
throw new InvalidOperationException("Only unit tests can reset configuration.");
|
||||
*/
|
||||
|
||||
using (new WriteLock(ConfigurationLock))
|
||||
{
|
||||
_isFrozen = false;
|
||||
}
|
||||
Frozen = null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user