Ensure more ReaderWriterLockSlim are disposed or converted

This commit is contained in:
Shannon
2021-04-20 17:56:55 +10:00
parent 7e332b23c9
commit bf7a3251d8
6 changed files with 101 additions and 30 deletions

View File

@@ -21,7 +21,7 @@ using File = System.IO.File;
namespace Umbraco.ModelsBuilder.Embedded
{
internal class PureLiveModelFactory : ILivePublishedModelFactory2, IRegisteredObject
internal class PureLiveModelFactory : ILivePublishedModelFactory2, IRegisteredObject, IDisposable
{
private Assembly _modelsAssembly;
private Infos _infos = new Infos { ModelInfos = null, ModelTypeMap = new Dictionary<string, Type>() };
@@ -33,6 +33,7 @@ namespace Umbraco.ModelsBuilder.Embedded
private int _ver, _skipver;
private readonly int _debugLevel;
private BuildManager _theBuildManager;
private bool _disposedValue;
private readonly Lazy<UmbracoServices> _umbracoServices; // fixme: this is because of circular refs :(
private UmbracoServices UmbracoServices => _umbracoServices.Value;
@@ -677,11 +678,31 @@ namespace Umbraco.ModelsBuilder.Embedded
public void Stop(bool immediate)
{
_watcher.EnableRaisingEvents = false;
_watcher.Dispose();
Dispose();
HostingEnvironment.UnregisterObject(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing)
{
_watcher.EnableRaisingEvents = false;
_watcher.Dispose();
_locker.Dispose();
}
_disposedValue = true;
}
}
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
}
#endregion
}
}

View File

@@ -16,7 +16,7 @@ namespace Umbraco.Web.Logging
/// </remarks>
internal class WebProfilerProvider : AspNetRequestProvider
{
private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim();
private readonly object _locker = new object();
private MiniProfiler _startupProfiler;
private int _first;
private volatile BootPhase _bootPhase;
@@ -39,8 +39,7 @@ namespace Umbraco.Web.Logging
public void BeginBootRequest()
{
_locker.EnterWriteLock();
try
lock (_locker)
{
if (_bootPhase != BootPhase.Boot)
throw new InvalidOperationException("Invalid boot phase.");
@@ -48,28 +47,19 @@ namespace Umbraco.Web.Logging
// assign the profiler to be the current MiniProfiler for the request
// is's already active, starting and all
HttpContext.Current.Items[":mini-profiler:"] = _startupProfiler;
}
finally
{
_locker.ExitWriteLock();
HttpContext.Current.Items[":mini-profiler:"] = _startupProfiler;
}
}
public void EndBootRequest()
{
_locker.EnterWriteLock();
try
lock (_locker)
{
if (_bootPhase != BootPhase.BootRequest)
throw new InvalidOperationException("Invalid boot phase.");
throw new InvalidOperationException("Invalid boot phase.");
_bootPhase = BootPhase.Booted;
_startupProfiler = null;
}
finally
{
_locker.ExitWriteLock();
_startupProfiler = null;
}
}

View File

@@ -13,7 +13,7 @@ using Umbraco.Web.PublishedCache.NuCache.Navigable;
namespace Umbraco.Web.PublishedCache.NuCache
{
internal class MemberCache : IPublishedMemberCache, INavigableData
internal class MemberCache : IPublishedMemberCache, INavigableData, IDisposable
{
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
@@ -23,6 +23,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
private readonly IMemberService _memberService;
private readonly PublishedContentTypeCache _contentTypeCache;
private readonly bool _previewDefault;
private bool _disposedValue;
public MemberCache(bool previewDefault, IAppCache snapshotCache, IMemberService memberService, PublishedContentTypeCache contentTypeCache,
IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IEntityXmlSerializer entitySerializer)
@@ -158,6 +159,25 @@ namespace Umbraco.Web.PublishedCache.NuCache
return _contentTypeCache.Get(PublishedItemType.Member, alias);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing)
{
_contentTypeCache.Dispose();
}
_disposedValue = true;
}
}
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
}
#endregion
}
}

View File

@@ -32,6 +32,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
ContentCache.Dispose();
MediaCache.Dispose();
MemberCache.Dispose();
}
}

View File

@@ -13,7 +13,7 @@ namespace Umbraco.Web.PublishedCache
/// Represents a content type cache.
/// </summary>
/// <remarks>This cache is not snapshotted, so it refreshes any time things change.</remarks>
public class PublishedContentTypeCache
public class PublishedContentTypeCache : IDisposable
{
// NOTE: These are not concurrent dictionaries because all access is done within a lock
private readonly Dictionary<string, IPublishedContentType> _typesByAlias = new Dictionary<string, IPublishedContentType>();
@@ -320,6 +320,8 @@ namespace Umbraco.Web.PublishedCache
// for unit tests - changing the callback must reset the cache obviously
// TODO: Why does this even exist? For testing you'd pass in a mocked service to get by id
private Func<int, IPublishedContentType> _getPublishedContentTypeById;
private bool _disposedValue;
internal Func<int, IPublishedContentType> GetPublishedContentTypeById
{
get => _getPublishedContentTypeById;
@@ -367,5 +369,24 @@ namespace Umbraco.Web.PublishedCache
{
return GetAliasKey(contentType.ItemType, contentType.Alias);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing)
{
_lock.Dispose();
}
_disposedValue = true;
}
}
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
}
}
}

View File

@@ -4,13 +4,14 @@ using System.Linq;
using System.Threading;
using System.Text.RegularExpressions;
using Umbraco.Core;
using System.ComponentModel;
namespace Umbraco.Web.Routing
{
/// <summary>
/// Provides utilities to handle site domains.
/// </summary>
public class SiteDomainHelper : ISiteDomainHelper
public class SiteDomainHelper : ISiteDomainHelper, IDisposable
{
#region Configure
@@ -18,6 +19,7 @@ namespace Umbraco.Web.Routing
private static Dictionary<string, string[]> _sites;
private static Dictionary<string, List<string>> _bindings;
private static Dictionary<string, Dictionary<string, string[]>> _qualifiedSites;
private bool _disposedValue;
// these are for unit tests *only*
// ReSharper disable ConvertToAutoPropertyWithPrivateSetter
@@ -30,16 +32,10 @@ namespace Umbraco.Web.Routing
private const string DomainValidationSource = @"^(((?i:http[s]?://)?([-\w]+(\.[-\w]+)*)(:\d+)?(/)?))$";
private static readonly Regex DomainValidation = new Regex(DomainValidationSource, RegexOptions.IgnoreCase | RegexOptions.Compiled);
/// <summary>
/// Returns a disposable object that represents safe write access to config.
/// </summary>
/// <remarks>Should be used in a <c>using(SiteDomainHelper.ConfigWriteLock) { ... }</c> mode.</remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
protected static IDisposable ConfigWriteLock => new WriteLock(ConfigLock);
/// <summary>
/// Returns a disposable object that represents safe read access to config.
/// </summary>
/// <remarks>Should be used in a <c>using(SiteDomainHelper.ConfigWriteLock) { ... }</c> mode.</remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
protected static IDisposable ConfigReadLock => new ReadLock(ConfigLock);
/// <summary>
@@ -313,6 +309,28 @@ namespace Umbraco.Web.Routing
return ret;
}
#endregion
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing)
{
// This is pretty nasty disposing a static on an instance but it's because this whole class
// is pretty fubar. I'm sure we've fixed this all up in netcore now? We need to remove all statics.
ConfigLock.Dispose();
}
_disposedValue = true;
}
}
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
}
}
}