Merge pull request #11071 from umbraco/v9/bugfix/empty-recycle-bin-index

Fixes empty recycle bin performance with indexing
This commit is contained in:
Bjarke Berg
2021-09-10 11:10:15 +02:00
committed by GitHub
4 changed files with 109 additions and 10 deletions

View File

@@ -118,6 +118,20 @@ namespace Umbraco.Cms.Infrastructure.Examine
}
}
/// <inheritdoc />
public void DeleteIndexForEntities(IReadOnlyCollection<int> entityIds, bool keepIfUnpublished)
{
var actions = DeferedActions.Get(_scopeProvider);
if (actions != null)
{
actions.Add(new DeferedDeleteIndex(this, entityIds, keepIfUnpublished));
}
else
{
DeferedDeleteIndex.Execute(this, entityIds, keepIfUnpublished);
}
}
/// <inheritdoc />
public void ReIndexForContent(IContent sender, bool isPublished)
{
@@ -371,6 +385,7 @@ namespace Umbraco.Cms.Infrastructure.Examine
{
private readonly ExamineUmbracoIndexingHandler _examineUmbracoIndexingHandler;
private readonly int _id;
private readonly IReadOnlyCollection<int> _ids;
private readonly bool _keepIfUnpublished;
public DeferedDeleteIndex(ExamineUmbracoIndexingHandler examineUmbracoIndexingHandler, int id, bool keepIfUnpublished)
@@ -380,16 +395,42 @@ namespace Umbraco.Cms.Infrastructure.Examine
_keepIfUnpublished = keepIfUnpublished;
}
public override void Execute() => Execute(_examineUmbracoIndexingHandler, _id, _keepIfUnpublished);
public DeferedDeleteIndex(ExamineUmbracoIndexingHandler examineUmbracoIndexingHandler, IReadOnlyCollection<int> ids, bool keepIfUnpublished)
{
_examineUmbracoIndexingHandler = examineUmbracoIndexingHandler;
_ids = ids;
_keepIfUnpublished = keepIfUnpublished;
}
public override void Execute()
{
if (_ids is null)
{
Execute(_examineUmbracoIndexingHandler, _id, _keepIfUnpublished);
}
else
{
Execute(_examineUmbracoIndexingHandler, _ids, _keepIfUnpublished);
}
}
public static void Execute(ExamineUmbracoIndexingHandler examineUmbracoIndexingHandler, int id, bool keepIfUnpublished)
{
var strId = id.ToString(CultureInfo.InvariantCulture);
foreach (var index in examineUmbracoIndexingHandler._examineManager.Indexes.OfType<IUmbracoIndex>()
.Where(x => x.PublishedValuesOnly || !keepIfUnpublished)
.Where(x => x.EnableDefaultEventHandler))
{
index.DeleteFromIndex(strId);
index.DeleteFromIndex(id.ToString(CultureInfo.InvariantCulture));
}
}
public static void Execute(ExamineUmbracoIndexingHandler examineUmbracoIndexingHandler, IReadOnlyCollection<int> ids, bool keepIfUnpublished)
{
foreach (var index in examineUmbracoIndexingHandler._examineManager.Indexes.OfType<IUmbracoIndex>()
.Where(x => x.PublishedValuesOnly || !keepIfUnpublished)
.Where(x => x.EnableDefaultEventHandler))
{
index.DeleteFromIndex(ids.Select(x => x.ToString(CultureInfo.InvariantCulture)));
}
}
}

View File

@@ -25,7 +25,7 @@ namespace Umbraco.Cms.Infrastructure.Search
void DeleteDocumentsForContentTypes(IReadOnlyCollection<int> removedContentTypes);
/// <summary>
/// Remove items from an index
/// Remove an item from an index
/// </summary>
/// <param name="entityId"></param>
/// <param name="keepIfUnpublished">
@@ -33,5 +33,15 @@ namespace Umbraco.Cms.Infrastructure.Search
/// If false it will delete this from all indexes regardless.
/// </param>
void DeleteIndexForEntity(int entityId, bool keepIfUnpublished);
/// <summary>
/// Remove items from an index
/// </summary>
/// <param name="entityIds"></param>
/// <param name="keepIfUnpublished">
/// If true, indicates that we will only delete this item from indexes that don't support unpublished content.
/// If false it will delete this from all indexes regardless.
/// </param>
void DeleteIndexForEntities(IReadOnlyCollection<int> entityIds, bool keepIfUnpublished);
}
}

View File

@@ -44,13 +44,21 @@ namespace Umbraco.Cms.Infrastructure.Search
throw new NotSupportedException();
}
// Used to track permanent deletions so we can bulk delete from the index
// when needed. For example, when emptying the recycle bin, else it will
// individually update the index which will be much slower.
HashSet<int> deleteBatch = null;
foreach (var payload in (ContentCacheRefresher.JsonPayload[])args.MessageObject)
{
if (payload.ChangeTypes.HasType(TreeChangeTypes.Remove))
{
// delete content entirely (with descendants)
// false: remove entirely from all indexes
_umbracoIndexingHandler.DeleteIndexForEntity(payload.Id, false);
if (deleteBatch == null)
{
deleteBatch = new HashSet<int>();
}
deleteBatch.Add(payload.Id);
}
else if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshAll))
{
@@ -62,6 +70,15 @@ namespace Umbraco.Cms.Infrastructure.Search
}
else // RefreshNode or RefreshBranch (maybe trashed)
{
if (deleteBatch != null && deleteBatch.Contains(payload.Id))
{
// the same node has already been deleted, to ensure ordering is
// handled, we'll need to execute all queued deleted items now
// and reset the deleted items list.
_umbracoIndexingHandler.DeleteIndexForEntities(deleteBatch, false);
deleteBatch = null;
}
// don't try to be too clever - refresh entirely
// there has to be race conditions in there ;-(
@@ -132,6 +149,12 @@ namespace Umbraco.Cms.Infrastructure.Search
//
// BUT ... pretty sure it is! see test "Index_Delete_Index_Item_Ensure_Heirarchy_Removed"
}
if (deleteBatch != null)
{
// process the delete batch
_umbracoIndexingHandler.DeleteIndexForEntities(deleteBatch, false);
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Notifications;
@@ -37,12 +38,21 @@ namespace Umbraco.Cms.Infrastructure.Search
throw new NotSupportedException();
}
// Used to track permanent deletions so we can bulk delete from the index
// when needed. For example, when emptying the recycle bin, else it will
// individually update the index which will be much slower.
HashSet<int> deleteBatch = null;
foreach (var payload in (MediaCacheRefresher.JsonPayload[])args.MessageObject)
{
if (payload.ChangeTypes.HasType(TreeChangeTypes.Remove))
{
// remove from *all* indexes
_umbracoIndexingHandler.DeleteIndexForEntity(payload.Id, false);
if (deleteBatch == null)
{
deleteBatch = new HashSet<int>();
}
deleteBatch.Add(payload.Id);
}
else if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshAll))
{
@@ -52,6 +62,15 @@ namespace Umbraco.Cms.Infrastructure.Search
}
else // RefreshNode or RefreshBranch (maybe trashed)
{
if (deleteBatch != null && deleteBatch.Contains(payload.Id))
{
// the same node has already been deleted, to ensure ordering is
// handled, we'll need to execute all queued deleted items now
// and reset the deleted items list.
_umbracoIndexingHandler.DeleteIndexForEntities(deleteBatch, false);
deleteBatch = null;
}
var media = _mediaService.GetById(payload.Id);
if (media == null)
{
@@ -83,7 +102,13 @@ namespace Umbraco.Cms.Infrastructure.Search
}
}
}
}
}
}
if (deleteBatch != null)
{
// process the delete batch
_umbracoIndexingHandler.DeleteIndexForEntities(deleteBatch, false);
}
}
}