Merge pull request #1613 from umbraco/temp-U4-7833

U4-7833 Changing doc type results in invalid cache, lucene indexes, e…
This commit is contained in:
Claus
2016-11-15 11:14:56 +01:00
committed by GitHub
3 changed files with 114 additions and 41 deletions

View File

@@ -326,7 +326,7 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// <summary>
/// A boolean flag indicating if a property type has been removed from this instance.
/// </summary>
/// <remarks>

View File

@@ -32,7 +32,7 @@ namespace Umbraco.Web.Cache
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
private static JsonPayload[] DeserializeFromJsonPayload(string json)
internal static JsonPayload[] DeserializeFromJsonPayload(string json)
{
var serializer = new JavaScriptSerializer();
var jsonObject = serializer.Deserialize<JsonPayload[]>(json);
@@ -45,30 +45,28 @@ namespace Umbraco.Web.Cache
/// <param name="contentType"></param>
/// <param name="isDeleted">if the item was deleted</param>
/// <returns></returns>
private static JsonPayload FromContentType(IContentTypeBase contentType, bool isDeleted = false)
internal static JsonPayload FromContentType(IContentTypeBase contentType, bool isDeleted = false)
{
var payload = new JsonPayload
{
Alias = contentType.Alias,
Id = contentType.Id,
PropertyTypeIds = contentType.PropertyTypes.Select(x => x.Id).ToArray(),
//either IContentType or IMediaType or IMemberType
Type = (contentType is IContentType)
? typeof(IContentType).Name
: (contentType is IMediaType)
{
Alias = contentType.Alias,
Id = contentType.Id,
PropertyTypeIds = contentType.PropertyTypes.Select(x => x.Id).ToArray(),
//either IContentType or IMediaType or IMemberType
Type = (contentType is IContentType)
? typeof(IContentType).Name
: (contentType is IMediaType)
? typeof(IMediaType).Name
: typeof(IMemberType).Name,
DescendantPayloads = contentType.Descendants().Select(x => FromContentType(x)).ToArray(),
WasDeleted = isDeleted
};
//here we need to check if the alias of the content type changed or if one of the properties was removed.
var dirty = contentType as IRememberBeingDirty;
if (dirty != null)
{
payload.PropertyRemoved = dirty.WasPropertyDirty("HasPropertyTypeBeenRemoved");
payload.AliasChanged = dirty.WasPropertyDirty("Alias");
payload.IsNew = dirty.WasPropertyDirty("HasIdentity");
}
DescendantPayloads = contentType.Descendants().Select(x => FromContentType(x)).ToArray(),
WasDeleted = isDeleted,
PropertyRemoved = contentType.WasPropertyDirty("HasPropertyTypeBeenRemoved"),
AliasChanged = contentType.WasPropertyDirty("Alias"),
PropertyTypeAliasChanged = contentType.PropertyTypes.Any(x => x.WasPropertyDirty("Alias")),
IsNew = contentType.WasPropertyDirty("HasIdentity")
};
return payload;
}
@@ -90,7 +88,7 @@ namespace Umbraco.Web.Cache
#region Sub classes
private class JsonPayload
internal class JsonPayload
{
public JsonPayload()
{
@@ -103,6 +101,7 @@ namespace Umbraco.Web.Cache
public string Type { get; set; }
public bool AliasChanged { get; set; }
public bool PropertyRemoved { get; set; }
public bool PropertyTypeAliasChanged { get; set; }
public JsonPayload[] DescendantPayloads { get; set; }
public bool WasDeleted { get; set; }
public bool IsNew { get; set; }
@@ -190,21 +189,21 @@ namespace Umbraco.Web.Cache
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.IdToKeyCacheKey);
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.KeyToIdCacheKey);
payloads.ForEach(payload =>
foreach (var payload in payloads)
{
//clear the cache for each item
ClearContentTypeCache(payload);
//we only need to do this for IContentType NOT for IMediaType, we don't want to refresh the whole cache.
//if the item was deleted or the alias changed or property removed then we need to refresh the content.
//and, don't refresh the cache if it is new.
if (payload.Type == typeof(IContentType).Name
&& payload.IsNew == false
&& (payload.WasDeleted || payload.AliasChanged || payload.PropertyRemoved || payload.PropertyTypeAliasChanged))
{
//clear the cache for each item
ClearContentTypeCache(payload);
//we only need to do this for IContentType NOT for IMediaType, we don't want to refresh the whole cache.
//if the item was deleted or the alias changed or property removed then we need to refresh the content.
//and, don't refresh the cache if it is new.
if (payload.Type == typeof(IContentType).Name
&& !payload.IsNew
&& (payload.WasDeleted || payload.AliasChanged || payload.PropertyRemoved))
{
needsContentRefresh = true;
}
});
needsContentRefresh = true;
}
}
//need to refresh the xml content cache if required
if (needsContentRefresh)
@@ -237,7 +236,7 @@ namespace Umbraco.Web.Cache
//cache if only a media type has changed.
//we don't want to update the routes cache if all of the content types here are new.
if (payloads.Any(x => x.Type == typeof(IContentType).Name)
&& !payloads.All(x => x.IsNew)) //if they are all new then don't proceed
&& payloads.All(x => x.IsNew) == false) //if they are all new then don't proceed
{
// SD: we need to clear the routes cache here!
//

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml;
@@ -67,12 +68,12 @@ namespace Umbraco.Web.Search
/// <summary>
/// This is used to refresh content indexers IndexData based on the DataService whenever a content type is changed since
/// properties may have been added/removed
/// properties may have been added/removed, then we need to re-index any required data if aliases have been changed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <remarks>
/// See: http://issues.umbraco.org/issue/U4-4798
/// See: http://issues.umbraco.org/issue/U4-4798, http://issues.umbraco.org/issue/U4-7833
/// </remarks>
static void ContentTypeCacheRefresherCacheUpdated(ContentTypeCacheRefresher sender, CacheRefresherEventArgs e)
{
@@ -81,6 +82,79 @@ namespace Umbraco.Web.Search
{
provider.RefreshIndexerDataFromDataService();
}
if (e.MessageType == MessageType.RefreshByJson)
{
var contentTypesChanged = new HashSet<string>();
var mediaTypesChanged = new HashSet<string>();
var memberTypesChanged = new HashSet<string>();
var payloads = ContentTypeCacheRefresher.DeserializeFromJsonPayload(e.MessageObject.ToString());
foreach (var payload in payloads)
{
if (payload.IsNew == false
&& (payload.WasDeleted || payload.AliasChanged || payload.PropertyRemoved || payload.PropertyTypeAliasChanged))
{
//if we get here it means that some aliases have changed and the indexes for those particular doc types will need to be updated
if (payload.Type == typeof(IContentType).Name)
{
//if it is content
contentTypesChanged.Add(payload.Alias);
}
else if (payload.Type == typeof(IMediaType).Name)
{
//if it is media
mediaTypesChanged.Add(payload.Alias);
}
else if (payload.Type == typeof(IMemberType).Name)
{
//if it is members
memberTypesChanged.Add(payload.Alias);
}
}
}
//TODO: We need to update Examine to support re-indexing multiple items at once instead of one by one which will speed up
// the re-indexing process, we don't want to revert to rebuilding the whole thing!
if (contentTypesChanged.Count > 0)
{
foreach (var alias in contentTypesChanged)
{
var ctType = ApplicationContext.Current.Services.ContentTypeService.GetContentType(alias);
var contentItems = ApplicationContext.Current.Services.ContentService.GetContentOfContentType(ctType.Id);
foreach (var contentItem in contentItems)
{
ReIndexForContent(contentItem, contentItem.HasPublishedVersion && contentItem.Trashed == false);
}
}
}
if (mediaTypesChanged.Count > 0)
{
foreach (var alias in mediaTypesChanged)
{
var ctType = ApplicationContext.Current.Services.ContentTypeService.GetMediaType(alias);
var mediaItems = ApplicationContext.Current.Services.MediaService.GetMediaOfMediaType(ctType.Id);
foreach (var mediaItem in mediaItems)
{
ReIndexForMedia(mediaItem, mediaItem.Trashed == false);
}
}
}
if (memberTypesChanged.Count > 0)
{
foreach (var alias in memberTypesChanged)
{
var ctType = ApplicationContext.Current.Services.MemberTypeService.Get(alias);
var memberItems = ApplicationContext.Current.Services.MemberService.GetMembersByMemberType(ctType.Id);
foreach (var memberItem in memberItems)
{
ReIndexForMember(memberItem);
}
}
}
}
}
static void MemberCacheRefresherCacheUpdated(MemberCacheRefresher sender, CacheRefresherEventArgs e)
@@ -432,7 +506,7 @@ namespace Umbraco.Web.Search
//add an icon attribute to get indexed
xml.Add(new XAttribute("icon", sender.ContentType.Icon));
ExamineManager.Instance.ReIndexNode(
ExamineManager.Instance.ReIndexNode(
xml, IndexTypes.Content,
ExamineManager.Instance.IndexProviderCollection.OfType<BaseUmbracoIndexer>()