Perf: shapetable sorting (#8676)

* Grouped ShapeAlteration by feature before sorting them

* removed stopwatches

* Sorting approach can be selected by setting the GroupByFeatures option in HostComponents.config
This commit is contained in:
Matteo Piovanelli
2023-05-05 09:43:02 +02:00
committed by GitHub
parent bf8cc13922
commit 12e9f06689
2 changed files with 64 additions and 7 deletions

View File

@@ -9,6 +9,14 @@
</Properties>
</Component>
<Component Type="Orchard.DisplayManagement.Descriptors.DefaultShapeTableManager">
<Properties>
<!-- Set Value="true" to enable an optimization in the sorting step of the ShapeAlterations.
Warning: Rendered results should not be affected, but intermediate steps might. -->
<Property Name="GroupByFeatures" Value="false"/>
</Properties>
</Component>
<Component Type="Orchard.DisplayManagement.Descriptors.ShapePlacementStrategy.PlacementFileParser">
<Properties>
<!-- Set Value="true" to disable Placement files monitoring (Placement.info) -->

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Autofac.Features.Metadata;
using Orchard.Caching;
using Orchard.ContentManagement;
using Orchard.Environment;
using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models;
@@ -19,6 +20,16 @@ namespace Orchard.DisplayManagement.Descriptors {
private readonly IParallelCacheContext _parallelCacheContext;
private readonly Work<IEnumerable<IShapeTableEventHandler>> _shapeTableEventHandlersWork;
/// <summary>
/// Group all ShapeAlterations by Feature, so we may more easily sort those by their
/// priorities and dependencies. The reason for this is that we may often end up with
/// orders of magnitude more ShapeAlterations than Features, so sorting directly the
/// former may end up being too expensive.
/// We can enable this through HostComponents.config as a safety measure in case this
/// breaks some frontend.
/// </summary>
public bool GroupByFeatures { get; set; }
public DefaultShapeTableManager(
IEnumerable<Meta<IShapeTableProvider>> bindingStrategies,
IExtensionManager extensionManager,
@@ -50,11 +61,36 @@ namespace Orchard.DisplayManagement.Descriptors {
return builder.BuildAlterations().ToReadOnlyCollection();
});
var alterations = alterationSets
.SelectMany(shapeAlterations => shapeAlterations)
.Where(alteration => IsModuleOrRequestedTheme(alteration, themeName))
.OrderByDependenciesAndPriorities(AlterationHasDependency, GetPriority)
.ToList();
List<ShapeAlteration> alterations;
if (GroupByFeatures) {
var unsortedAlterations = alterationSets
.SelectMany(shapeAlterations => shapeAlterations)
.Where(alteration => IsModuleOrRequestedTheme(alteration, themeName));
// Group all ShapeAlterations by Feature, so we may more easily sort those by their
// priorities and dependencies. The reason for this is that we may often end up with
// orders of magnitude more ShapeAlterations than Features, so sorting directly the
// former may end up being too expensive.
var alterationsByFeature = unsortedAlterations
.GroupBy(sa => sa.Feature.Descriptor.Id)
.Select(g => new AlterationGroup {
Feature = g.First().Feature,
Alterations = g
});
var orderedGroups = alterationsByFeature
.OrderByDependenciesAndPriorities(AlterationHasDependency, GetPriority);
alterations = orderedGroups
.SelectMany(g => g.Alterations)
.ToList();
}
else {
alterations = alterationSets
.SelectMany(shapeAlterations => shapeAlterations)
.Where(alteration => IsModuleOrRequestedTheme(alteration, themeName))
.OrderByDependenciesAndPriorities(AlterationHasDependency, GetPriority)
.ToList();
}
var descriptors = alterations.GroupBy(alteration => alteration.ShapeType, StringComparer.OrdinalIgnoreCase)
.Select(group => group.Aggregate(
@@ -64,8 +100,8 @@ namespace Orchard.DisplayManagement.Descriptors {
return descriptor;
})).ToList();
foreach(var descriptor in descriptors) {
foreach(var alteration in alterations.Where(a => a.ShapeType == descriptor.ShapeType).ToList()) {
foreach (var descriptor in descriptors) {
foreach (var alteration in alterations.Where(a => a.ShapeType == descriptor.ShapeType).ToList()) {
var local = new ShapeDescriptor { ShapeType = descriptor.ShapeType };
alteration.Alter(local);
descriptor.BindingSources.Add(local.BindingSource);
@@ -131,5 +167,18 @@ namespace Orchard.DisplayManagement.Descriptors {
}
return false;
}
class AlterationGroup {
public Feature Feature { get; set; }
public IEnumerable<ShapeAlteration> Alterations { get; set; }
}
private static int GetPriority(AlterationGroup shapeAlteration) {
return shapeAlteration.Feature.Descriptor.Priority;
}
private static bool AlterationHasDependency(AlterationGroup item, AlterationGroup subject) {
return ExtensionManager.HasDependency(item.Feature.Descriptor, subject.Feature.Descriptor);
}
}
}