Ensures the xml cache is distributed properly including variants as well as Examine updating correctly.

This commit is contained in:
Shannon
2014-05-29 18:58:51 +10:00
parent e1702cec60
commit fdc5976035
9 changed files with 130 additions and 68 deletions
@@ -19,7 +19,10 @@ namespace Umbraco.Core.Models.ContentVariations
public VariantInfo(params int[] variantIds)
{
VariantIds = variantIds;
VariantIds = variantIds.Any()
? variantIds
: new int[] {};
IsVariant = false;
}
@@ -28,6 +31,7 @@ namespace Umbraco.Core.Models.ContentVariations
IsVariant = true;
MasterDocId = masterDocId;
Key = key;
VariantIds = new int[] { };
}
public int[] VariantIds { get; set; }
@@ -266,6 +266,7 @@ namespace Umbraco.Web.Cache
// newly published ones will be synced with the published page cache refresher
var unpublished = e.SavedEntities.Where(x => x.JustPublished() == false).ToArray();
var ids = unpublished.Select(x => x.Id).ToList();
//ensure the variants are refreshed too
ids.AddRange(unpublished.SelectMany(x => x.VariantInfo.VariantIds));
ids.AddRange(unpublished.Select(x => x.VariantInfo.MasterDocId));
@@ -206,46 +206,28 @@ namespace Umbraco.Web.Cache
dc.RefreshAll(new Guid(DistributedCache.PageCacheRefresherId));
}
/// <summary>
/// Refreshes the cache amongst servers for a page
/// </summary>
/// <param name="dc"></param>
/// <param name="documentId"></param>
public static void RefreshPageCache(this DistributedCache dc, int documentId)
{
dc.Refresh(new Guid(DistributedCache.PageCacheRefresherId), documentId);
}
/// <summary>
/// Refreshes page cache for all instances passed in
/// </summary>
/// <param name="dc"></param>
/// <param name="content"></param>
public static void RefreshPageCache(this DistributedCache dc, params IContent[] content)
/// <param name="contentIds"></param>
public static void RefreshPageCache(this DistributedCache dc, params int[] contentIds)
{
dc.Refresh(new Guid(DistributedCache.PageCacheRefresherId), x => x.Id, content);
dc.RefreshByJson(new Guid(DistributedCache.PageCacheRefresherId),
PageCacheRefresher.SerializeToJsonPayload(PageCacheRefresher.OperationType.Saved, contentIds));
}
/// <summary>
/// Removes the cache amongst servers for a page
/// </summary>
/// <param name="dc"></param>
/// <param name="content"></param>
public static void RemovePageCache(this DistributedCache dc, params IContent[] content)
/// <param name="contentIds"></param>
public static void RemovePageCache(this DistributedCache dc, params int[] contentIds)
{
dc.Remove(new Guid(DistributedCache.PageCacheRefresherId), x => x.Id, content);
dc.RefreshByJson(new Guid(DistributedCache.PageCacheRefresherId),
PageCacheRefresher.SerializeToJsonPayload(PageCacheRefresher.OperationType.Deleted, contentIds));
}
/// <summary>
/// Removes the cache amongst servers for a page
/// </summary>
/// <param name="dc"></param>
/// <param name="documentId"></param>
public static void RemovePageCache(this DistributedCache dc, int documentId)
{
dc.Remove(new Guid(DistributedCache.PageCacheRefresherId), documentId);
}
/// <summary>
/// invokes the unpublished page cache refresher
/// </summary>
+71 -12
View File
@@ -1,10 +1,12 @@
using System;
using System.Web.Script.Serialization;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Models;
using Umbraco.Core.Sync;
using umbraco;
using umbraco.cms.businesslogic.web;
using System.Linq;
namespace Umbraco.Web.Cache
{
@@ -15,7 +17,7 @@ namespace Umbraco.Web.Cache
/// If Load balancing is enabled (by default disabled, is set in umbracoSettings.config) PageCacheRefresher will be called
/// everytime content is added/updated/removed to ensure that the content cache is identical on all load balanced servers
/// </remarks>
public class PageCacheRefresher : TypedCacheRefresherBase<PageCacheRefresher, IContent>
public class PageCacheRefresher : JsonCacheRefresherBase<PageCacheRefresher>
{
protected override PageCacheRefresher Instance
@@ -44,6 +46,51 @@ namespace Umbraco.Web.Cache
get { return "Page Refresher"; }
}
#region Static helpers
/// <summary>
/// Converts the json to a JsonPayload object
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
internal static JsonPayload[] DeserializeFromJsonPayload(string json)
{
var serializer = new JavaScriptSerializer();
var jsonObject = serializer.Deserialize<JsonPayload[]>(json);
return jsonObject;
}
internal static string SerializeToJsonPayload(OperationType op, params int[] contentIds)
{
var serializer = new JavaScriptSerializer();
var items = contentIds.Select(x => new JsonPayload
{
Id = x,
Operation = op
}).ToArray();
var json = serializer.Serialize(items);
return json;
}
#endregion
#region Sub classes
internal enum OperationType
{
Deleted,
Saved
}
internal class JsonPayload
{
public int Id { get; set; }
public OperationType Operation { get; set; }
}
#endregion
/// <summary>
/// Refreshes all nodes in umbraco.
/// </summary>
@@ -79,22 +126,34 @@ namespace Umbraco.Web.Cache
base.Remove(id);
}
public override void Refresh(IContent instance)
/// <summary>
/// Implement the IJsonCacheRefresher so that we can bulk delete/refresh the cache based on multiple IDs
/// </summary>
/// <param name="jsonPayload"></param>
public override void Refresh(string jsonPayload)
{
ApplicationContext.Current.ApplicationCache.ClearPartialViewCache();
content.Instance.UpdateDocumentCache(new Document(instance));
DistributedCache.Instance.ClearAllMacroCacheOnCurrentServer();
DistributedCache.Instance.ClearXsltCacheOnCurrentServer();
base.Refresh(instance);
}
var payloads = DeserializeFromJsonPayload(jsonPayload);
if (payloads.Any() == false) return;
public override void Remove(IContent instance)
{
ApplicationContext.Current.ApplicationCache.ClearPartialViewCache();
content.Instance.ClearDocumentCache(new Document(instance));
DistributedCache.Instance.ClearAllMacroCacheOnCurrentServer();
DistributedCache.Instance.ClearXsltCacheOnCurrentServer();
base.Remove(instance);
foreach (var payload in payloads)
{
switch (payload.Operation)
{
case OperationType.Deleted:
content.Instance.ClearDocumentCache(payload.Id);
break;
case OperationType.Saved:
content.Instance.UpdateDocumentCache(payload.Id);
break;
}
}
base.Refresh(jsonPayload);
}
}
}
@@ -11,7 +11,7 @@ namespace Umbraco.Web.Cache
/// <summary>
/// A cache refresher used for non-published content, this is primarily to notify Examine indexes to update and to refresh the RuntimeCacheRefresher
/// </summary>
public sealed class UnpublishedPageCacheRefresher : CacheRefresherBase<UnpublishedPageCacheRefresher>, IJsonCacheRefresher
public sealed class UnpublishedPageCacheRefresher : JsonCacheRefresherBase<UnpublishedPageCacheRefresher>
{
protected override UnpublishedPageCacheRefresher Instance
{
@@ -95,14 +95,14 @@ namespace Umbraco.Web.Cache
/// Implement the IJsonCacheRefresher so that we can bulk delete/refresh the cache based on multiple IDs
/// </summary>
/// <param name="jsonPayload"></param>
public void Refresh(string jsonPayload)
public override void Refresh(string jsonPayload)
{
foreach (var payload in DeserializeFromJsonPayload(jsonPayload))
{
RuntimeCacheProvider.Current.Delete(typeof(IContent), payload.Id);
}
OnCacheUpdated(Instance, new CacheRefresherEventArgs(jsonPayload, MessageType.RefreshByJson));
base.Refresh(jsonPayload);
}
}
@@ -475,25 +475,21 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
//determine which child to add based on the current VariantInfo
if (_variantInfo.IsVariant)
{
//get the master, then children
if (xmlChild.ParentNode != null)
{
//TODO: There's probably a faster way with the old xml api to do this
//find a variant of the current child for the current variant key
var variant = xmlChild.ParentNode.ChildNodes.OfType<XmlElement>()
.FirstOrDefault(x =>
//find all
x.AttributeValue<int>("masterDocId") == xmlChild.AttributeValue<int>("id")
&& xmlChild.AttributeValue<string>("variantKey") == _variantInfo.Key);
//TODO: There's probably a faster way with the old xml api to do this
if (variant != null)
{
//we found a variant!
_children.Add(
(new XmlPublishedContent(variant, _isPreviewing, true, _variantInfo)).CreateModel());
useVariant = true;
}
//find a variant of the current child for the current variant key
var variant = workingNode.ChildNodes.OfType<XmlElement>()
.FirstOrDefault(x =>
//find all
x.AttributeValue<int>("masterDocId") == xmlChild.AttributeValue<int>("id")
&& x.AttributeValue<string>("variantKey") == _variantInfo.Key);
if (variant != null)
{
//we found a variant!
_children.Add(
(new XmlPublishedContent(variant, _isPreviewing, true, _variantInfo)).CreateModel());
useVariant = true;
}
}
+8 -4
View File
@@ -342,10 +342,14 @@ namespace Umbraco.Web.Search
DeleteIndexForEntity(payload.Id, false);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
case UnpublishedPageCacheRefresher.OperationType.Saved:
var c5 = ApplicationContext.Current.Services.ContentService.GetById(payload.Id);
ReIndexForContent(c5, false);
break;
}
}
}
break;
@@ -62,7 +62,13 @@ namespace Umbraco.Web.Strategies.Publishing
/// </summary>
private void UpdateMultipleContentCache(IEnumerable<IContent> content)
{
DistributedCache.Instance.RefreshPageCache(content.ToArray());
var asArray = content.ToArray();
var ids = asArray.Select(x => x.Id).ToList();
//ensure the variants are refreshed too
ids.AddRange(asArray.SelectMany(x => x.VariantInfo.VariantIds));
ids.AddRange(asArray.Select(x => x.VariantInfo.MasterDocId));
DistributedCache.Instance.RefreshPageCache(ids.ToArray());
}
/// <summary>
@@ -70,7 +76,11 @@ namespace Umbraco.Web.Strategies.Publishing
/// </summary>
private void UpdateSingleContentCache(IContent content)
{
DistributedCache.Instance.RefreshPageCache(content);
var ids = new List<int> {content.Id};
//ensure the variants are refreshed too
ids.AddRange(content.VariantInfo.VariantIds);
ids.Add(content.VariantInfo.MasterDocId);
DistributedCache.Instance.RefreshPageCache(ids.ToArray());
}
}
}
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Configuration;
@@ -53,7 +54,12 @@ namespace Umbraco.Web.Strategies.Publishing
/// </summary>
private void UnPublishSingle(IContent content)
{
DistributedCache.Instance.RemovePageCache(content);
var ids = new List<int> { content.Id };
//ensure the variants are refreshed too
ids.AddRange(content.VariantInfo.VariantIds);
ids.Add(content.VariantInfo.MasterDocId);
DistributedCache.Instance.RemovePageCache(ids.ToArray());
}
}
}