diff --git a/src/Umbraco.Core/Cache/CacheKeys.cs b/src/Umbraco.Core/Cache/CacheKeys.cs index 6ef00c5e85..570c44f75d 100644 --- a/src/Umbraco.Core/Cache/CacheKeys.cs +++ b/src/Umbraco.Core/Cache/CacheKeys.cs @@ -6,7 +6,7 @@ namespace Umbraco.Core.Cache /// public static class CacheKeys { - public const string MediaCacheKey = "GetMedia"; + public const string MediaCacheKey = "UL_GetMedia"; //NOTE: pretty sure this is never used anymore internal const string MacroRuntimeCacheKey = "UmbracoRuntimeMacroCache"; @@ -16,7 +16,7 @@ namespace Umbraco.Core.Cache public const string MacroHtmlDateAddedCacheKey = "macroHtml_DateAdded_"; public const string MacroControlDateAddedCacheKey = "macroControl_DateAdded_"; - public const string MemberCacheKey = "GetMember"; + public const string MemberCacheKey = "UL_GetMember"; public const string TemplateCacheKey = "template"; diff --git a/src/Umbraco.Core/Configuration/UmbracoVersion.cs b/src/Umbraco.Core/Configuration/UmbracoVersion.cs index 908426637c..583e1097bf 100644 --- a/src/Umbraco.Core/Configuration/UmbracoVersion.cs +++ b/src/Umbraco.Core/Configuration/UmbracoVersion.cs @@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration { public class UmbracoVersion { - private static readonly Version Version = new Version("6.1.0"); + private static readonly Version Version = new Version("6.0.3"); /// /// Gets the current version of Umbraco. diff --git a/src/Umbraco.Core/Sync/DefaultServerMessenger.cs b/src/Umbraco.Core/Sync/DefaultServerMessenger.cs index 9176a94728..50750dbde0 100644 --- a/src/Umbraco.Core/Sync/DefaultServerMessenger.cs +++ b/src/Umbraco.Core/Sync/DefaultServerMessenger.cs @@ -17,9 +17,12 @@ namespace Umbraco.Core.Sync /// internal class DefaultServerMessenger : IServerMessenger { - private readonly string _login; - private readonly string _password; - private readonly bool _useDistributedCalls; + private readonly Func> _getUserNamePasswordDelegate; + private volatile bool _hasResolvedDelegate = false; + private readonly object _locker = new object(); + private string _login; + private string _password; + private bool _useDistributedCalls; /// /// Without a username/password all distribuion will be disabled @@ -36,11 +39,23 @@ namespace Umbraco.Core.Sync /// internal DefaultServerMessenger(string login, string password) { + if (login == null) throw new ArgumentNullException("login"); + if (password == null) throw new ArgumentNullException("password"); + _useDistributedCalls = UmbracoSettings.UseDistributedCalls; _login = login; _password = password; } + /// + /// Allows to set a lazy delegate to resolve the username/password + /// + /// + public DefaultServerMessenger(Func> getUserNamePasswordDelegate) + { + _getUserNamePasswordDelegate = getUserNamePasswordDelegate; + } + public void PerformRefresh(IEnumerable servers, ICacheRefresher refresher,Func getNumericId, params T[] instances) { if (servers == null) throw new ArgumentNullException("servers"); @@ -160,6 +175,47 @@ namespace Umbraco.Core.Sync } } + /// + /// If we are instantiated with a lazy delegate to get the username/password, we'll resolve it here + /// + private void EnsureLazyUsernamePasswordDelegateResolved() + { + if (!_hasResolvedDelegate && _getUserNamePasswordDelegate != null) + { + lock (_locker) + { + if (!_hasResolvedDelegate) + { + _hasResolvedDelegate = true; //set flag + + try + { + var result = _getUserNamePasswordDelegate(); + if (result == null) + { + _login = null; + _password = null; + _useDistributedCalls = false; + } + else + { + _login = result.Item1; + _password = result.Item2; + _useDistributedCalls = UmbracoSettings.UseDistributedCalls; + } + } + catch (Exception ex) + { + LogHelper.Error("Could not resolve username/password delegate, server distribution will be disabled", ex); + _login = null; + _password = null; + _useDistributedCalls = false; + } + } + } + } + } + private void InvokeMethodOnRefresherInstance(ICacheRefresher refresher, MessageType dispatchType, IEnumerable ids) { if (refresher == null) throw new ArgumentNullException("refresher"); @@ -212,6 +268,8 @@ namespace Umbraco.Core.Sync if (servers == null) throw new ArgumentNullException("servers"); if (refresher == null) throw new ArgumentNullException("refresher"); + EnsureLazyUsernamePasswordDelegateResolved(); + //Now, check if we are using Distrubuted calls. If there are no servers in the list then we // can definitely not distribute. if (!_useDistributedCalls || !servers.Any()) diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 93e7035e83..f061f7369b 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -2469,7 +2469,7 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\" True 61637 / - http://localhost:61639/VirtualDir + http://localhost:61638 False False diff --git a/src/Umbraco.Web.UI/config/ExamineIndex.Release.config b/src/Umbraco.Web.UI/config/ExamineIndex.Release.config index b7342a75b0..00222f4b85 100644 --- a/src/Umbraco.Web.UI/config/ExamineIndex.Release.config +++ b/src/Umbraco.Web.UI/config/ExamineIndex.Release.config @@ -7,11 +7,12 @@ Index/Search providers can be defined in the UmbracoSettings.config More information and documentation can be found on CodePlex: http://umbracoexamine.codeplex.com --> + - + diff --git a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs index fd660a38db..3037ccd5c1 100644 --- a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs +++ b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs @@ -19,7 +19,12 @@ namespace Umbraco.Web.Cache { if (UmbracoSettings.UmbracoLibraryCacheDuration <= 0) return; - //Bind to content events - currently used for macro clearing + //Bind to content events - currently used for: + // - macro clearing + // - clearing the xslt cache (MS.Internal.Xml.XPath.XPathSelectionIterator) + //NOTE: These are 'special' event handlers that will only clear cache for items on the current server + // that is because this event will fire based on a distributed cache call, meaning this event fires on + // all servers based on the distributed cache call for updating content. content.AfterUpdateDocumentCache += content_AfterUpdateDocumentCache; content.AfterClearDocumentCache += content_AfterClearDocumentCache; @@ -61,7 +66,8 @@ namespace Umbraco.Web.Cache /// void content_AfterClearDocumentCache(global::umbraco.cms.businesslogic.web.Document sender, DocumentCacheEventArgs e) { - DistributedCache.Instance.ClearAllMacroCache(); + DistributedCache.Instance.ClearAllMacroCacheOnCurrentServer(); + DistributedCache.Instance.ClearXsltCacheOnCurrentServer(); } /// @@ -71,7 +77,8 @@ namespace Umbraco.Web.Cache /// void content_AfterUpdateDocumentCache(global::umbraco.cms.businesslogic.web.Document sender, DocumentCacheEventArgs e) { - DistributedCache.Instance.ClearAllMacroCache(); + DistributedCache.Instance.ClearAllMacroCacheOnCurrentServer(); + DistributedCache.Instance.ClearXsltCacheOnCurrentServer(); } static void UserDeleting(User sender, System.EventArgs e) diff --git a/src/Umbraco.Web/Cache/DistributedCache.cs b/src/Umbraco.Web/Cache/DistributedCache.cs index 6793454894..02146aa7f4 100644 --- a/src/Umbraco.Web/Cache/DistributedCache.cs +++ b/src/Umbraco.Web/Cache/DistributedCache.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Net; using System.Threading; using System.Web.Services.Protocols; @@ -113,9 +114,24 @@ namespace Umbraco.Web.Cache /// /// The unique identifier. public void RefreshAll(Guid factoryGuid) + { + RefreshAll(factoryGuid, true); + } + + /// + /// Sends a request to all registered load-balanced servers to refresh all nodes + /// using the specified ICacheRefresher with the guid factoryGuid. + /// + /// The unique identifier. + /// + /// If true will send the request out to all registered LB servers, if false will only execute the current server + /// + public void RefreshAll(Guid factoryGuid, bool allServers) { ServerMessengerResolver.Current.Messenger.PerformRefreshAll( - ServerRegistrarResolver.Current.Registrar.Registrations, + allServers + ? ServerRegistrarResolver.Current.Registrar.Registrations + : Enumerable.Empty(), //this ensures it will only execute against the current server GetRefresherById(factoryGuid)); } diff --git a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs index 11a251a511..989ddd5355 100644 --- a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs +++ b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Umbraco.Core; using Umbraco.Core.Models; using umbraco; @@ -210,12 +211,21 @@ namespace Umbraco.Web.Cache } /// - /// Clears the cache for all macros + /// Clears the cache for all macros on the current server /// /// - public static void ClearAllMacroCache(this DistributedCache dc) + public static void ClearAllMacroCacheOnCurrentServer(this DistributedCache dc) { - dc.RefreshAll(new Guid(DistributedCache.MacroCacheRefresherId)); + //NOTE: The 'false' ensure that it will only refresh on the current server, not post to all servers + dc.RefreshAll(new Guid(DistributedCache.MacroCacheRefresherId), false); + } + + public static void ClearXsltCacheOnCurrentServer(this DistributedCache dc) + { + if (UmbracoSettings.UmbracoLibraryCacheDuration > 0) + { + ApplicationContext.Current.ApplicationCache.ClearCacheObjectTypes("MS.Internal.Xml.XPath.XPathSelectionIterator"); + } } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/MediaCacheRefresher.cs b/src/Umbraco.Web/Cache/MediaCacheRefresher.cs index 4deeb324a6..b3bdc201a9 100644 --- a/src/Umbraco.Web/Cache/MediaCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MediaCacheRefresher.cs @@ -53,12 +53,12 @@ namespace Umbraco.Web.Cache foreach (var idPart in media.Path.Split(',')) { ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch( - string.Format("UL_{0}_{1}_True", CacheKeys.MediaCacheKey, idPart)); + string.Format("{0}_{1}_True", CacheKeys.MediaCacheKey, idPart)); // Also clear calls that only query this specific item! if (idPart == media.Id.ToString()) ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch( - string.Format("UL_{0}_{1}", CacheKeys.MediaCacheKey, media.Id)); + string.Format("{0}_{1}", CacheKeys.MediaCacheKey, media.Id)); } } diff --git a/src/Umbraco.Web/Cache/MemberCacheRefresher.cs b/src/Umbraco.Web/Cache/MemberCacheRefresher.cs index 3e8e82f54d..63608e5560 100644 --- a/src/Umbraco.Web/Cache/MemberCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MemberCacheRefresher.cs @@ -41,7 +41,7 @@ namespace Umbraco.Web.Cache private void ClearCache(int id) { ApplicationContext.Current.ApplicationCache. - ClearCacheByKeySearch(string.Format("UL_{0}_{1}", CacheKeys.MemberCacheKey, id)); + ClearCacheByKeySearch(string.Format("{0}_{1}", CacheKeys.MemberCacheKey, id)); } public void Refresh(Member instance) diff --git a/src/Umbraco.Web/WebBootManager.cs b/src/Umbraco.Web/WebBootManager.cs index 48a836bc7c..9f46825b41 100644 --- a/src/Umbraco.Web/WebBootManager.cs +++ b/src/Umbraco.Web/WebBootManager.cs @@ -234,23 +234,27 @@ namespace Umbraco.Web { base.InitializeResolvers(); - //we should not proceed to change this if the app/database is not configured since there will - // be no user, plus we don't need to have server messages sent if this is the case. - if (ApplicationContext.IsConfigured && ApplicationContext.DatabaseContext.IsDatabaseConfigured) + //Override the ServerMessengerResolver to set a username/password for the distributed calls + ServerMessengerResolver.Current.SetServerMessenger(new DefaultServerMessenger(() => { - var user = User.GetUser(UmbracoSettings.DistributedCallUser); - try - { - //Override the ServerMessengerResolver to set a username/password for the distributed calls - ServerMessengerResolver.Current.SetServerMessenger(new DefaultServerMessenger( - user.LoginName, - user.GetPassword())); + //we should not proceed to change this if the app/database is not configured since there will + // be no user, plus we don't need to have server messages sent if this is the case. + if (ApplicationContext.IsConfigured && ApplicationContext.DatabaseContext.IsDatabaseConfigured) + { + try + { + var user = User.GetUser(UmbracoSettings.DistributedCallUser); + return new System.Tuple(user.LoginName, user.GetPassword()); + } + catch (Exception e) + { + LogHelper.Error("An error occurred trying to set the IServerMessenger during application startup", e); + return null; + } } - catch (Exception e) - { - LogHelper.Error("An error occurred trying to set the IServerMessenger during application startup", e); - } - } + LogHelper.Warn("Could not initialize the DefaultServerMessenger, the application is not configured or the database is not configured"); + return null; + })); //We are going to manually remove a few cache refreshers here because we've obsoleted them and we don't want them // to be registered more than once diff --git a/src/Umbraco.Web/umbraco.presentation/content.cs b/src/Umbraco.Web/umbraco.presentation/content.cs index cf7c21ef65..32200560a5 100644 --- a/src/Umbraco.Web/umbraco.presentation/content.cs +++ b/src/Umbraco.Web/umbraco.presentation/content.cs @@ -137,18 +137,7 @@ namespace umbraco set { lock (XmlContentInternalSyncLock) - { - //SD: Cache clearance moved to event handling: CacheRefresherEventHandler - //// Clear macro cache - //Cache.ClearCacheObjectTypes("umbraco.MacroCacheContent"); - //Cache.ClearCacheByKeySearch(CacheKeys.MacroHtmlCacheKey); - - // Clear library cache - if (UmbracoSettings.UmbracoLibraryCacheDuration > 0) - { - Cache.ClearCacheObjectTypes("MS.Internal.Xml.XPath.XPathSelectionIterator"); - } - + { _xmlContent = value; if (!UmbracoSettings.isXmlContentCacheDisabled && UmbracoSettings.continouslyUpdateXmlDiskCache) diff --git a/src/Umbraco.Web/umbraco.presentation/library.cs b/src/Umbraco.Web/umbraco.presentation/library.cs index 739c69ef0f..98482ee785 100644 --- a/src/Umbraco.Web/umbraco.presentation/library.cs +++ b/src/Umbraco.Web/umbraco.presentation/library.cs @@ -10,6 +10,7 @@ using System.Web.UI; using System.Xml; using System.Xml.XPath; using Umbraco.Core; +using Umbraco.Core.Cache; using Umbraco.Core.Logging; using Umbraco.Web; using Umbraco.Web.Cache; @@ -72,8 +73,6 @@ namespace umbraco public static DateTime PublishStart; private page _page; private static readonly object libraryCacheLock = new object(); - private const string GETMEDIA_CACHE_KEY = "GetMedia"; - private const string GETMEMBER_CACHE_KEY = "GetMember"; #endregion @@ -465,13 +464,11 @@ namespace umbraco { if (UmbracoSettings.UmbracoLibraryCacheDuration > 0) { - XPathNodeIterator retVal = Cache.GetCacheItem(String.Format( - "UL_{0}_{1}_{2}", GETMEDIA_CACHE_KEY, MediaId, Deep), libraryCacheLock, + XPathNodeIterator retVal = ApplicationContext.Current.ApplicationCache.GetCacheItem( + string.Format( + "{0}_{1}_{2}", CacheKeys.MediaCacheKey, MediaId, Deep), TimeSpan.FromSeconds(UmbracoSettings.UmbracoLibraryCacheDuration), - delegate - { - return getMediaDo(MediaId, Deep); - }); + () => getMediaDo(MediaId, Deep)); if (retVal != null) return retVal; @@ -518,13 +515,11 @@ namespace umbraco { if (UmbracoSettings.UmbracoLibraryCacheDuration > 0) { - XmlDocument retVal = Cache.GetCacheItem(String.Format( - "UL_{0}_{1}", GETMEMBER_CACHE_KEY, MemberId), libraryCacheLock, + var retVal = ApplicationContext.Current.ApplicationCache.GetCacheItem( + string.Format( + "{0}_{1}", CacheKeys.MemberCacheKey, MemberId), TimeSpan.FromSeconds(UmbracoSettings.UmbracoLibraryCacheDuration), - delegate - { - return getMemberDo(MemberId); - }); + () => getMemberDo(MemberId)); if (retVal != null) return retVal.CreateNavigator().Select("/"); diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/cache/LegacyClasses.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/cache/LegacyClasses.cs index 10f0f9d874..a497c86884 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/cache/LegacyClasses.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/cache/LegacyClasses.cs @@ -82,7 +82,7 @@ namespace umbraco.presentation.cache } } - [Obsolete("This class is no longer used, it has been superceded by Umbraco.Web.Cache.CacheRefresherClient, however that is marked internal and these should not be used directly in your code.")] + [Obsolete("This class is no longer used, it has been superceded by Umbraco.Core.Sync.ServerSyncWebServiceClient, however that is marked internal and these should not be used directly in your code.")] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Web.Services.WebServiceBindingAttribute(Name = "CacheRefresherSoap", Namespace = "http://umbraco.org/webservices/")]