From c77174059d41ffc69cbbbe940b2d508bf4b8096a Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 31 Oct 2016 11:06:17 +0100 Subject: [PATCH] Backport MainDom cleanup from 7.6 --- src/Umbraco.Core/MainDom.cs | 68 +++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Core/MainDom.cs b/src/Umbraco.Core/MainDom.cs index fb8ad06999..8e7efc5171 100644 --- a/src/Umbraco.Core/MainDom.cs +++ b/src/Umbraco.Core/MainDom.cs @@ -1,18 +1,21 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.IO.MemoryMappedFiles; -using System.Text; using System.Threading; -using System.Threading.Tasks; using System.Web.Hosting; using Umbraco.Core.Logging; -using Umbraco.Core.ObjectResolution; namespace Umbraco.Core { - // represents the main domain - class MainDom : IRegisteredObject + /// + /// Represents the main AppDomain running for a given application. + /// + /// + /// There can be only one "main" AppDomain running for a given application at a time. + /// When an AppDomain starts, it tries to acquire the main domain status. + /// When an AppDomain stops (eg the application is restarting) it should release the main domain status. + /// It is possible to register against the MainDom and be notified when it is released. + /// + internal class MainDom : IRegisteredObject { #region Vars @@ -34,16 +37,26 @@ namespace Umbraco.Core private volatile bool _signaled; // we have been signaled // actions to run before releasing the main domain - private readonly SortedList _callbacks = new SortedList(); + private readonly SortedList _callbacks = new SortedList(new WeightComparer()); private const int LockTimeoutMilliseconds = 90000; // (1.5 * 60 * 1000) == 1 min 30 seconds + private class WeightComparer : IComparer + { + public int Compare(int x, int y) + { + var result = x.CompareTo(y); + // return "equal" as "greater than" + return result == 0 ? 1 : result; + } + } + #endregion #region Ctor // initializes a new instance of MainDom - public MainDom(ILogger logger) + internal MainDom(ILogger logger) { _logger = logger; @@ -52,22 +65,47 @@ namespace Umbraco.Core if (HostingEnvironment.ApplicationID != null) appId = HostingEnvironment.ApplicationID.ReplaceNonAlphanumericChars(string.Empty); - var lockName = "UMBRACO-" + appId + "-MAINDOM-LCK"; + // combining with the physical path because if running on eg IIS Express, + // two sites could have the same appId even though they are different. + // + // now what could still collide is... two sites, running in two different processes + // and having the same appId, and running on the same app physical path + // + // we *cannot* use the process ID here because when an AppPool restarts it is + // a new process for the same application path + + var appPath = HostingEnvironment.ApplicationPhysicalPath; + var hash = (appId + ":::" + appPath).ToSHA1(); + + var lockName = "UMBRACO-" + hash + "-MAINDOM-LCK"; _asyncLock = new AsyncLock(lockName); - var eventName = "UMBRACO-" + appId + "-MAINDOM-EVT"; + var eventName = "UMBRACO-" + hash + "-MAINDOM-EVT"; _signal = new EventWaitHandle(false, EventResetMode.AutoReset, eventName); } #endregion - // register a main domain consumer + /// + /// Registers a resource that requires the current AppDomain to be the main domain to function. + /// + /// An action to execute before the AppDomain releases the main domain status. + /// An optional weight (lower goes first). + /// A value indicating whether it was possible to register. public bool Register(Action release, int weight = 100) { return Register(null, release, weight); } - // register a main domain consumer + /// + /// Registers a resource that requires the current AppDomain to be the main domain to function. + /// + /// An action to execute when registering. + /// An action to execute before the AppDomain releases the main domain status. + /// An optional weight (lower goes first). + /// A value indicating whether it was possible to register. + /// If registering is successful, then the action + /// is guaranteed to execute before the AppDomain releases the main domain status. public bool Register(Action install, Action release, int weight = 100) { lock (_locko) @@ -123,7 +161,7 @@ namespace Umbraco.Core } // acquires the main domain - public bool Acquire() + internal bool Acquire() { lock (_locko) // we don't want the hosting environment to interfere by signaling { @@ -174,7 +212,7 @@ namespace Umbraco.Core } // IRegisteredObject - public void Stop(bool immediate) + void IRegisteredObject.Stop(bool immediate) { try {