mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-26 20:16:15 +08:00
Refactor cache context to support correct parallel execution
We need a new service, IParallelCacheContext, which allows tracking the current cache context across threads and tasks running in the thread pool. --HG-- branch : 1.x
This commit is contained in:
@@ -55,6 +55,7 @@ namespace Orchard.Core.Tests.Common.Providers {
|
|||||||
builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();
|
builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();
|
||||||
builder.RegisterType<StubExtensionManager>().As<IExtensionManager>();
|
builder.RegisterType<StubExtensionManager>().As<IExtensionManager>();
|
||||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||||
|
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||||
builder.RegisterInstance(new Mock<IThemeManager>().Object);
|
builder.RegisterInstance(new Mock<IThemeManager>().Object);
|
||||||
builder.RegisterInstance(new Mock<IOrchardServices>().Object);
|
builder.RegisterInstance(new Mock<IOrchardServices>().Object);
|
||||||
builder.RegisterInstance(new Mock<RequestContext>().Object);
|
builder.RegisterInstance(new Mock<RequestContext>().Object);
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ namespace Orchard.Core.Tests.Settings.Metadata {
|
|||||||
.As(typeof(IMapper<SettingsDictionary, XElement>));
|
.As(typeof(IMapper<SettingsDictionary, XElement>));
|
||||||
builder.RegisterType<Signals>().As<ISignals>();
|
builder.RegisterType<Signals>().As<ISignals>();
|
||||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||||
|
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||||
|
|
||||||
_container = builder.Build();
|
_container = builder.Build();
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ namespace Orchard.Tests.Modules.CodeGeneration.Commands {
|
|||||||
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
||||||
builder.RegisterType<SchemaCommandGenerator>().As<ISchemaCommandGenerator>();
|
builder.RegisterType<SchemaCommandGenerator>().As<ISchemaCommandGenerator>();
|
||||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||||
|
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||||
builder.RegisterType<StubHostEnvironment>().As<IHostEnvironment>();
|
builder.RegisterType<StubHostEnvironment>().As<IHostEnvironment>();
|
||||||
|
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ namespace Orchard.Tests.Modules.Migrations {
|
|||||||
builder.RegisterType<SchemaCommandGenerator>().As<ISchemaCommandGenerator>();
|
builder.RegisterType<SchemaCommandGenerator>().As<ISchemaCommandGenerator>();
|
||||||
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
|
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
|
||||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||||
|
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||||
builder.RegisterType<StubHostEnvironment>().As<IHostEnvironment>();
|
builder.RegisterType<StubHostEnvironment>().As<IHostEnvironment>();
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ namespace Orchard.Tests.Modules.Packaging.Services {
|
|||||||
builder.RegisterType<FolderUpdater>().As<IFolderUpdater>();
|
builder.RegisterType<FolderUpdater>().As<IFolderUpdater>();
|
||||||
builder.RegisterInstance(new Mock<INotifier>().Object);
|
builder.RegisterInstance(new Mock<INotifier>().Object);
|
||||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||||
|
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||||
|
|
||||||
_mockedVirtualPathProvider = new Mock<IVirtualPathProvider>();
|
_mockedVirtualPathProvider = new Mock<IVirtualPathProvider>();
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ namespace Orchard.Tests.Modules.Packaging.Services {
|
|||||||
builder.RegisterType<FolderUpdater>().As<IFolderUpdater>();
|
builder.RegisterType<FolderUpdater>().As<IFolderUpdater>();
|
||||||
builder.RegisterInstance(new Mock<INotifier>().Object);
|
builder.RegisterInstance(new Mock<INotifier>().Object);
|
||||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||||
|
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||||
|
|
||||||
_mockedVirtualPathProvider = new Mock<IVirtualPathProvider>();
|
_mockedVirtualPathProvider = new Mock<IVirtualPathProvider>();
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ namespace Orchard.Tests.Modules.Recipes.RecipeHandlers {
|
|||||||
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
||||||
builder.RegisterType<FeatureManager>().As<IFeatureManager>();
|
builder.RegisterType<FeatureManager>().As<IFeatureManager>();
|
||||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||||
|
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||||
builder.RegisterType<ShellDescriptorManager>().As<IShellDescriptorManager>().SingleInstance();
|
builder.RegisterType<ShellDescriptorManager>().As<IShellDescriptorManager>().SingleInstance();
|
||||||
builder.RegisterType<StubDataMigrationManager>().As<IDataMigrationManager>();
|
builder.RegisterType<StubDataMigrationManager>().As<IDataMigrationManager>();
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ namespace Orchard.Tests.Modules.Recipes.RecipeHandlers {
|
|||||||
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
||||||
builder.RegisterType<FeatureManager>().As<IFeatureManager>();
|
builder.RegisterType<FeatureManager>().As<IFeatureManager>();
|
||||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||||
|
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||||
builder.RegisterType<ShellDescriptorManager>().As<IShellDescriptorManager>().SingleInstance();
|
builder.RegisterType<ShellDescriptorManager>().As<IShellDescriptorManager>().SingleInstance();
|
||||||
builder.RegisterType<ModuleRecipeHandlerTest.StubDataMigrationManager>().As<IDataMigrationManager>();
|
builder.RegisterType<ModuleRecipeHandlerTest.StubDataMigrationManager>().As<IDataMigrationManager>();
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ namespace Orchard.Tests.Modules.Recipes.Services {
|
|||||||
builder.RegisterType<StubAppDataFolder>().As<IAppDataFolder>();
|
builder.RegisterType<StubAppDataFolder>().As<IAppDataFolder>();
|
||||||
builder.RegisterType<StubClock>().As<IClock>();
|
builder.RegisterType<StubClock>().As<IClock>();
|
||||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||||
|
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||||
builder.RegisterInstance(_folders).As<IExtensionFolders>();
|
builder.RegisterInstance(_folders).As<IExtensionFolders>();
|
||||||
builder.RegisterType<Environment.Extensions.ExtensionManagerTests.StubLoaders>().As<IExtensionLoader>();
|
builder.RegisterType<Environment.Extensions.ExtensionManagerTests.StubLoaders>().As<IExtensionLoader>();
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ namespace Orchard.Tests.Modules.Users.Controllers {
|
|||||||
builder.RegisterInstance(new Mock<INotifier>().Object);
|
builder.RegisterInstance(new Mock<INotifier>().Object);
|
||||||
builder.RegisterInstance(new Mock<IContentDisplay>().Object);
|
builder.RegisterInstance(new Mock<IContentDisplay>().Object);
|
||||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||||
|
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||||
builder.RegisterType<Signals>().As<ISignals>();
|
builder.RegisterType<Signals>().As<ISignals>();
|
||||||
|
|
||||||
builder.RegisterType<DefaultEncryptionService>().As<IEncryptionService>();
|
builder.RegisterType<DefaultEncryptionService>().As<IEncryptionService>();
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Orchard.Tests.Caching {
|
|||||||
builder.RegisterModule(new CacheModule());
|
builder.RegisterModule(new CacheModule());
|
||||||
builder.RegisterType<DefaultCacheManager>().As<ICacheManager>();
|
builder.RegisterType<DefaultCacheManager>().As<ICacheManager>();
|
||||||
builder.RegisterType<DefaultCacheHolder>().As<ICacheHolder>().SingleInstance();
|
builder.RegisterType<DefaultCacheHolder>().As<ICacheHolder>().SingleInstance();
|
||||||
builder.RegisterType<DefaultCacheManager>().As<ICacheManager>();
|
builder.RegisterType<DefaultCacheContextAccessor>().As<ICacheContextAccessor>();
|
||||||
_container = builder.Build();
|
_container = builder.Build();
|
||||||
_cacheManager = _container.Resolve<ICacheManager>(new TypedParameter(typeof(Type), GetType()));
|
_cacheManager = _container.Resolve<ICacheManager>(new TypedParameter(typeof(Type), GetType()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,8 @@ namespace Orchard.Tests.Caching {
|
|||||||
builder.RegisterModule(new CacheModule());
|
builder.RegisterModule(new CacheModule());
|
||||||
builder.RegisterType<DefaultCacheManager>().As<ICacheManager>();
|
builder.RegisterType<DefaultCacheManager>().As<ICacheManager>();
|
||||||
builder.RegisterType<DefaultCacheHolder>().As<ICacheHolder>().SingleInstance();
|
builder.RegisterType<DefaultCacheHolder>().As<ICacheHolder>().SingleInstance();
|
||||||
builder.RegisterType<DefaultCacheManager>().As<ICacheManager>();
|
builder.RegisterType<DefaultCacheContextAccessor>().As<ICacheContextAccessor>();
|
||||||
builder.RegisterInstance<IClock>(_clock = new StubClock());
|
builder.RegisterInstance<IClock>(_clock = new StubClock());
|
||||||
builder.RegisterType<DefaultCacheManager>().As<ICacheManager>();
|
|
||||||
_container = builder.Build();
|
_container = builder.Build();
|
||||||
_cacheManager = _container.Resolve<ICacheManager>(new TypedParameter(typeof(Type), GetType()));
|
_cacheManager = _container.Resolve<ICacheManager>(new TypedParameter(typeof(Type), GetType()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ namespace Orchard.Tests.DataMigration {
|
|||||||
builder.RegisterType<DataMigrationManager>().As<IDataMigrationManager>();
|
builder.RegisterType<DataMigrationManager>().As<IDataMigrationManager>();
|
||||||
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
|
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
|
||||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||||
|
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||||
_session = _sessionFactory.OpenSession();
|
_session = _sessionFactory.OpenSession();
|
||||||
builder.RegisterInstance(new DefaultContentManagerTests.TestSessionLocator(_session)).As<ISessionLocator>();
|
builder.RegisterInstance(new DefaultContentManagerTests.TestSessionLocator(_session)).As<ISessionLocator>();
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace Orchard.Tests.DisplayManagement.Descriptors {
|
|||||||
protected override void Register(Autofac.ContainerBuilder builder) {
|
protected override void Register(Autofac.ContainerBuilder builder) {
|
||||||
builder.RegisterType<PlacementFileParser>().As<IPlacementFileParser>();
|
builder.RegisterType<PlacementFileParser>().As<IPlacementFileParser>();
|
||||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||||
|
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||||
builder.RegisterType<InMemoryWebSiteFolder>().As<IWebSiteFolder>()
|
builder.RegisterType<InMemoryWebSiteFolder>().As<IWebSiteFolder>()
|
||||||
.As<InMemoryWebSiteFolder>().InstancePerLifetimeScope();
|
.As<InMemoryWebSiteFolder>().InstancePerLifetimeScope();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ namespace Orchard.Tests.Environment.Extensions {
|
|||||||
builder.RegisterInstance(_folders).As<IExtensionFolders>();
|
builder.RegisterInstance(_folders).As<IExtensionFolders>();
|
||||||
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
||||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||||
|
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||||
|
|
||||||
_container = builder.Build();
|
_container = builder.Build();
|
||||||
@@ -116,6 +117,9 @@ namespace Orchard.Tests.Environment.Extensions {
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ExtensionManager CreateExtensionManager(StubFolders extensionFolder, StubLoaders extensionLoader) {
|
||||||
|
return new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubParallelCacheContext(), new StubAsyncTokenProvider());
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void AvailableExtensionsShouldFollowCatalogLocations() {
|
public void AvailableExtensionsShouldFollowCatalogLocations() {
|
||||||
@@ -361,7 +365,7 @@ Features:
|
|||||||
Description: Contains the Phi type.
|
Description: Contains the Phi type.
|
||||||
");
|
");
|
||||||
|
|
||||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
IExtensionManager extensionManager = CreateExtensionManager(extensionFolder, extensionLoader); ;
|
||||||
var testFeature = extensionManager.AvailableExtensions()
|
var testFeature = extensionManager.AvailableExtensions()
|
||||||
.SelectMany(x => x.Features);
|
.SelectMany(x => x.Features);
|
||||||
|
|
||||||
@@ -387,7 +391,7 @@ Features:
|
|||||||
Description: Contains the Phi type.
|
Description: Contains the Phi type.
|
||||||
");
|
");
|
||||||
|
|
||||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
IExtensionManager extensionManager = CreateExtensionManager(extensionFolder, extensionLoader); ;
|
||||||
var testFeature = extensionManager.AvailableExtensions()
|
var testFeature = extensionManager.AvailableExtensions()
|
||||||
.SelectMany(x => x.Features);
|
.SelectMany(x => x.Features);
|
||||||
|
|
||||||
@@ -416,7 +420,7 @@ Features:
|
|||||||
Description: Contains the Phi type.
|
Description: Contains the Phi type.
|
||||||
");
|
");
|
||||||
|
|
||||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
IExtensionManager extensionManager = CreateExtensionManager(extensionFolder, extensionLoader); ;
|
||||||
var testFeature = extensionManager.AvailableExtensions()
|
var testFeature = extensionManager.AvailableExtensions()
|
||||||
.SelectMany(x => x.Features)
|
.SelectMany(x => x.Features)
|
||||||
.Single(x => x.Id == "TestFeature");
|
.Single(x => x.Id == "TestFeature");
|
||||||
@@ -446,7 +450,7 @@ Features:
|
|||||||
Description: Contains the Phi type.
|
Description: Contains the Phi type.
|
||||||
");
|
");
|
||||||
|
|
||||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
IExtensionManager extensionManager = CreateExtensionManager(extensionFolder, extensionLoader); ;
|
||||||
var testFeature = extensionManager.AvailableExtensions()
|
var testFeature = extensionManager.AvailableExtensions()
|
||||||
.SelectMany(x => x.Features)
|
.SelectMany(x => x.Features)
|
||||||
.Single(x => x.Id == "TestFeature");
|
.Single(x => x.Id == "TestFeature");
|
||||||
@@ -474,7 +478,7 @@ Features:
|
|||||||
Description: Contains the Phi type.
|
Description: Contains the Phi type.
|
||||||
");
|
");
|
||||||
|
|
||||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
IExtensionManager extensionManager = CreateExtensionManager(extensionFolder, extensionLoader); ;
|
||||||
var testModule = extensionManager.AvailableExtensions()
|
var testModule = extensionManager.AvailableExtensions()
|
||||||
.SelectMany(x => x.Features)
|
.SelectMany(x => x.Features)
|
||||||
.Single(x => x.Id == "TestModule");
|
.Single(x => x.Id == "TestModule");
|
||||||
@@ -498,7 +502,7 @@ Version: 1.0.3
|
|||||||
OrchardVersion: 1
|
OrchardVersion: 1
|
||||||
");
|
");
|
||||||
|
|
||||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
IExtensionManager extensionManager = CreateExtensionManager(extensionFolder, extensionLoader); ;
|
||||||
var minimalisticModule = extensionManager.AvailableExtensions().Single(x => x.Id == "Minimalistic");
|
var minimalisticModule = extensionManager.AvailableExtensions().Single(x => x.Id == "Minimalistic");
|
||||||
|
|
||||||
Assert.That(minimalisticModule.Features.Count(), Is.EqualTo(1));
|
Assert.That(minimalisticModule.Features.Count(), Is.EqualTo(1));
|
||||||
@@ -517,7 +521,7 @@ Version: 1.0.3
|
|||||||
OrchardVersion: 1
|
OrchardVersion: 1
|
||||||
");
|
");
|
||||||
|
|
||||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
IExtensionManager extensionManager = CreateExtensionManager(extensionFolder, extensionLoader); ;
|
||||||
var minimalisticModule = extensionManager.AvailableExtensions().Single(x => x.Id == "Minimalistic");
|
var minimalisticModule = extensionManager.AvailableExtensions().Single(x => x.Id == "Minimalistic");
|
||||||
|
|
||||||
Assert.That(minimalisticModule.Features.Count(), Is.EqualTo(1));
|
Assert.That(minimalisticModule.Features.Count(), Is.EqualTo(1));
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ namespace Orchard.Tests.Environment.Extensions {
|
|||||||
builder.RegisterInstance(_folders).As<IExtensionFolders>();
|
builder.RegisterInstance(_folders).As<IExtensionFolders>();
|
||||||
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
||||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||||
|
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||||
|
|
||||||
_container = builder.Build();
|
_container = builder.Build();
|
||||||
@@ -284,7 +285,7 @@ Features:
|
|||||||
Description: Contains the Phi type.
|
Description: Contains the Phi type.
|
||||||
");
|
");
|
||||||
|
|
||||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
IExtensionManager extensionManager = CreateExtensionManager(extensionFolder, extensionLoader);
|
||||||
var testFeature = extensionManager.AvailableExtensions()
|
var testFeature = extensionManager.AvailableExtensions()
|
||||||
.SelectMany(x => x.Features);
|
.SelectMany(x => x.Features);
|
||||||
|
|
||||||
@@ -310,7 +311,7 @@ Features:
|
|||||||
Description: Contains the Phi type.
|
Description: Contains the Phi type.
|
||||||
");
|
");
|
||||||
|
|
||||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
IExtensionManager extensionManager = CreateExtensionManager(extensionFolder, extensionLoader);
|
||||||
var testFeature = extensionManager.AvailableExtensions()
|
var testFeature = extensionManager.AvailableExtensions()
|
||||||
.SelectMany(x => x.Features);
|
.SelectMany(x => x.Features);
|
||||||
|
|
||||||
@@ -323,6 +324,14 @@ Features:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ExtensionManager CreateExtensionManager(StubFolders extensionFolder, StubLoaders extensionLoader) {
|
||||||
|
return CreateExtensionManager(new[] { extensionFolder }, new[] { extensionLoader });
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ExtensionManager CreateExtensionManager(IEnumerable<StubFolders> extensionFolder, IEnumerable<StubLoaders> extensionLoader) {
|
||||||
|
return new ExtensionManager(extensionFolder, extensionLoader, new StubCacheManager(), new StubParallelCacheContext(), new StubAsyncTokenProvider());
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void ExtensionManagerShouldReturnEmptyFeatureIfFeatureDoesNotExist() {
|
public void ExtensionManagerShouldReturnEmptyFeatureIfFeatureDoesNotExist() {
|
||||||
var featureDescriptor = new FeatureDescriptor { Id = "NoSuchFeature", Extension = new ExtensionDescriptor { Id = "NoSuchFeature" } };
|
var featureDescriptor = new FeatureDescriptor { Id = "NoSuchFeature", Extension = new ExtensionDescriptor { Id = "NoSuchFeature" } };
|
||||||
@@ -347,7 +356,7 @@ Features:
|
|||||||
Description: Contains the Phi type.
|
Description: Contains the Phi type.
|
||||||
");
|
");
|
||||||
|
|
||||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
IExtensionManager extensionManager = CreateExtensionManager(extensionFolder, extensionLoader); ;
|
||||||
var testFeature = extensionManager.AvailableExtensions()
|
var testFeature = extensionManager.AvailableExtensions()
|
||||||
.SelectMany(x => x.Features)
|
.SelectMany(x => x.Features)
|
||||||
.Single(x => x.Id == "TestFeature");
|
.Single(x => x.Id == "TestFeature");
|
||||||
@@ -377,7 +386,7 @@ Features:
|
|||||||
Description: Contains the Phi type.
|
Description: Contains the Phi type.
|
||||||
");
|
");
|
||||||
|
|
||||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
IExtensionManager extensionManager = CreateExtensionManager(extensionFolder, extensionLoader); ;
|
||||||
var testFeature = extensionManager.AvailableExtensions()
|
var testFeature = extensionManager.AvailableExtensions()
|
||||||
.SelectMany(x => x.Features)
|
.SelectMany(x => x.Features)
|
||||||
.Single(x => x.Id == "TestFeature");
|
.Single(x => x.Id == "TestFeature");
|
||||||
@@ -405,7 +414,7 @@ Features:
|
|||||||
Description: Contains the Phi type.
|
Description: Contains the Phi type.
|
||||||
");
|
");
|
||||||
|
|
||||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
IExtensionManager extensionManager = CreateExtensionManager(extensionFolder, extensionLoader); ;
|
||||||
var testModule = extensionManager.AvailableExtensions()
|
var testModule = extensionManager.AvailableExtensions()
|
||||||
.SelectMany(x => x.Features)
|
.SelectMany(x => x.Features)
|
||||||
.Single(x => x.Id == "TestModule");
|
.Single(x => x.Id == "TestModule");
|
||||||
@@ -429,7 +438,7 @@ Version: 1.0.3
|
|||||||
OrchardVersion: 1
|
OrchardVersion: 1
|
||||||
");
|
");
|
||||||
|
|
||||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
IExtensionManager extensionManager = CreateExtensionManager(extensionFolder, extensionLoader); ;
|
||||||
var minimalisticModule = extensionManager.AvailableExtensions().Single(x => x.Id == "Minimalistic");
|
var minimalisticModule = extensionManager.AvailableExtensions().Single(x => x.Id == "Minimalistic");
|
||||||
|
|
||||||
Assert.That(minimalisticModule.Features.Count(), Is.EqualTo(1));
|
Assert.That(minimalisticModule.Features.Count(), Is.EqualTo(1));
|
||||||
@@ -465,7 +474,7 @@ Features:
|
|||||||
Dependencies: Beta
|
Dependencies: Beta
|
||||||
");
|
");
|
||||||
|
|
||||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
IExtensionManager extensionManager = CreateExtensionManager(extensionFolder, extensionLoader); ;
|
||||||
var features = extensionManager.AvailableFeatures();
|
var features = extensionManager.AvailableFeatures();
|
||||||
Assert.That(features.Aggregate("<", (a, b) => a + b.Id + "<"), Is.EqualTo("<Beta<Gamma<Alpha<"));
|
Assert.That(features.Aggregate("<", (a, b) => a + b.Id + "<"), Is.EqualTo("<Beta<Gamma<Alpha<"));
|
||||||
}
|
}
|
||||||
@@ -505,7 +514,7 @@ Version: 1.0.3
|
|||||||
OrchardVersion: 1
|
OrchardVersion: 1
|
||||||
");
|
");
|
||||||
|
|
||||||
IExtensionManager extensionManager = new ExtensionManager(new[] { moduleExtensionFolder, themeExtensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
IExtensionManager extensionManager = CreateExtensionManager(new[] { moduleExtensionFolder, themeExtensionFolder }, new[] { extensionLoader });
|
||||||
var features = extensionManager.AvailableFeatures();
|
var features = extensionManager.AvailableFeatures();
|
||||||
Assert.That(features.Count(), Is.EqualTo(4));
|
Assert.That(features.Count(), Is.EqualTo(4));
|
||||||
}
|
}
|
||||||
@@ -539,7 +548,7 @@ OrchardVersion: 1{1}{2}",
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void AssertFeaturesAreInOrder(IEnumerable<StubFolders> folders, StubLoaders loader, string expectedOrder) {
|
private static void AssertFeaturesAreInOrder(IEnumerable<StubFolders> folders, StubLoaders loader, string expectedOrder) {
|
||||||
var extensionManager = new ExtensionManager(folders, new[] { loader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
var extensionManager = CreateExtensionManager(folders, new[] { loader });
|
||||||
var features = extensionManager.AvailableFeatures();
|
var features = extensionManager.AvailableFeatures();
|
||||||
Assert.That(features.Aggregate("<", (a, b) => a + b.Id + "<"), Is.EqualTo(expectedOrder));
|
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<ExtensionManager>().As<IExtensionManager>();
|
||||||
builder.RegisterType<FeatureManager>().As<IFeatureManager>();
|
builder.RegisterType<FeatureManager>().As<IFeatureManager>();
|
||||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||||
|
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||||
builder.RegisterType<ShellDescriptorManager>().As<IShellDescriptorManager>().SingleInstance();
|
builder.RegisterType<ShellDescriptorManager>().As<IShellDescriptorManager>().SingleInstance();
|
||||||
builder.RegisterType<ShellStateManager>().As<IShellStateManager>().SingleInstance();
|
builder.RegisterType<ShellStateManager>().As<IShellStateManager>().SingleInstance();
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace Orchard.Tests.FileSystems.Dependencies {
|
|||||||
builder.RegisterType<StubClock>().As<IClock>().SingleInstance();
|
builder.RegisterType<StubClock>().As<IClock>().SingleInstance();
|
||||||
builder.RegisterType<StubAppDataFolder>().As<IAppDataFolder>().SingleInstance();
|
builder.RegisterType<StubAppDataFolder>().As<IAppDataFolder>().SingleInstance();
|
||||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>().SingleInstance();
|
builder.RegisterType<StubCacheManager>().As<ICacheManager>().SingleInstance();
|
||||||
|
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||||
builder.RegisterType<DefaultDependenciesFolder>().As<IDependenciesFolder>();
|
builder.RegisterType<DefaultDependenciesFolder>().As<IDependenciesFolder>();
|
||||||
return builder.Build();
|
return builder.Build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Orchard.Tests.Stubs {
|
|||||||
private readonly ICacheManager _defaultCacheManager;
|
private readonly ICacheManager _defaultCacheManager;
|
||||||
|
|
||||||
public StubCacheManager() {
|
public StubCacheManager() {
|
||||||
_defaultCacheManager = new DefaultCacheManager(this.GetType(), new DefaultCacheHolder(new DefaultAcquireContextContext()));
|
_defaultCacheManager = new DefaultCacheManager(this.GetType(), new DefaultCacheHolder(new DefaultCacheContextAccessor()));
|
||||||
}
|
}
|
||||||
public TResult Get<TKey, TResult>(TKey key, Func<AcquireContext<TKey>, TResult> acquire) {
|
public TResult Get<TKey, TResult>(TKey key, Func<AcquireContext<TKey>, TResult> acquire) {
|
||||||
return _defaultCacheManager.Get(key, acquire);
|
return _defaultCacheManager.Get(key, acquire);
|
||||||
@@ -19,6 +19,17 @@ namespace Orchard.Tests.Stubs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class StubParallelCacheContext : IParallelCacheContext {
|
||||||
|
public ITask<T> CreateContextAwareTask<T>(Func<T> function) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<TResult> RunInParallel<T, TResult>(IEnumerable<T> source, Func<T, TResult> selector) {
|
||||||
|
return source.Select(selector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public class StubAsyncTokenProvider : IAsyncTokenProvider {
|
public class StubAsyncTokenProvider : IAsyncTokenProvider {
|
||||||
public IVolatileToken GetToken(Action<Action<IVolatileToken>> task) {
|
public IVolatileToken GetToken(Action<Action<IVolatileToken>> task) {
|
||||||
var tokens = new List<IVolatileToken>();
|
var tokens = new List<IVolatileToken>();
|
||||||
|
|||||||
@@ -14,4 +14,19 @@ namespace Orchard.Caching {
|
|||||||
public TKey Key { get; private set; }
|
public TKey Key { get; private set; }
|
||||||
public Action<IVolatileToken> Monitor { get; private set; }
|
public Action<IVolatileToken> Monitor { get; private set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Simple implementation of "IAcquireContext" given a lamdba
|
||||||
|
/// </summary>
|
||||||
|
public class SimpleAcquireContext : IAcquireContext {
|
||||||
|
private readonly Action<IVolatileToken> _monitor;
|
||||||
|
|
||||||
|
public SimpleAcquireContext(Action<IVolatileToken> monitor) {
|
||||||
|
_monitor = monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action<IVolatileToken> Monitor {
|
||||||
|
get { return _monitor; }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ using System.Linq;
|
|||||||
|
|
||||||
namespace Orchard.Caching {
|
namespace Orchard.Caching {
|
||||||
public class Cache<TKey, TResult> : ICache<TKey, TResult> {
|
public class Cache<TKey, TResult> : ICache<TKey, TResult> {
|
||||||
private readonly IAcquireContextContext _acquireContextContext;
|
private readonly ICacheContextAccessor _cacheContextAccessor;
|
||||||
private readonly ConcurrentDictionary<TKey, CacheEntry> _entries;
|
private readonly ConcurrentDictionary<TKey, CacheEntry> _entries;
|
||||||
|
|
||||||
public Cache(IAcquireContextContext acquireContextContext) {
|
public Cache(ICacheContextAccessor cacheContextAccessor) {
|
||||||
_acquireContextContext = acquireContextContext;
|
_cacheContextAccessor = cacheContextAccessor;
|
||||||
_entries = new ConcurrentDictionary<TKey, CacheEntry>();
|
_entries = new ConcurrentDictionary<TKey, CacheEntry>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,9 +21,9 @@ namespace Orchard.Caching {
|
|||||||
(k, currentEntry) => (currentEntry.GetTokens() != null && currentEntry.GetTokens().Any(t => !t.IsCurrent) ? CreateEntry(k, acquire) : currentEntry));
|
(k, currentEntry) => (currentEntry.GetTokens() != null && currentEntry.GetTokens().Any(t => !t.IsCurrent) ? CreateEntry(k, acquire) : currentEntry));
|
||||||
|
|
||||||
// Bubble up volatile tokens to parent context
|
// Bubble up volatile tokens to parent context
|
||||||
if (_acquireContextContext.Instance != null && entry.GetTokens() != null) {
|
if (_cacheContextAccessor.Current != null && entry.GetTokens() != null) {
|
||||||
foreach (var token in entry.GetTokens())
|
foreach (var token in entry.GetTokens())
|
||||||
_acquireContextContext.Instance.Monitor(token);
|
_cacheContextAccessor.Current.Monitor(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry.Result;
|
return entry.Result;
|
||||||
@@ -37,14 +37,14 @@ namespace Orchard.Caching {
|
|||||||
IAcquireContext parentContext = null;
|
IAcquireContext parentContext = null;
|
||||||
try {
|
try {
|
||||||
// Push context
|
// Push context
|
||||||
parentContext = _acquireContextContext.Instance;
|
parentContext = _cacheContextAccessor.Current;
|
||||||
_acquireContextContext.Instance = context;
|
_cacheContextAccessor.Current = context;
|
||||||
|
|
||||||
entry.Result = acquire(context);
|
entry.Result = acquire(context);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// Pop context
|
// Pop context
|
||||||
_acquireContextContext.Instance = parentContext;
|
_cacheContextAccessor.Current = parentContext;
|
||||||
}
|
}
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
using System.Security.Principal;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Orchard.Caching {
|
|
||||||
/// <summary>
|
|
||||||
/// Keep track of nested caches contexts on a given thread
|
|
||||||
/// </summary>
|
|
||||||
public class DefaultAcquireContextContext : IAcquireContextContext {
|
|
||||||
public IAcquireContext Instance {
|
|
||||||
get {
|
|
||||||
var principal = Thread.CurrentPrincipal as SurrogatePrincipal;
|
|
||||||
if (principal == null)
|
|
||||||
return null;
|
|
||||||
return principal.AcquireContext;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
var surrogatePrincipal = Thread.CurrentPrincipal as SurrogatePrincipal;
|
|
||||||
if (value == null) {
|
|
||||||
if (surrogatePrincipal != null) {
|
|
||||||
surrogatePrincipal.AcquireContext = null;
|
|
||||||
Thread.CurrentPrincipal = surrogatePrincipal.ActualPrincipal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (surrogatePrincipal == null) {
|
|
||||||
surrogatePrincipal = new SurrogatePrincipal(Thread.CurrentPrincipal);
|
|
||||||
Thread.CurrentPrincipal = surrogatePrincipal;
|
|
||||||
}
|
|
||||||
surrogatePrincipal.AcquireContext = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SurrogatePrincipal : IPrincipal {
|
|
||||||
private readonly IPrincipal _principal;
|
|
||||||
|
|
||||||
public SurrogatePrincipal(IPrincipal principal) {
|
|
||||||
_principal = principal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsInRole(string role) {
|
|
||||||
return _principal.IsInRole(role);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IIdentity Identity {
|
|
||||||
get { return _principal.Identity; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public IPrincipal ActualPrincipal {
|
|
||||||
get { return _principal; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public IAcquireContext AcquireContext { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
20
src/Orchard/Caching/DefaultCacheContextAccessor.cs
Normal file
20
src/Orchard/Caching/DefaultCacheContextAccessor.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Orchard.Caching {
|
||||||
|
public class DefaultCacheContextAccessor : ICacheContextAccessor {
|
||||||
|
[ThreadStatic]
|
||||||
|
private static IAcquireContext _threadInstance;
|
||||||
|
|
||||||
|
public static IAcquireContext ThreadInstance {
|
||||||
|
get { return _threadInstance; }
|
||||||
|
set { _threadInstance = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAcquireContext Current {
|
||||||
|
get { return ThreadInstance; }
|
||||||
|
set { ThreadInstance = value; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,11 +7,11 @@ namespace Orchard.Caching {
|
|||||||
/// The cache holder is responsible for actually storing the references to cached entities.
|
/// The cache holder is responsible for actually storing the references to cached entities.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DefaultCacheHolder : ICacheHolder {
|
public class DefaultCacheHolder : ICacheHolder {
|
||||||
private readonly IAcquireContextContext _acquireContextContext;
|
private readonly ICacheContextAccessor _cacheContextAccessor;
|
||||||
private readonly ConcurrentDictionary<CacheKey, object> _caches = new ConcurrentDictionary<CacheKey, object>();
|
private readonly ConcurrentDictionary<CacheKey, object> _caches = new ConcurrentDictionary<CacheKey, object>();
|
||||||
|
|
||||||
public DefaultCacheHolder(IAcquireContextContext acquireContextContext) {
|
public DefaultCacheHolder(ICacheContextAccessor cacheContextAccessor) {
|
||||||
_acquireContextContext = acquireContextContext;
|
_cacheContextAccessor = cacheContextAccessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
class CacheKey : Tuple<Type, Type, Type> {
|
class CacheKey : Tuple<Type, Type, Type> {
|
||||||
@@ -29,7 +29,7 @@ namespace Orchard.Caching {
|
|||||||
/// <returns>An entry from the cache, or a new, empty one, if none is found.</returns>
|
/// <returns>An entry from the cache, or a new, empty one, if none is found.</returns>
|
||||||
public ICache<TKey, TResult> GetCache<TKey, TResult>(Type component) {
|
public ICache<TKey, TResult> GetCache<TKey, TResult>(Type component) {
|
||||||
var cacheKey = new CacheKey(component, typeof(TKey), typeof(TResult));
|
var cacheKey = new CacheKey(component, typeof(TKey), typeof(TResult));
|
||||||
var result = _caches.GetOrAdd(cacheKey, k => new Cache<TKey, TResult>(_acquireContextContext));
|
var result = _caches.GetOrAdd(cacheKey, k => new Cache<TKey, TResult>(_cacheContextAccessor));
|
||||||
return (Cache<TKey, TResult>)result;
|
return (Cache<TKey, TResult>)result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
102
src/Orchard/Caching/DefaultParallelCacheContext.cs
Normal file
102
src/Orchard/Caching/DefaultParallelCacheContext.cs
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Orchard.Caching {
|
||||||
|
public class DefaultParallelCacheContext : IParallelCacheContext {
|
||||||
|
private readonly ICacheContextAccessor _cacheContextAccessor;
|
||||||
|
|
||||||
|
public DefaultParallelCacheContext(ICacheContextAccessor cacheContextAccessor) {
|
||||||
|
_cacheContextAccessor = cacheContextAccessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<TResult> RunInParallel<T, TResult>(IEnumerable<T> source, Func<T, TResult> selector) {
|
||||||
|
// Create tasks that capture the current thread context
|
||||||
|
var tasks = source.Select(item => this.CreateContextAwareTask(() => selector(item))).ToList();
|
||||||
|
|
||||||
|
// Run tasks in parallel and combine results immediately
|
||||||
|
var result = tasks.AsParallel().Select(task => task.Execute()).ToList();
|
||||||
|
|
||||||
|
// Forward tokens collected by tasks to the current context
|
||||||
|
foreach(var task in tasks) {
|
||||||
|
task.Finish();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a task that wraps some piece of code that implictly depends on the cache context.
|
||||||
|
/// The return task can be used in any execution thread (e.g. System.Threading.Tasks).
|
||||||
|
/// </summary>
|
||||||
|
public ITask<T> CreateContextAwareTask<T>(Func<T> function) {
|
||||||
|
return new TaskWithAcquireContext<T>(_cacheContextAccessor, function);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TaskWithAcquireContext<T> : ITask<T> {
|
||||||
|
private readonly ICacheContextAccessor _cacheContextAccessor;
|
||||||
|
private readonly Func<T> _function;
|
||||||
|
private IList<IVolatileToken> _tokens;
|
||||||
|
|
||||||
|
public TaskWithAcquireContext(ICacheContextAccessor cacheContextAccessor, Func<T> function) {
|
||||||
|
_cacheContextAccessor = cacheContextAccessor;
|
||||||
|
_function = function;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Execute task and collect eventual volatile tokens
|
||||||
|
/// </summary>
|
||||||
|
public T Execute() {
|
||||||
|
IAcquireContext parentContext = _cacheContextAccessor.Current;
|
||||||
|
try {
|
||||||
|
// Push context
|
||||||
|
if (parentContext == null) {
|
||||||
|
_cacheContextAccessor.Current = new SimpleAcquireContext(AddToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute lambda
|
||||||
|
return _function();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
// Pop context
|
||||||
|
if (parentContext == null) {
|
||||||
|
_cacheContextAccessor.Current = parentContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return tokens collected during task execution
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<IVolatileToken> Tokens {
|
||||||
|
get {
|
||||||
|
if (_tokens == null)
|
||||||
|
return Enumerable.Empty<IVolatileToken>();
|
||||||
|
return _tokens;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
Finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Forward collected tokens to current cache context
|
||||||
|
/// </summary>
|
||||||
|
public void Finish() {
|
||||||
|
var tokens = _tokens;
|
||||||
|
_tokens = null;
|
||||||
|
if (_cacheContextAccessor.Current != null && tokens != null) {
|
||||||
|
foreach (var token in tokens) {
|
||||||
|
_cacheContextAccessor.Current.Monitor(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddToken(IVolatileToken token) {
|
||||||
|
if (_tokens == null)
|
||||||
|
_tokens = new List<IVolatileToken>();
|
||||||
|
_tokens.Add(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
namespace Orchard.Caching {
|
|
||||||
public interface IAcquireContextContext {
|
|
||||||
IAcquireContext Instance { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
5
src/Orchard/Caching/ICacheContextAccessor.cs
Normal file
5
src/Orchard/Caching/ICacheContextAccessor.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
namespace Orchard.Caching {
|
||||||
|
public interface ICacheContextAccessor {
|
||||||
|
IAcquireContext Current { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
36
src/Orchard/Caching/IParallelCacheContext.cs
Normal file
36
src/Orchard/Caching/IParallelCacheContext.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Orchard.Caching {
|
||||||
|
/// <summary>
|
||||||
|
/// Provides services to enable parallel tasks aware of the current cache context.
|
||||||
|
/// </summary>
|
||||||
|
public interface IParallelCacheContext {
|
||||||
|
/// <summary>
|
||||||
|
/// Create a task that wraps some piece of code that implictly depends on the cache context.
|
||||||
|
/// The return task can be used in any execution thread (e.g. System.Threading.Tasks).
|
||||||
|
/// </summary>
|
||||||
|
ITask<T> CreateContextAwareTask<T>(Func<T> function);
|
||||||
|
|
||||||
|
IEnumerable<TResult> RunInParallel<T, TResult>(IEnumerable<T> source, Func<T, TResult> selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ITask<T> : IDisposable {
|
||||||
|
/// <summary>
|
||||||
|
/// Execute task and collect eventual volatile tokens
|
||||||
|
/// </summary>
|
||||||
|
T Execute();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return tokens collected during task execution. May be empty if nothing collected,
|
||||||
|
/// or if the task was executed in the same context as the current
|
||||||
|
/// ICacheContextAccessor.Current.
|
||||||
|
/// </summary>
|
||||||
|
IEnumerable<IVolatileToken> Tokens { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Forward collected tokens to current cache context
|
||||||
|
/// </summary>
|
||||||
|
void Finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ namespace Orchard.Environment.Extensions {
|
|||||||
private readonly IEnumerable<IExtensionFolders> _folders;
|
private readonly IEnumerable<IExtensionFolders> _folders;
|
||||||
private readonly IAsyncTokenProvider _asyncTokenProvider;
|
private readonly IAsyncTokenProvider _asyncTokenProvider;
|
||||||
private readonly ICacheManager _cacheManager;
|
private readonly ICacheManager _cacheManager;
|
||||||
|
private readonly IParallelCacheContext _parallelCacheContext;
|
||||||
private readonly IEnumerable<IExtensionLoader> _loaders;
|
private readonly IEnumerable<IExtensionLoader> _loaders;
|
||||||
|
|
||||||
public Localizer T { get; set; }
|
public Localizer T { get; set; }
|
||||||
@@ -24,11 +25,13 @@ namespace Orchard.Environment.Extensions {
|
|||||||
IEnumerable<IExtensionFolders> folders,
|
IEnumerable<IExtensionFolders> folders,
|
||||||
IEnumerable<IExtensionLoader> loaders,
|
IEnumerable<IExtensionLoader> loaders,
|
||||||
ICacheManager cacheManager,
|
ICacheManager cacheManager,
|
||||||
|
IParallelCacheContext parallelCacheContext,
|
||||||
IAsyncTokenProvider asyncTokenProvider) {
|
IAsyncTokenProvider asyncTokenProvider) {
|
||||||
|
|
||||||
_folders = folders;
|
_folders = folders;
|
||||||
_asyncTokenProvider = asyncTokenProvider;
|
_asyncTokenProvider = asyncTokenProvider;
|
||||||
_cacheManager = cacheManager;
|
_cacheManager = cacheManager;
|
||||||
|
_parallelCacheContext = parallelCacheContext;
|
||||||
_loaders = loaders.OrderBy(x => x.Order).ToArray();
|
_loaders = loaders.OrderBy(x => x.Order).ToArray();
|
||||||
T = NullLocalizer.Instance;
|
T = NullLocalizer.Instance;
|
||||||
Logger = NullLogger.Instance;
|
Logger = NullLogger.Instance;
|
||||||
@@ -42,16 +45,18 @@ namespace Orchard.Environment.Extensions {
|
|||||||
|
|
||||||
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
|
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
|
||||||
return _cacheManager.Get("AvailableExtensions", ctx =>
|
return _cacheManager.Get("AvailableExtensions", ctx =>
|
||||||
_folders
|
_parallelCacheContext
|
||||||
.AsParallel() // Execute in parallel for each folder
|
.RunInParallel(_folders, folder => folder.AvailableExtensions())
|
||||||
.SelectMany(folder => folder.AvailableExtensions())
|
.SelectMany(descriptors => descriptors)
|
||||||
.ToList() // Force execution inside the cache entry
|
.ToReadOnlyCollection());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<FeatureDescriptor> AvailableFeatures() {
|
public IEnumerable<FeatureDescriptor> AvailableFeatures() {
|
||||||
return _cacheManager.Get("AvailableFeatures", ctx =>
|
return _cacheManager.Get("AvailableFeatures", ctx =>
|
||||||
AvailableExtensions().SelectMany(ext => ext.Features).OrderByDependenciesAndPriorities(HasDependency, GetPriority).ToReadOnlyCollection());
|
AvailableExtensions()
|
||||||
|
.SelectMany(ext => ext.Features)
|
||||||
|
.OrderByDependenciesAndPriorities(HasDependency, GetPriority)
|
||||||
|
.ToReadOnlyCollection());
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static int GetPriority(FeatureDescriptor featureDescriptor) {
|
internal static int GetPriority(FeatureDescriptor featureDescriptor) {
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ namespace Orchard.Environment {
|
|||||||
// a single default host implementation is needed for bootstrapping a web app domain
|
// a single default host implementation is needed for bootstrapping a web app domain
|
||||||
builder.RegisterType<DefaultOrchardEventBus>().As<IEventBus>().SingleInstance();
|
builder.RegisterType<DefaultOrchardEventBus>().As<IEventBus>().SingleInstance();
|
||||||
builder.RegisterType<DefaultCacheHolder>().As<ICacheHolder>().SingleInstance();
|
builder.RegisterType<DefaultCacheHolder>().As<ICacheHolder>().SingleInstance();
|
||||||
builder.RegisterType<DefaultAcquireContextContext>().As<IAcquireContextContext>().SingleInstance();
|
builder.RegisterType<DefaultCacheContextAccessor>().As<ICacheContextAccessor>().SingleInstance();
|
||||||
|
builder.RegisterType<DefaultParallelCacheContext>().As<IParallelCacheContext>().SingleInstance();
|
||||||
builder.RegisterType<DefaultAsyncTokenProvider>().As<IAsyncTokenProvider>().SingleInstance();
|
builder.RegisterType<DefaultAsyncTokenProvider>().As<IAsyncTokenProvider>().SingleInstance();
|
||||||
builder.RegisterType<DefaultHostEnvironment>().As<IHostEnvironment>().SingleInstance();
|
builder.RegisterType<DefaultHostEnvironment>().As<IHostEnvironment>().SingleInstance();
|
||||||
builder.RegisterType<DefaultHostLocalRestart>().As<IHostLocalRestart>().SingleInstance();
|
builder.RegisterType<DefaultHostLocalRestart>().As<IHostLocalRestart>().SingleInstance();
|
||||||
|
|||||||
@@ -148,8 +148,10 @@
|
|||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Caching\DefaultAcquireContextContext.cs" />
|
<Compile Include="Caching\DefaultCacheContextAccessor.cs" />
|
||||||
<Compile Include="Caching\IAcquireContextContext.cs" />
|
<Compile Include="Caching\DefaultParallelCacheContext.cs" />
|
||||||
|
<Compile Include="Caching\ICacheContextAccessor.cs" />
|
||||||
|
<Compile Include="Caching\IParallelCacheContext.cs" />
|
||||||
<Compile Include="ContentManagement\ContentIdentity.cs" />
|
<Compile Include="ContentManagement\ContentIdentity.cs" />
|
||||||
<Compile Include="ContentManagement\ContentItemBehavior.cs" />
|
<Compile Include="ContentManagement\ContentItemBehavior.cs" />
|
||||||
<Compile Include="ContentManagement\ContentPartBehavior.cs" />
|
<Compile Include="ContentManagement\ContentPartBehavior.cs" />
|
||||||
|
|||||||
Reference in New Issue
Block a user