2013-02-07 03:22:38 +06:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Globalization;
|
2013-03-16 01:37:05 +06:00
|
|
|
using System.Linq;
|
2013-02-07 03:22:38 +06:00
|
|
|
using System.Net;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Web.Services.Protocols;
|
|
|
|
|
using System.Xml;
|
|
|
|
|
using Umbraco.Core;
|
|
|
|
|
using Umbraco.Core.Configuration;
|
|
|
|
|
using Umbraco.Core.IO;
|
|
|
|
|
using Umbraco.Core.Logging;
|
2013-02-11 20:07:23 +06:00
|
|
|
using Umbraco.Core.Sync;
|
2013-02-07 03:22:38 +06:00
|
|
|
using umbraco.BusinessLogic;
|
2013-02-07 04:26:48 +06:00
|
|
|
using umbraco.interfaces;
|
2013-02-07 03:22:38 +06:00
|
|
|
|
|
|
|
|
namespace Umbraco.Web.Cache
|
|
|
|
|
{
|
2013-03-21 20:30:32 +06:00
|
|
|
//public class CacheUpdatedEventArgs : EventArgs
|
|
|
|
|
//{
|
|
|
|
|
|
|
|
|
|
//}
|
|
|
|
|
|
2013-02-07 03:22:38 +06:00
|
|
|
/// <summary>
|
2013-02-12 03:46:27 +06:00
|
|
|
/// DistributedCache is used to invalidate cache throughout the application which also takes in to account load balancing environments automatically
|
2013-02-07 03:22:38 +06:00
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Distributing calls to all registered load balanced servers, ensuring that content are synced and cached on all servers.
|
|
|
|
|
/// Dispatcher is exendable, so 3rd party services can easily be integrated into the workflow, using the interfaces.ICacheRefresher interface.
|
|
|
|
|
///
|
|
|
|
|
/// Dispatcher can refresh/remove content, templates and macros.
|
|
|
|
|
/// </remarks>
|
2013-03-16 09:03:26 +06:00
|
|
|
public sealed class DistributedCache
|
2013-02-07 03:22:38 +06:00
|
|
|
{
|
2013-02-07 03:49:45 +06:00
|
|
|
|
|
|
|
|
#region Public constants/Ids
|
|
|
|
|
|
2013-04-04 21:57:41 +06:00
|
|
|
public const string ApplicationTreeCacheRefresherId = "0AC6C028-9860-4EA4-958D-14D39F45886E";
|
|
|
|
|
public const string ApplicationCacheRefresherId = "B15F34A1-BC1D-4F8B-8369-3222728AB4C8";
|
2013-02-07 03:55:14 +06:00
|
|
|
public const string TemplateRefresherId = "DD12B6A0-14B9-46e8-8800-C154F74047C8";
|
|
|
|
|
public const string PageCacheRefresherId = "27AB3022-3DFA-47b6-9119-5945BC88FD66";
|
2013-02-07 03:58:47 +06:00
|
|
|
public const string MemberCacheRefresherId = "E285DF34-ACDC-4226-AE32-C0CB5CF388DA";
|
2014-02-12 17:14:16 +11:00
|
|
|
public const string MemberGroupCacheRefresherId = "187F236B-BD21-4C85-8A7C-29FBA3D6C00C";
|
2013-02-07 04:01:50 +06:00
|
|
|
public const string MediaCacheRefresherId = "B29286DD-2D40-4DDB-B325-681226589FEC";
|
2013-02-07 04:04:51 +06:00
|
|
|
public const string MacroCacheRefresherId = "7B1E683C-5F34-43dd-803D-9699EA1E98CA";
|
2013-02-12 04:13:29 +06:00
|
|
|
public const string UserCacheRefresherId = "E057AF6D-2EE6-41F4-8045-3694010F0AA6";
|
2013-07-09 11:47:46 +10:00
|
|
|
public const string UserPermissionsCacheRefresherId = "840AB9C5-5C0B-48DB-A77E-29FE4B80CD3A";
|
2013-04-04 03:43:05 +06:00
|
|
|
public const string UserTypeCacheRefresherId = "7E707E21-0195-4522-9A3C-658CC1761BD4";
|
2013-03-16 08:47:55 +06:00
|
|
|
public const string ContentTypeCacheRefresherId = "6902E22C-9C10-483C-91F3-66B7CAE9E2F5";
|
2013-03-22 00:35:15 +06:00
|
|
|
public const string LanguageCacheRefresherId = "3E0F95D8-0BE5-44B8-8394-2B8750B62654";
|
2013-03-22 00:49:07 +06:00
|
|
|
public const string DomainCacheRefresherId = "11290A79-4B57-4C99-AD72-7748A3CF38AF";
|
2013-03-22 01:49:34 +06:00
|
|
|
public const string StylesheetCacheRefresherId = "E0633648-0DEB-44AE-9A48-75C3A55CB670";
|
|
|
|
|
public const string StylesheetPropertyCacheRefresherId = "2BC7A3A4-6EB1-4FBC-BAA3-C9E7B6D36D38";
|
2013-03-22 05:04:32 +06:00
|
|
|
public const string DataTypeCacheRefresherId = "35B16C25-A17E-45D7-BC8F-EDAB1DCC28D2";
|
2013-03-23 01:59:25 +06:00
|
|
|
public const string DictionaryCacheRefresherId = "D1D7E227-F817-4816-BFE9-6C39B6152884";
|
2013-03-22 00:49:07 +06:00
|
|
|
|
2013-02-07 03:49:45 +06:00
|
|
|
#endregion
|
|
|
|
|
|
2013-02-07 03:29:47 +06:00
|
|
|
private static readonly DistributedCache InstanceObject = new DistributedCache();
|
2013-02-07 03:22:38 +06:00
|
|
|
|
2013-03-21 20:30:32 +06:00
|
|
|
///// <summary>
|
|
|
|
|
///// Fired when any cache refresher method has fired
|
|
|
|
|
///// </summary>
|
|
|
|
|
///// <remarks>
|
|
|
|
|
///// This could be used by developers to know when a cache refresher has executed on the local server.
|
|
|
|
|
///// Similarly to the content.AfterUpdateDocumentCache which fires locally on each machine.
|
|
|
|
|
///// </remarks>
|
|
|
|
|
//public event EventHandler<CacheUpdatedEventArgs> CacheChanged;
|
|
|
|
|
|
|
|
|
|
//private void OnCacheChanged(CacheUpdatedEventArgs args)
|
|
|
|
|
//{
|
|
|
|
|
// if (CacheChanged != null)
|
|
|
|
|
// {
|
|
|
|
|
// CacheChanged(this, args);
|
|
|
|
|
// }
|
|
|
|
|
//}
|
|
|
|
|
|
2013-02-07 03:22:38 +06:00
|
|
|
/// <summary>
|
|
|
|
|
/// Constructor
|
|
|
|
|
/// </summary>
|
2013-02-07 03:29:47 +06:00
|
|
|
private DistributedCache()
|
2013-02-12 03:46:27 +06:00
|
|
|
{
|
2013-02-07 03:22:38 +06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Singleton
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
2013-02-07 03:29:47 +06:00
|
|
|
public static DistributedCache Instance
|
2013-02-07 03:22:38 +06:00
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return InstanceObject;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-12 04:47:36 +06:00
|
|
|
/// <summary>
|
|
|
|
|
/// Sends a request to all registered load-balanced servers to refresh node with the specified Id
|
|
|
|
|
/// using the specified ICacheRefresher with the guid factoryGuid.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="T"></typeparam>
|
|
|
|
|
/// <param name="factoryGuid"></param>
|
|
|
|
|
/// <param name="getNumericId">The callback method to retreive the ID from an instance</param>
|
|
|
|
|
/// <param name="instances">The instances containing Ids</param>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// This method is much better for performance because it does not need to re-lookup an object instance
|
|
|
|
|
/// </remarks>
|
|
|
|
|
public void Refresh<T>(Guid factoryGuid, Func<T, int> getNumericId, params T[] instances)
|
|
|
|
|
{
|
|
|
|
|
ServerMessengerResolver.Current.Messenger.PerformRefresh<T>(
|
|
|
|
|
ServerRegistrarResolver.Current.Registrar.Registrations,
|
|
|
|
|
GetRefresherById(factoryGuid),
|
|
|
|
|
getNumericId,
|
|
|
|
|
instances);
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-07 03:22:38 +06:00
|
|
|
/// <summary>
|
|
|
|
|
/// Sends a request to all registered load-balanced servers to refresh node with the specified Id
|
|
|
|
|
/// using the specified ICacheRefresher with the guid factoryGuid.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="factoryGuid">The unique identifier of the ICacheRefresher used to refresh the node.</param>
|
|
|
|
|
/// <param name="id">The id of the node.</param>
|
|
|
|
|
public void Refresh(Guid factoryGuid, int id)
|
|
|
|
|
{
|
2013-02-12 03:46:27 +06:00
|
|
|
ServerMessengerResolver.Current.Messenger.PerformRefresh(
|
|
|
|
|
ServerRegistrarResolver.Current.Registrar.Registrations,
|
|
|
|
|
GetRefresherById(factoryGuid),
|
|
|
|
|
id);
|
2013-02-07 03:22:38 +06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sends a request to all registered load-balanced servers to refresh the node with the specified guid
|
|
|
|
|
/// using the specified ICacheRefresher with the guid factoryGuid.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="factoryGuid">The unique identifier of the ICacheRefresher used to refresh the node.</param>
|
|
|
|
|
/// <param name="id">The guid of the node.</param>
|
|
|
|
|
public void Refresh(Guid factoryGuid, Guid id)
|
|
|
|
|
{
|
2013-02-12 03:46:27 +06:00
|
|
|
ServerMessengerResolver.Current.Messenger.PerformRefresh(
|
|
|
|
|
ServerRegistrarResolver.Current.Registrar.Registrations,
|
|
|
|
|
GetRefresherById(factoryGuid),
|
|
|
|
|
id);
|
2013-02-07 03:22:38 +06:00
|
|
|
}
|
|
|
|
|
|
2013-03-21 20:30:32 +06:00
|
|
|
/// <summary>
|
|
|
|
|
/// Sends a request to all registered load-balanced servers to refresh data based on the custom json payload
|
|
|
|
|
/// using the specified ICacheRefresher with the guid factoryGuid.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="factoryGuid"></param>
|
|
|
|
|
/// <param name="jsonPayload"></param>
|
|
|
|
|
public void RefreshByJson(Guid factoryGuid, string jsonPayload)
|
|
|
|
|
{
|
|
|
|
|
ServerMessengerResolver.Current.Messenger.PerformRefresh(
|
|
|
|
|
ServerRegistrarResolver.Current.Registrar.Registrations,
|
|
|
|
|
GetRefresherById(factoryGuid),
|
|
|
|
|
jsonPayload);
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-07 03:22:38 +06:00
|
|
|
/// <summary>
|
|
|
|
|
/// Sends a request to all registered load-balanced servers to refresh all nodes
|
|
|
|
|
/// using the specified ICacheRefresher with the guid factoryGuid.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="factoryGuid">The unique identifier.</param>
|
|
|
|
|
public void RefreshAll(Guid factoryGuid)
|
2013-03-16 01:37:05 +06:00
|
|
|
{
|
|
|
|
|
RefreshAll(factoryGuid, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sends a request to all registered load-balanced servers to refresh all nodes
|
|
|
|
|
/// using the specified ICacheRefresher with the guid factoryGuid.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="factoryGuid">The unique identifier.</param>
|
|
|
|
|
/// <param name="allServers">
|
|
|
|
|
/// If true will send the request out to all registered LB servers, if false will only execute the current server
|
|
|
|
|
/// </param>
|
|
|
|
|
public void RefreshAll(Guid factoryGuid, bool allServers)
|
2013-02-07 03:22:38 +06:00
|
|
|
{
|
2013-02-12 03:46:27 +06:00
|
|
|
ServerMessengerResolver.Current.Messenger.PerformRefreshAll(
|
2013-03-16 01:37:05 +06:00
|
|
|
allServers
|
|
|
|
|
? ServerRegistrarResolver.Current.Registrar.Registrations
|
|
|
|
|
: Enumerable.Empty<IServerAddress>(), //this ensures it will only execute against the current server
|
2013-02-12 03:46:27 +06:00
|
|
|
GetRefresherById(factoryGuid));
|
2013-02-07 03:22:38 +06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sends a request to all registered load-balanced servers to remove the node with the specified id
|
|
|
|
|
/// using the specified ICacheRefresher with the guid factoryGuid.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="factoryGuid">The unique identifier.</param>
|
|
|
|
|
/// <param name="id">The id.</param>
|
|
|
|
|
public void Remove(Guid factoryGuid, int id)
|
|
|
|
|
{
|
2013-02-12 03:46:27 +06:00
|
|
|
ServerMessengerResolver.Current.Messenger.PerformRemove(
|
|
|
|
|
ServerRegistrarResolver.Current.Registrar.Registrations,
|
|
|
|
|
GetRefresherById(factoryGuid),
|
|
|
|
|
id);
|
2013-02-07 03:22:38 +06:00
|
|
|
}
|
2013-02-12 07:35:47 +06:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sends a request to all registered load-balanced servers to remove the node specified
|
|
|
|
|
/// using the specified ICacheRefresher with the guid factoryGuid.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="T"></typeparam>
|
|
|
|
|
/// <param name="factoryGuid"></param>
|
|
|
|
|
/// <param name="getNumericId"></param>
|
|
|
|
|
/// <param name="instances"></param>
|
|
|
|
|
public void Remove<T>(Guid factoryGuid, Func<T, int> getNumericId, params T[] instances)
|
|
|
|
|
{
|
|
|
|
|
ServerMessengerResolver.Current.Messenger.PerformRemove<T>(
|
|
|
|
|
ServerRegistrarResolver.Current.Registrar.Registrations,
|
|
|
|
|
GetRefresherById(factoryGuid),
|
|
|
|
|
getNumericId,
|
|
|
|
|
instances);
|
2013-03-23 01:59:25 +06:00
|
|
|
}
|
2013-03-21 20:30:32 +06:00
|
|
|
|
2013-02-07 04:26:48 +06:00
|
|
|
private static ICacheRefresher GetRefresherById(Guid uniqueIdentifier)
|
|
|
|
|
{
|
|
|
|
|
return CacheRefreshersResolver.Current.GetById(uniqueIdentifier);
|
2013-02-07 03:22:38 +06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|