mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
PERF: Move async token monitoring to a service interface
Update UT --HG-- branch : 1.x
This commit is contained in:
@@ -50,6 +50,7 @@ namespace Orchard.Tests.Modules.CodeGeneration.Commands {
|
||||
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
||||
builder.RegisterType<SchemaCommandGenerator>().As<ISchemaCommandGenerator>();
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
builder.RegisterType<StubHostEnvironment>().As<IHostEnvironment>();
|
||||
|
||||
_container = builder.Build();
|
||||
|
||||
@@ -88,6 +88,7 @@ namespace Orchard.Tests.Modules.Migrations {
|
||||
builder.RegisterType<SchemaCommandGenerator>().As<ISchemaCommandGenerator>();
|
||||
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
builder.RegisterType<StubHostEnvironment>().As<IHostEnvironment>();
|
||||
|
||||
_session = _sessionFactory.OpenSession();
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace Orchard.Tests.Modules.Packaging.Services {
|
||||
builder.RegisterType<FolderUpdater>().As<IFolderUpdater>();
|
||||
builder.RegisterInstance(new Mock<INotifier>().Object);
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
|
||||
_mockedVirtualPathProvider = new Mock<IVirtualPathProvider>();
|
||||
builder.RegisterInstance(_mockedVirtualPathProvider.Object).As<IVirtualPathProvider>();
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace Orchard.Tests.Modules.Packaging.Services {
|
||||
builder.RegisterType<FolderUpdater>().As<IFolderUpdater>();
|
||||
builder.RegisterInstance(new Mock<INotifier>().Object);
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
|
||||
_mockedVirtualPathProvider = new Mock<IVirtualPathProvider>();
|
||||
builder.RegisterInstance(_mockedVirtualPathProvider.Object).As<IVirtualPathProvider>();
|
||||
|
||||
@@ -50,6 +50,7 @@ namespace Orchard.Tests.Modules.Recipes.RecipeHandlers {
|
||||
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
||||
builder.RegisterType<FeatureManager>().As<IFeatureManager>();
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
builder.RegisterType<ShellDescriptorManager>().As<IShellDescriptorManager>().SingleInstance();
|
||||
builder.RegisterType<StubDataMigrationManager>().As<IDataMigrationManager>();
|
||||
builder.RegisterType<StubPackagingSourceManager>().As<IPackagingSourceManager>();
|
||||
|
||||
@@ -53,6 +53,7 @@ namespace Orchard.Tests.Modules.Recipes.RecipeHandlers {
|
||||
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
||||
builder.RegisterType<FeatureManager>().As<IFeatureManager>();
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
builder.RegisterType<ShellDescriptorManager>().As<IShellDescriptorManager>().SingleInstance();
|
||||
builder.RegisterType<ModuleRecipeHandlerTest.StubDataMigrationManager>().As<IDataMigrationManager>();
|
||||
builder.RegisterType<ModuleRecipeHandlerTest.StubPackagingSourceManager>().As<IPackagingSourceManager>();
|
||||
|
||||
@@ -73,6 +73,7 @@ namespace Orchard.Tests.Modules.Recipes.Services {
|
||||
builder.RegisterType<StubAppDataFolder>().As<IAppDataFolder>();
|
||||
builder.RegisterType<StubClock>().As<IClock>();
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
builder.RegisterInstance(_folders).As<IExtensionFolders>();
|
||||
builder.RegisterType<Environment.Extensions.ExtensionManagerTests.StubLoaders>().As<IExtensionLoader>();
|
||||
builder.RegisterType<RecipeParser>().As<IRecipeParser>();
|
||||
|
||||
@@ -68,6 +68,7 @@ namespace Orchard.Tests.DataMigration {
|
||||
builder.RegisterType<DataMigrationManager>().As<IDataMigrationManager>();
|
||||
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
_session = _sessionFactory.OpenSession();
|
||||
builder.RegisterInstance(new DefaultContentManagerTests.TestSessionLocator(_session)).As<ISessionLocator>();
|
||||
foreach(var type in dataMigrations) {
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace Orchard.Tests.Environment.Extensions {
|
||||
builder.RegisterInstance(_folders).As<IExtensionFolders>();
|
||||
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
|
||||
_container = builder.Build();
|
||||
_manager = _container.Resolve<IExtensionManager>();
|
||||
@@ -360,7 +361,7 @@ Features:
|
||||
Description: Contains the Phi type.
|
||||
");
|
||||
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
||||
var testFeature = extensionManager.AvailableExtensions()
|
||||
.SelectMany(x => x.Features);
|
||||
|
||||
@@ -386,7 +387,7 @@ Features:
|
||||
Description: Contains the Phi type.
|
||||
");
|
||||
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
||||
var testFeature = extensionManager.AvailableExtensions()
|
||||
.SelectMany(x => x.Features);
|
||||
|
||||
@@ -415,7 +416,7 @@ Features:
|
||||
Description: Contains the Phi type.
|
||||
");
|
||||
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
||||
var testFeature = extensionManager.AvailableExtensions()
|
||||
.SelectMany(x => x.Features)
|
||||
.Single(x => x.Id == "TestFeature");
|
||||
@@ -445,7 +446,7 @@ Features:
|
||||
Description: Contains the Phi type.
|
||||
");
|
||||
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
||||
var testFeature = extensionManager.AvailableExtensions()
|
||||
.SelectMany(x => x.Features)
|
||||
.Single(x => x.Id == "TestFeature");
|
||||
@@ -473,7 +474,7 @@ Features:
|
||||
Description: Contains the Phi type.
|
||||
");
|
||||
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
||||
var testModule = extensionManager.AvailableExtensions()
|
||||
.SelectMany(x => x.Features)
|
||||
.Single(x => x.Id == "TestModule");
|
||||
@@ -497,7 +498,7 @@ Version: 1.0.3
|
||||
OrchardVersion: 1
|
||||
");
|
||||
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
||||
var minimalisticModule = extensionManager.AvailableExtensions().Single(x => x.Id == "Minimalistic");
|
||||
|
||||
Assert.That(minimalisticModule.Features.Count(), Is.EqualTo(1));
|
||||
@@ -516,7 +517,7 @@ Version: 1.0.3
|
||||
OrchardVersion: 1
|
||||
");
|
||||
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
||||
var minimalisticModule = extensionManager.AvailableExtensions().Single(x => x.Id == "Minimalistic");
|
||||
|
||||
Assert.That(minimalisticModule.Features.Count(), Is.EqualTo(1));
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace Orchard.Tests.Environment.Extensions {
|
||||
builder.RegisterInstance(_folders).As<IExtensionFolders>();
|
||||
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
|
||||
_container = builder.Build();
|
||||
_manager = _container.Resolve<IExtensionManager>();
|
||||
@@ -283,7 +284,7 @@ Features:
|
||||
Description: Contains the Phi type.
|
||||
");
|
||||
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
||||
var testFeature = extensionManager.AvailableExtensions()
|
||||
.SelectMany(x => x.Features);
|
||||
|
||||
@@ -309,7 +310,7 @@ Features:
|
||||
Description: Contains the Phi type.
|
||||
");
|
||||
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
||||
var testFeature = extensionManager.AvailableExtensions()
|
||||
.SelectMany(x => x.Features);
|
||||
|
||||
@@ -346,7 +347,7 @@ Features:
|
||||
Description: Contains the Phi type.
|
||||
");
|
||||
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
||||
var testFeature = extensionManager.AvailableExtensions()
|
||||
.SelectMany(x => x.Features)
|
||||
.Single(x => x.Id == "TestFeature");
|
||||
@@ -376,7 +377,7 @@ Features:
|
||||
Description: Contains the Phi type.
|
||||
");
|
||||
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
||||
var testFeature = extensionManager.AvailableExtensions()
|
||||
.SelectMany(x => x.Features)
|
||||
.Single(x => x.Id == "TestFeature");
|
||||
@@ -404,7 +405,7 @@ Features:
|
||||
Description: Contains the Phi type.
|
||||
");
|
||||
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
||||
var testModule = extensionManager.AvailableExtensions()
|
||||
.SelectMany(x => x.Features)
|
||||
.Single(x => x.Id == "TestModule");
|
||||
@@ -428,7 +429,7 @@ Version: 1.0.3
|
||||
OrchardVersion: 1
|
||||
");
|
||||
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
||||
var minimalisticModule = extensionManager.AvailableExtensions().Single(x => x.Id == "Minimalistic");
|
||||
|
||||
Assert.That(minimalisticModule.Features.Count(), Is.EqualTo(1));
|
||||
@@ -464,7 +465,7 @@ Features:
|
||||
Dependencies: Beta
|
||||
");
|
||||
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager());
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
||||
var features = extensionManager.AvailableFeatures();
|
||||
Assert.That(features.Aggregate("<", (a, b) => a + b.Id + "<"), Is.EqualTo("<Beta<Gamma<Alpha<"));
|
||||
}
|
||||
@@ -504,7 +505,7 @@ Version: 1.0.3
|
||||
OrchardVersion: 1
|
||||
");
|
||||
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { moduleExtensionFolder, themeExtensionFolder }, new[] { extensionLoader }, new StubCacheManager());
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { moduleExtensionFolder, themeExtensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
||||
var features = extensionManager.AvailableFeatures();
|
||||
Assert.That(features.Count(), Is.EqualTo(4));
|
||||
}
|
||||
@@ -538,7 +539,7 @@ OrchardVersion: 1{1}{2}",
|
||||
}
|
||||
|
||||
private static void AssertFeaturesAreInOrder(IEnumerable<StubFolders> folders, StubLoaders loader, string expectedOrder) {
|
||||
var extensionManager = new ExtensionManager(folders, new[] { loader }, new StubCacheManager());
|
||||
var extensionManager = new ExtensionManager(folders, new[] { loader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
||||
var features = extensionManager.AvailableFeatures();
|
||||
Assert.That(features.Aggregate("<", (a, b) => a + b.Id + "<"), Is.EqualTo(expectedOrder));
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace Orchard.Tests.Environment.Features {
|
||||
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
||||
builder.RegisterType<FeatureManager>().As<IFeatureManager>();
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
builder.RegisterType<ShellDescriptorManager>().As<IShellDescriptorManager>().SingleInstance();
|
||||
builder.RegisterType<ShellStateManager>().As<IShellStateManager>().SingleInstance();
|
||||
builder.RegisterType<StubEventBus>().As<IEventBus>().SingleInstance();
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Orchard.Caching;
|
||||
|
||||
namespace Orchard.Tests.Stubs {
|
||||
@@ -16,4 +18,21 @@ namespace Orchard.Tests.Stubs {
|
||||
return _defaultCacheManager.GetCache<TKey, TResult>();
|
||||
}
|
||||
}
|
||||
|
||||
public class StubAsyncTokenProvider : IAsyncTokenProvider {
|
||||
public IVolatileToken GetToken(Action<Action<IVolatileToken>> task) {
|
||||
var tokens = new List<IVolatileToken>();
|
||||
task(tokens.Add);
|
||||
return new Token(tokens);
|
||||
}
|
||||
public class Token : IVolatileToken {
|
||||
private readonly List<IVolatileToken> _tokens;
|
||||
|
||||
public Token(List<IVolatileToken> tokens) {
|
||||
_tokens = tokens;
|
||||
}
|
||||
|
||||
public bool IsCurrent { get { return _tokens.All(t => t.IsCurrent); } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
64
src/Orchard/Caching/DefaultAsyncTokenProvider.cs
Normal file
64
src/Orchard/Caching/DefaultAsyncTokenProvider.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Orchard.Logging;
|
||||
|
||||
namespace Orchard.Caching {
|
||||
public class DefaultAsyncTokenProvider : IAsyncTokenProvider {
|
||||
public DefaultAsyncTokenProvider() {
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public IVolatileToken GetToken(Action<Action<IVolatileToken>> task) {
|
||||
var token = new AsyncVolativeToken(task, Logger);
|
||||
token.QueueWorkItem();
|
||||
return token;
|
||||
}
|
||||
|
||||
public class AsyncVolativeToken : IVolatileToken {
|
||||
private readonly Action<Action<IVolatileToken>> _task;
|
||||
private readonly List<IVolatileToken> _taskTokens = new List<IVolatileToken>();
|
||||
private volatile Exception _taskException;
|
||||
private volatile bool _isTaskFinished;
|
||||
|
||||
public AsyncVolativeToken(Action<Action<IVolatileToken>> task, ILogger logger) {
|
||||
_task = task;
|
||||
Logger = logger;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public void QueueWorkItem() {
|
||||
// Start a work item to collect tokens in our internal array
|
||||
ThreadPool.QueueUserWorkItem((state) => {
|
||||
try {
|
||||
_task(token => _taskTokens.Add(token));
|
||||
}
|
||||
catch (Exception e) {
|
||||
Logger.Error(e, "Error while monitoring extension files. Assuming extensions are not current.");
|
||||
_taskException = e;
|
||||
}
|
||||
finally {
|
||||
_isTaskFinished = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public bool IsCurrent {
|
||||
get {
|
||||
// We are current until the task has finished
|
||||
if (_taskException != null) {
|
||||
return false;
|
||||
}
|
||||
if (_isTaskFinished) {
|
||||
return _taskTokens.All(t => t.IsCurrent);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
src/Orchard/Caching/IAsyncTokenProvider.cs
Normal file
7
src/Orchard/Caching/IAsyncTokenProvider.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using System;
|
||||
|
||||
namespace Orchard.Caching {
|
||||
public interface IAsyncTokenProvider {
|
||||
IVolatileToken GetToken(Action<Action<IVolatileToken>> task);
|
||||
}
|
||||
}
|
||||
@@ -13,14 +13,21 @@ using Orchard.Utility.Extensions;
|
||||
namespace Orchard.Environment.Extensions {
|
||||
public class ExtensionManager : IExtensionManager {
|
||||
private readonly IEnumerable<IExtensionFolders> _folders;
|
||||
private readonly IAsyncTokenProvider _asyncTokenProvider;
|
||||
private readonly ICacheManager _cacheManager;
|
||||
private readonly IEnumerable<IExtensionLoader> _loaders;
|
||||
|
||||
public Localizer T { get; set; }
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public ExtensionManager(IEnumerable<IExtensionFolders> folders, IEnumerable<IExtensionLoader> loaders, ICacheManager cacheManager) {
|
||||
public ExtensionManager(
|
||||
IEnumerable<IExtensionFolders> folders,
|
||||
IEnumerable<IExtensionLoader> loaders,
|
||||
ICacheManager cacheManager,
|
||||
IAsyncTokenProvider asyncTokenProvider) {
|
||||
|
||||
_folders = folders;
|
||||
_asyncTokenProvider = asyncTokenProvider;
|
||||
_cacheManager = cacheManager;
|
||||
_loaders = loaders.OrderBy(x => x.Order).ToArray();
|
||||
T = NullLocalizer.Instance;
|
||||
@@ -38,7 +45,7 @@ namespace Orchard.Environment.Extensions {
|
||||
}
|
||||
|
||||
public IEnumerable<FeatureDescriptor> AvailableFeatures() {
|
||||
return _cacheManager.Get("...", ctx =>
|
||||
return _cacheManager.Get("...", ctx =>
|
||||
AvailableExtensions().SelectMany(ext => ext.Features).OrderByDependenciesAndPriorities(HasDependency, GetPriority).ToReadOnlyCollection());
|
||||
}
|
||||
|
||||
@@ -58,7 +65,7 @@ namespace Orchard.Environment.Extensions {
|
||||
// Themes implicitly depend on modules to ensure build and override ordering
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (DefaultExtensionTypes.IsTheme(subject.Extension.ExtensionType)) {
|
||||
// Theme depends on another if it is its base theme
|
||||
return item.Extension.BaseTheme == subject.Id;
|
||||
@@ -91,9 +98,11 @@ namespace Orchard.Environment.Extensions {
|
||||
extensionEntry = _cacheManager.Get(extensionId, ctx => {
|
||||
var entry = BuildEntry(extensionDescriptor);
|
||||
if (entry != null) {
|
||||
foreach (var loader in _loaders) {
|
||||
loader.Monitor(entry.Descriptor, (token) => ctx.Monitor(token));
|
||||
}
|
||||
ctx.Monitor(_asyncTokenProvider.GetToken(monitor => {
|
||||
foreach (var loader in _loaders) {
|
||||
loader.Monitor(entry.Descriptor, token => monitor(token));
|
||||
}
|
||||
}));
|
||||
}
|
||||
return entry;
|
||||
});
|
||||
@@ -134,7 +143,7 @@ namespace Orchard.Environment.Extensions {
|
||||
}
|
||||
return extensionId;
|
||||
}
|
||||
|
||||
|
||||
private ExtensionEntry BuildEntry(ExtensionDescriptor descriptor) {
|
||||
foreach (var loader in _loaders) {
|
||||
ExtensionEntry entry = loader.Load(descriptor);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Orchard.Caching;
|
||||
using Orchard.Environment.Extensions.Loaders;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
@@ -11,14 +10,18 @@ using Orchard.Logging;
|
||||
namespace Orchard.Environment.Extensions {
|
||||
public class ExtensionMonitoringCoordinator : IExtensionMonitoringCoordinator {
|
||||
private readonly IVirtualPathMonitor _virtualPathMonitor;
|
||||
private readonly IAsyncTokenProvider _asyncTokenProvider;
|
||||
private readonly IExtensionManager _extensionManager;
|
||||
private readonly IEnumerable<IExtensionLoader> _loaders;
|
||||
|
||||
public ExtensionMonitoringCoordinator(IVirtualPathMonitor virtualPathMonitor,
|
||||
public ExtensionMonitoringCoordinator(
|
||||
IVirtualPathMonitor virtualPathMonitor,
|
||||
IAsyncTokenProvider asyncTokenProvider,
|
||||
IExtensionManager extensionManager,
|
||||
IEnumerable<IExtensionLoader> loaders) {
|
||||
|
||||
_virtualPathMonitor = virtualPathMonitor;
|
||||
_asyncTokenProvider = asyncTokenProvider;
|
||||
_extensionManager = extensionManager;
|
||||
_loaders = loaders;
|
||||
|
||||
@@ -33,11 +36,8 @@ namespace Orchard.Environment.Extensions {
|
||||
if (Disabled)
|
||||
return;
|
||||
|
||||
//PREF: Monitor extensions asynchronously. IsCurrent will be 'true'
|
||||
// until all tokens are collected by the work function.
|
||||
var token = new AsyncVolativeToken(MonitorExtensionsWork, Logger);
|
||||
monitor(token);
|
||||
token.QueueWorkItem();
|
||||
//PERF: Monitor extensions asynchronously.
|
||||
monitor(_asyncTokenProvider.GetToken(MonitorExtensionsWork));
|
||||
}
|
||||
|
||||
public void MonitorExtensionsWork(Action<IVolatileToken> monitor) {
|
||||
@@ -55,48 +55,5 @@ namespace Orchard.Environment.Extensions {
|
||||
}
|
||||
Logger.Information("Done monitoring extension files...");
|
||||
}
|
||||
|
||||
public class AsyncVolativeToken : IVolatileToken {
|
||||
private readonly Action<Action<IVolatileToken>> _task;
|
||||
private readonly List<IVolatileToken> _taskTokens = new List<IVolatileToken>();
|
||||
private volatile Exception _taskException;
|
||||
private volatile bool _isTaskFinished;
|
||||
|
||||
public AsyncVolativeToken(Action<Action<IVolatileToken>> task, ILogger logger) {
|
||||
_task = task;
|
||||
Logger = logger;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public void QueueWorkItem() {
|
||||
// Start a work item to collect tokens in our internal array
|
||||
ThreadPool.QueueUserWorkItem((state) => {
|
||||
try {
|
||||
_task(token => _taskTokens.Add(token));
|
||||
}
|
||||
catch (Exception e) {
|
||||
Logger.Error(e, "Error while monitoring extension files. Assuming extensions are not current.");
|
||||
_taskException = e;
|
||||
}
|
||||
finally {
|
||||
_isTaskFinished = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public bool IsCurrent {
|
||||
get {
|
||||
// We are current until the task has finished
|
||||
if (_taskException != null) {
|
||||
return false;
|
||||
}
|
||||
if (_isTaskFinished) {
|
||||
return _taskTokens.All(t => t.IsCurrent);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ namespace Orchard.Environment {
|
||||
// a single default host implementation is needed for bootstrapping a web app domain
|
||||
builder.RegisterType<DefaultOrchardEventBus>().As<IEventBus>().SingleInstance();
|
||||
builder.RegisterType<DefaultCacheHolder>().As<ICacheHolder>().SingleInstance();
|
||||
builder.RegisterType<DefaultAsyncTokenProvider>().As<IAsyncTokenProvider>().SingleInstance();
|
||||
builder.RegisterType<DefaultHostEnvironment>().As<IHostEnvironment>().SingleInstance();
|
||||
builder.RegisterType<DefaultHostLocalRestart>().As<IHostLocalRestart>().SingleInstance();
|
||||
builder.RegisterType<DefaultBuildManager>().As<IBuildManager>().SingleInstance();
|
||||
|
||||
@@ -175,7 +175,9 @@
|
||||
<Compile Include="DisplayManagement\Shapes\ShapeDebugView.cs" />
|
||||
<Compile Include="DisplayManagement\Shapes\ITagBuilderFactory.cs" />
|
||||
<Compile Include="Environment\CollectionOrderModule.cs" />
|
||||
<Compile Include="Caching\DefaultAsyncTokenProvider.cs" />
|
||||
<Compile Include="Environment\Extensions\ExtensionMonitoringCoordinator.cs" />
|
||||
<Compile Include="Caching\IAsyncTokenProvider.cs" />
|
||||
<Compile Include="Environment\Extensions\IExtensionMonitoringCoordinator.cs" />
|
||||
<Compile Include="Environment\Extensions\OrchardSuppressDependencyAttribute.cs" />
|
||||
<Compile Include="Environment\Features\IFeatureManager.cs" />
|
||||
|
||||
Reference in New Issue
Block a user