mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-26 12:03:16 +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<StubExtensionManager>().As<IExtensionManager>();
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||
builder.RegisterInstance(new Mock<IThemeManager>().Object);
|
||||
builder.RegisterInstance(new Mock<IOrchardServices>().Object);
|
||||
builder.RegisterInstance(new Mock<RequestContext>().Object);
|
||||
|
||||
@@ -50,6 +50,7 @@ namespace Orchard.Core.Tests.Settings.Metadata {
|
||||
.As(typeof(IMapper<SettingsDictionary, XElement>));
|
||||
builder.RegisterType<Signals>().As<ISignals>();
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||
|
||||
_container = builder.Build();
|
||||
|
||||
|
||||
@@ -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<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
builder.RegisterType<StubHostEnvironment>().As<IHostEnvironment>();
|
||||
|
||||
|
||||
@@ -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<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
builder.RegisterType<StubHostEnvironment>().As<IHostEnvironment>();
|
||||
|
||||
|
||||
@@ -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<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
|
||||
_mockedVirtualPathProvider = new Mock<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<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
|
||||
_mockedVirtualPathProvider = new Mock<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<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
builder.RegisterType<ShellDescriptorManager>().As<IShellDescriptorManager>().SingleInstance();
|
||||
builder.RegisterType<StubDataMigrationManager>().As<IDataMigrationManager>();
|
||||
|
||||
@@ -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<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
builder.RegisterType<ShellDescriptorManager>().As<IShellDescriptorManager>().SingleInstance();
|
||||
builder.RegisterType<ModuleRecipeHandlerTest.StubDataMigrationManager>().As<IDataMigrationManager>();
|
||||
|
||||
@@ -74,6 +74,7 @@ namespace Orchard.Tests.Modules.Recipes.Services {
|
||||
builder.RegisterType<StubAppDataFolder>().As<IAppDataFolder>();
|
||||
builder.RegisterType<StubClock>().As<IClock>();
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
builder.RegisterInstance(_folders).As<IExtensionFolders>();
|
||||
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<IContentDisplay>().Object);
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||
builder.RegisterType<Signals>().As<ISignals>();
|
||||
|
||||
builder.RegisterType<DefaultEncryptionService>().As<IEncryptionService>();
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Orchard.Tests.Caching {
|
||||
builder.RegisterModule(new CacheModule());
|
||||
builder.RegisterType<DefaultCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<DefaultCacheHolder>().As<ICacheHolder>().SingleInstance();
|
||||
builder.RegisterType<DefaultCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<DefaultCacheContextAccessor>().As<ICacheContextAccessor>();
|
||||
_container = builder.Build();
|
||||
_cacheManager = _container.Resolve<ICacheManager>(new TypedParameter(typeof(Type), GetType()));
|
||||
}
|
||||
|
||||
@@ -18,9 +18,8 @@ namespace Orchard.Tests.Caching {
|
||||
builder.RegisterModule(new CacheModule());
|
||||
builder.RegisterType<DefaultCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<DefaultCacheHolder>().As<ICacheHolder>().SingleInstance();
|
||||
builder.RegisterType<DefaultCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<DefaultCacheContextAccessor>().As<ICacheContextAccessor>();
|
||||
builder.RegisterInstance<IClock>(_clock = new StubClock());
|
||||
builder.RegisterType<DefaultCacheManager>().As<ICacheManager>();
|
||||
_container = builder.Build();
|
||||
_cacheManager = _container.Resolve<ICacheManager>(new TypedParameter(typeof(Type), GetType()));
|
||||
}
|
||||
|
||||
@@ -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<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
_session = _sessionFactory.OpenSession();
|
||||
builder.RegisterInstance(new DefaultContentManagerTests.TestSessionLocator(_session)).As<ISessionLocator>();
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Orchard.Tests.DisplayManagement.Descriptors {
|
||||
protected override void Register(Autofac.ContainerBuilder builder) {
|
||||
builder.RegisterType<PlacementFileParser>().As<IPlacementFileParser>();
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||
builder.RegisterType<InMemoryWebSiteFolder>().As<IWebSiteFolder>()
|
||||
.As<InMemoryWebSiteFolder>().InstancePerLifetimeScope();
|
||||
}
|
||||
|
||||
@@ -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<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
|
||||
_container = builder.Build();
|
||||
@@ -116,6 +117,9 @@ namespace Orchard.Tests.Environment.Extensions {
|
||||
#endregion
|
||||
}
|
||||
|
||||
private ExtensionManager CreateExtensionManager(StubFolders extensionFolder, StubLoaders extensionLoader) {
|
||||
return new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubParallelCacheContext(), new StubAsyncTokenProvider());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AvailableExtensionsShouldFollowCatalogLocations() {
|
||||
@@ -361,7 +365,7 @@ Features:
|
||||
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()
|
||||
.SelectMany(x => x.Features);
|
||||
|
||||
@@ -387,7 +391,7 @@ Features:
|
||||
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()
|
||||
.SelectMany(x => x.Features);
|
||||
|
||||
@@ -416,7 +420,7 @@ Features:
|
||||
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()
|
||||
.SelectMany(x => x.Features)
|
||||
.Single(x => x.Id == "TestFeature");
|
||||
@@ -446,7 +450,7 @@ Features:
|
||||
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()
|
||||
.SelectMany(x => x.Features)
|
||||
.Single(x => x.Id == "TestFeature");
|
||||
@@ -474,7 +478,7 @@ Features:
|
||||
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()
|
||||
.SelectMany(x => x.Features)
|
||||
.Single(x => x.Id == "TestModule");
|
||||
@@ -498,7 +502,7 @@ Version: 1.0.3
|
||||
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");
|
||||
|
||||
Assert.That(minimalisticModule.Features.Count(), Is.EqualTo(1));
|
||||
@@ -517,7 +521,7 @@ Version: 1.0.3
|
||||
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");
|
||||
|
||||
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<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
|
||||
_container = builder.Build();
|
||||
@@ -284,7 +285,7 @@ Features:
|
||||
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()
|
||||
.SelectMany(x => x.Features);
|
||||
|
||||
@@ -310,7 +311,7 @@ Features:
|
||||
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()
|
||||
.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]
|
||||
public void ExtensionManagerShouldReturnEmptyFeatureIfFeatureDoesNotExist() {
|
||||
var featureDescriptor = new FeatureDescriptor { Id = "NoSuchFeature", Extension = new ExtensionDescriptor { Id = "NoSuchFeature" } };
|
||||
@@ -347,7 +356,7 @@ Features:
|
||||
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()
|
||||
.SelectMany(x => x.Features)
|
||||
.Single(x => x.Id == "TestFeature");
|
||||
@@ -377,7 +386,7 @@ Features:
|
||||
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()
|
||||
.SelectMany(x => x.Features)
|
||||
.Single(x => x.Id == "TestFeature");
|
||||
@@ -405,7 +414,7 @@ Features:
|
||||
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()
|
||||
.SelectMany(x => x.Features)
|
||||
.Single(x => x.Id == "TestModule");
|
||||
@@ -429,7 +438,7 @@ Version: 1.0.3
|
||||
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");
|
||||
|
||||
Assert.That(minimalisticModule.Features.Count(), Is.EqualTo(1));
|
||||
@@ -465,7 +474,7 @@ Features:
|
||||
Dependencies: Beta
|
||||
");
|
||||
|
||||
IExtensionManager extensionManager = new ExtensionManager(new[] { extensionFolder }, new[] { extensionLoader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
||||
IExtensionManager extensionManager = CreateExtensionManager(extensionFolder, extensionLoader); ;
|
||||
var features = extensionManager.AvailableFeatures();
|
||||
Assert.That(features.Aggregate("<", (a, b) => a + b.Id + "<"), Is.EqualTo("<Beta<Gamma<Alpha<"));
|
||||
}
|
||||
@@ -505,7 +514,7 @@ Version: 1.0.3
|
||||
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();
|
||||
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) {
|
||||
var extensionManager = new ExtensionManager(folders, new[] { loader }, new StubCacheManager(), new StubAsyncTokenProvider());
|
||||
var extensionManager = CreateExtensionManager(folders, new[] { loader });
|
||||
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<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||
builder.RegisterType<StubAsyncTokenProvider>().As<IAsyncTokenProvider>();
|
||||
builder.RegisterType<ShellDescriptorManager>().As<IShellDescriptorManager>().SingleInstance();
|
||||
builder.RegisterType<ShellStateManager>().As<IShellStateManager>().SingleInstance();
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace Orchard.Tests.FileSystems.Dependencies {
|
||||
builder.RegisterType<StubClock>().As<IClock>().SingleInstance();
|
||||
builder.RegisterType<StubAppDataFolder>().As<IAppDataFolder>().SingleInstance();
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>().SingleInstance();
|
||||
builder.RegisterType<StubParallelCacheContext>().As<IParallelCacheContext>();
|
||||
builder.RegisterType<DefaultDependenciesFolder>().As<IDependenciesFolder>();
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Orchard.Tests.Stubs {
|
||||
private readonly ICacheManager _defaultCacheManager;
|
||||
|
||||
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) {
|
||||
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 IVolatileToken GetToken(Action<Action<IVolatileToken>> task) {
|
||||
var tokens = new List<IVolatileToken>();
|
||||
|
||||
@@ -14,4 +14,19 @@ namespace Orchard.Caching {
|
||||
public TKey Key { 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 {
|
||||
public class Cache<TKey, TResult> : ICache<TKey, TResult> {
|
||||
private readonly IAcquireContextContext _acquireContextContext;
|
||||
private readonly ICacheContextAccessor _cacheContextAccessor;
|
||||
private readonly ConcurrentDictionary<TKey, CacheEntry> _entries;
|
||||
|
||||
public Cache(IAcquireContextContext acquireContextContext) {
|
||||
_acquireContextContext = acquireContextContext;
|
||||
public Cache(ICacheContextAccessor cacheContextAccessor) {
|
||||
_cacheContextAccessor = cacheContextAccessor;
|
||||
_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));
|
||||
|
||||
// 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())
|
||||
_acquireContextContext.Instance.Monitor(token);
|
||||
_cacheContextAccessor.Current.Monitor(token);
|
||||
}
|
||||
|
||||
return entry.Result;
|
||||
@@ -37,14 +37,14 @@ namespace Orchard.Caching {
|
||||
IAcquireContext parentContext = null;
|
||||
try {
|
||||
// Push context
|
||||
parentContext = _acquireContextContext.Instance;
|
||||
_acquireContextContext.Instance = context;
|
||||
parentContext = _cacheContextAccessor.Current;
|
||||
_cacheContextAccessor.Current = context;
|
||||
|
||||
entry.Result = acquire(context);
|
||||
}
|
||||
finally {
|
||||
// Pop context
|
||||
_acquireContextContext.Instance = parentContext;
|
||||
_cacheContextAccessor.Current = parentContext;
|
||||
}
|
||||
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.
|
||||
/// </summary>
|
||||
public class DefaultCacheHolder : ICacheHolder {
|
||||
private readonly IAcquireContextContext _acquireContextContext;
|
||||
private readonly ICacheContextAccessor _cacheContextAccessor;
|
||||
private readonly ConcurrentDictionary<CacheKey, object> _caches = new ConcurrentDictionary<CacheKey, object>();
|
||||
|
||||
public DefaultCacheHolder(IAcquireContextContext acquireContextContext) {
|
||||
_acquireContextContext = acquireContextContext;
|
||||
public DefaultCacheHolder(ICacheContextAccessor cacheContextAccessor) {
|
||||
_cacheContextAccessor = cacheContextAccessor;
|
||||
}
|
||||
|
||||
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>
|
||||
public ICache<TKey, TResult> GetCache<TKey, TResult>(Type component) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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 IAsyncTokenProvider _asyncTokenProvider;
|
||||
private readonly ICacheManager _cacheManager;
|
||||
private readonly IParallelCacheContext _parallelCacheContext;
|
||||
private readonly IEnumerable<IExtensionLoader> _loaders;
|
||||
|
||||
public Localizer T { get; set; }
|
||||
@@ -24,11 +25,13 @@ namespace Orchard.Environment.Extensions {
|
||||
IEnumerable<IExtensionFolders> folders,
|
||||
IEnumerable<IExtensionLoader> loaders,
|
||||
ICacheManager cacheManager,
|
||||
IParallelCacheContext parallelCacheContext,
|
||||
IAsyncTokenProvider asyncTokenProvider) {
|
||||
|
||||
_folders = folders;
|
||||
_asyncTokenProvider = asyncTokenProvider;
|
||||
_cacheManager = cacheManager;
|
||||
_parallelCacheContext = parallelCacheContext;
|
||||
_loaders = loaders.OrderBy(x => x.Order).ToArray();
|
||||
T = NullLocalizer.Instance;
|
||||
Logger = NullLogger.Instance;
|
||||
@@ -42,16 +45,18 @@ namespace Orchard.Environment.Extensions {
|
||||
|
||||
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
|
||||
return _cacheManager.Get("AvailableExtensions", ctx =>
|
||||
_folders
|
||||
.AsParallel() // Execute in parallel for each folder
|
||||
.SelectMany(folder => folder.AvailableExtensions())
|
||||
.ToList() // Force execution inside the cache entry
|
||||
);
|
||||
_parallelCacheContext
|
||||
.RunInParallel(_folders, folder => folder.AvailableExtensions())
|
||||
.SelectMany(descriptors => descriptors)
|
||||
.ToReadOnlyCollection());
|
||||
}
|
||||
|
||||
public IEnumerable<FeatureDescriptor> AvailableFeatures() {
|
||||
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) {
|
||||
|
||||
@@ -39,7 +39,8 @@ 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<DefaultAcquireContextContext>().As<IAcquireContextContext>().SingleInstance();
|
||||
builder.RegisterType<DefaultCacheContextAccessor>().As<ICacheContextAccessor>().SingleInstance();
|
||||
builder.RegisterType<DefaultParallelCacheContext>().As<IParallelCacheContext>().SingleInstance();
|
||||
builder.RegisterType<DefaultAsyncTokenProvider>().As<IAsyncTokenProvider>().SingleInstance();
|
||||
builder.RegisterType<DefaultHostEnvironment>().As<IHostEnvironment>().SingleInstance();
|
||||
builder.RegisterType<DefaultHostLocalRestart>().As<IHostLocalRestart>().SingleInstance();
|
||||
|
||||
@@ -148,8 +148,10 @@
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Caching\DefaultAcquireContextContext.cs" />
|
||||
<Compile Include="Caching\IAcquireContextContext.cs" />
|
||||
<Compile Include="Caching\DefaultCacheContextAccessor.cs" />
|
||||
<Compile Include="Caching\DefaultParallelCacheContext.cs" />
|
||||
<Compile Include="Caching\ICacheContextAccessor.cs" />
|
||||
<Compile Include="Caching\IParallelCacheContext.cs" />
|
||||
<Compile Include="ContentManagement\ContentIdentity.cs" />
|
||||
<Compile Include="ContentManagement\ContentItemBehavior.cs" />
|
||||
<Compile Include="ContentManagement\ContentPartBehavior.cs" />
|
||||
|
||||
Reference in New Issue
Block a user