From f72538a9814c9030a04ddbec00954afeabdb7f71 Mon Sep 17 00:00:00 2001 From: Georg von Kries Date: Fri, 28 Jun 2024 10:58:57 +0200 Subject: [PATCH] Performance optimizations and simplifications of extension manager. --- .../Extensions/ExtensionManager.cs | 238 +++++++----------- 1 file changed, 95 insertions(+), 143 deletions(-) diff --git a/src/OrchardCore/OrchardCore/Extensions/ExtensionManager.cs b/src/OrchardCore/OrchardCore/Extensions/ExtensionManager.cs index dca77fb07b2..6f40d4df033 100644 --- a/src/OrchardCore/OrchardCore/Extensions/ExtensionManager.cs +++ b/src/OrchardCore/OrchardCore/Extensions/ExtensionManager.cs @@ -18,26 +18,16 @@ namespace OrchardCore.Environment.Extensions { - public class ExtensionManager : IExtensionManager + public sealed class ExtensionManager : IExtensionManager { - private readonly IApplicationContext _applicationContext; - - private readonly IExtensionDependencyStrategy[] _extensionDependencyStrategies; - private readonly IExtensionPriorityStrategy[] _extensionPriorityStrategies; - private readonly ITypeFeatureProvider _typeFeatureProvider; - private readonly IFeaturesProvider _featuresProvider; - - private FrozenDictionary _extensions; - private List _extensionsInfos; - private FrozenDictionary _features; - private IFeatureInfo[] _featureInfos; + private readonly FrozenDictionary _extensions; + private readonly List _extensionsInfos; + private readonly FrozenDictionary _features; + private readonly IFeatureInfo[] _featureInfos; private readonly ConcurrentDictionary>> _featureDependencies = new(); private readonly ConcurrentDictionary>> _dependentFeatures = new(); - private bool _isInitialized; - private readonly object _synLock = new(); - public ExtensionManager( IApplicationContext applicationContext, IEnumerable extensionDependencyStrategies, @@ -46,20 +36,84 @@ public class ExtensionManager : IExtensionManager IFeaturesProvider featuresProvider, ILogger logger) { - _applicationContext = applicationContext; - _extensionDependencyStrategies = extensionDependencyStrategies as IExtensionDependencyStrategy[] ?? extensionDependencyStrategies.ToArray(); - _extensionPriorityStrategies = extensionPriorityStrategies as IExtensionPriorityStrategy[] ?? extensionPriorityStrategies.ToArray(); - _typeFeatureProvider = typeFeatureProvider; - _featuresProvider = featuresProvider; L = logger; + + var modules = applicationContext.Application.Modules; + var loadedExtensions = new ConcurrentDictionary(); + + // Load all extensions in parallel + Parallel.ForEach(modules, (module, cancellationToken) => + { + if (!module.ModuleInfo.Exists) + { + return; + } + + var manifestInfo = new ManifestInfo(module.ModuleInfo); + var extensionInfo = new ExtensionInfo(module.SubPath, manifestInfo, (mi, ei) => + { + return featuresProvider.GetFeatures(ei, mi); + }); + + var entry = new ExtensionEntry + { + ExtensionInfo = extensionInfo, + Assembly = module.Assembly, + ExportedTypes = module.Assembly.ExportedTypes + }; + + loadedExtensions.TryAdd(module.Name, entry); + }); + + // Get all types from all extension and add them to the type feature provider. + foreach (var loadedExtension in loadedExtensions) + { + var extension = loadedExtension.Value; + + foreach (var exportedType in extension.ExportedTypes.Where(IsComponentType)) + { + if (!SkipExtensionFeatureRegistration(exportedType)) + { + var sourceFeature = GetSourceFeatureNameForType(exportedType, extension.ExtensionInfo.Id); + + var feature = extension.ExtensionInfo.Features.FirstOrDefault(f => f.Id == sourceFeature); + + if (feature == null) + { + // Type has no specific feature, add it to all features + foreach (var curFeature in extension.ExtensionInfo.Features) + { + typeFeatureProvider.TryAdd(exportedType, curFeature); + } + } + else + { + typeFeatureProvider.TryAdd(exportedType, feature); + } + } + } + } + + // Feature infos and entries are ordered by priority and dependencies. + _featureInfos = Order( + loadedExtensions.SelectMany(extension => extension.Value.ExtensionInfo.Features), + extensionDependencyStrategies as IExtensionDependencyStrategy[] ?? extensionDependencyStrategies.ToArray(), + extensionPriorityStrategies as IExtensionPriorityStrategy[] ?? extensionPriorityStrategies.ToArray()); + _features = _featureInfos.ToFrozenDictionary(f => f.Id, f => f); + + // Extensions are also ordered according to the weight of their first features. + _extensionsInfos = _featureInfos + .Where(f => f.Id == f.Extension.Features.First().Id) + .Select(f => f.Extension) + .ToList(); + + _extensions = _extensionsInfos.ToFrozenDictionary(e => e.Id, e => loadedExtensions[e.Id]); } public ILogger L { get; set; } public IExtensionInfo GetExtension(string extensionId) { - EnsureInitialized(); - if (!string.IsNullOrEmpty(extensionId) && _extensions.TryGetValue(extensionId, out var extension)) { return extension.ExtensionInfo; @@ -70,15 +124,16 @@ public IExtensionInfo GetExtension(string extensionId) public IEnumerable GetExtensions() { - EnsureInitialized(); - return _extensionsInfos; } - public IEnumerable GetFeatures(string[] featureIdsToLoad) + public IEnumerable GetFeatures() { - EnsureInitialized(); + return _featureInfos; + } + public IEnumerable GetFeatures(string[] featureIdsToLoad) + { var allDependencyIds = new HashSet(featureIdsToLoad .SelectMany(GetFeatureDependencies) .Select(x => x.Id)); @@ -94,8 +149,6 @@ public IEnumerable GetFeatures(string[] featureIdsToLoad) public Task LoadExtensionAsync(IExtensionInfo extensionInfo) { - EnsureInitialized(); - _extensions.TryGetValue(extensionInfo.Id, out var extension); return Task.FromResult(extension); @@ -103,16 +156,12 @@ public Task LoadExtensionAsync(IExtensionInfo extensionInfo) public Task> LoadFeaturesAsync() { - EnsureInitialized(); - // Must return the features ordered by dependencies. return Task.FromResult>(_featureInfos); } public Task> LoadFeaturesAsync(string[] featureIdsToLoad) { - EnsureInitialized(); - var features = new HashSet(GetFeatures(featureIdsToLoad).Select(f => f.Id)); // Must return the features ordered by dependencies. @@ -124,8 +173,6 @@ public Task> LoadFeaturesAsync(string[] featureIdsToLo public IEnumerable GetFeatureDependencies(string featureId) { - EnsureInitialized(); - return _featureDependencies.GetOrAdd(featureId, (key) => new Lazy>(() => { if (!_features.TryGetValue(key, out var entry)) @@ -139,8 +186,6 @@ public IEnumerable GetFeatureDependencies(string featureId) public IEnumerable GetDependentFeatures(string featureId) { - EnsureInitialized(); - return _dependentFeatures.GetOrAdd(featureId, (key) => new Lazy>(() => { if (!_features.TryGetValue(key, out var entry)) @@ -152,7 +197,7 @@ public IEnumerable GetDependentFeatures(string featureId) })).Value; } - private IEnumerable GetFeatureDependencies( + private static IEnumerable GetFeatureDependencies( IFeatureInfo feature, IFeatureInfo[] features) { @@ -166,16 +211,15 @@ public IEnumerable GetDependentFeatures(string featureId) var next = stack.Pop(); foreach (var dependency in next) { - if (!dependencyIds.Contains(dependency.Id)) + if (dependencyIds.Add(dependency.Id)) { - dependencyIds.Add(dependency.Id); stack.Push(GetFeatureDependenciesFunc(dependency, features)); } } } // Preserve the underlying order of feature infos. - foreach (var featureInfo in _featureInfos) + foreach (var featureInfo in features) { if (dependencyIds.Contains(featureInfo.Id)) { @@ -184,7 +228,7 @@ public IEnumerable GetDependentFeatures(string featureId) } } - private IEnumerable GetDependentFeatures( + private static IEnumerable GetDependentFeatures( IFeatureInfo feature, IFeatureInfo[] features) { @@ -198,16 +242,15 @@ public IEnumerable GetDependentFeatures(string featureId) var next = stack.Pop(); foreach (var dependency in next) { - if (!dependencyIds.Contains(dependency.Id)) + if (dependencyIds.Add(dependency.Id)) { - dependencyIds.Add(dependency.Id); stack.Push(GetDependentFeaturesFunc(dependency, features)); } } } // Preserve the underlying order of feature infos. - foreach (var featureInfo in _featureInfos) + foreach (var featureInfo in features) { if (dependencyIds.Contains(featureInfo.Id)) { @@ -216,13 +259,6 @@ public IEnumerable GetDependentFeatures(string featureId) } } - public IEnumerable GetFeatures() - { - EnsureInitialized(); - - return _featureInfos; - } - private static List GetDependentFeaturesFunc(IFeatureInfo currentFeature, IFeatureInfo[] features) { var list = new List(); @@ -259,103 +295,19 @@ private static List GetFeatureDependenciesFunc(IFeatureInfo curren return list; } - private void EnsureInitialized() - { - if (_isInitialized) - { - return; - } - - lock (_synLock) - { - if (_isInitialized) - { - return; - } - - var modules = _applicationContext.Application.Modules; - var loadedExtensions = new ConcurrentDictionary(); - - // Load all extensions in parallel - Parallel.ForEach(modules, (module, cancellationToken) => - { - if (!module.ModuleInfo.Exists) - { - return; - } - - var manifestInfo = new ManifestInfo(module.ModuleInfo); - var extensionInfo = new ExtensionInfo(module.SubPath, manifestInfo, (mi, ei) => - { - return _featuresProvider.GetFeatures(ei, mi); - }); - - var entry = new ExtensionEntry - { - ExtensionInfo = extensionInfo, - Assembly = module.Assembly, - ExportedTypes = module.Assembly.ExportedTypes - }; - - loadedExtensions.TryAdd(module.Name, entry); - }); - - // Get all types from all extension and add them to the type feature provider. - foreach (var loadedExtension in loadedExtensions) - { - var extension = loadedExtension.Value; - - foreach (var exportedType in extension.ExportedTypes.Where(IsComponentType)) - { - if (!SkipExtensionFeatureRegistration(exportedType)) - { - var sourceFeature = GetSourceFeatureNameForType(exportedType, extension.ExtensionInfo.Id); - - var feature = extension.ExtensionInfo.Features.FirstOrDefault(f => f.Id == sourceFeature); - - if (feature == null) - { - // Type has no specific feature, add it to all features - foreach (var curFeature in extension.ExtensionInfo.Features) - { - _typeFeatureProvider.TryAdd(exportedType, curFeature); - } - } - else - { - _typeFeatureProvider.TryAdd(exportedType, feature); - } - } - } - } - - // Feature infos and entries are ordered by priority and dependencies. - _featureInfos = Order(loadedExtensions.SelectMany(extension => extension.Value.ExtensionInfo.Features)); - _features = _featureInfos.ToFrozenDictionary(f => f.Id, f => f); - - // Extensions are also ordered according to the weight of their first features. - _extensionsInfos = _featureInfos - .Where(f => f.Id == f.Extension.Features.First().Id) - .Select(f => f.Extension) - .ToList(); - - _extensions = _extensionsInfos.ToFrozenDictionary(e => e.Id, e => loadedExtensions[e.Id]); - - _isInitialized = true; - } - } - - private IFeatureInfo[] Order(IEnumerable featuresToOrder) + private static IFeatureInfo[] Order(IEnumerable featuresToOrder, IExtensionDependencyStrategy[] extensionDependencyStrategies, IExtensionPriorityStrategy[] extensionPriorityStrategies) { return featuresToOrder .OrderBy(x => x.Id) - .OrderByDependenciesAndPriorities(HasDependency, GetPriority) + .OrderByDependenciesAndPriorities( + (f1, f2) => HasDependency(f1, f2, extensionDependencyStrategies), + feature => GetPriority(feature, extensionPriorityStrategies)) .ToArray(); } - private bool HasDependency(IFeatureInfo f1, IFeatureInfo f2) + private static bool HasDependency(IFeatureInfo f1, IFeatureInfo f2, IExtensionDependencyStrategy[] extensionDependencyStrategies) { - foreach (var s in _extensionDependencyStrategies) + foreach (var s in extensionDependencyStrategies) { if (s.HasDependency(f1, f2)) { @@ -366,10 +318,10 @@ private bool HasDependency(IFeatureInfo f1, IFeatureInfo f2) return false; } - private int GetPriority(IFeatureInfo feature) + private static int GetPriority(IFeatureInfo feature, IExtensionPriorityStrategy[] extensionPriorityStrategies) { var sum = 0; - foreach (var strategy in _extensionPriorityStrategies) + foreach (var strategy in extensionPriorityStrategies) { sum += strategy.GetPriority(feature); }