mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
Abstract away cache context
This is needed to support proper behavior of cache context when executing tasks in parallel. --HG-- branch : 1.x
This commit is contained in:
@@ -8,7 +8,7 @@ namespace Orchard.Tests.Stubs {
|
||||
private readonly ICacheManager _defaultCacheManager;
|
||||
|
||||
public StubCacheManager() {
|
||||
_defaultCacheManager = new DefaultCacheManager(this.GetType(), new DefaultCacheHolder());
|
||||
_defaultCacheManager = new DefaultCacheManager(this.GetType(), new DefaultCacheHolder(new DefaultAcquireContextContext()));
|
||||
}
|
||||
public TResult Get<TKey, TResult>(TKey key, Func<AcquireContext<TKey>, TResult> acquire) {
|
||||
return _defaultCacheManager.Get(key, acquire);
|
||||
|
||||
@@ -5,9 +5,11 @@ using System.Linq;
|
||||
|
||||
namespace Orchard.Caching {
|
||||
public class Cache<TKey, TResult> : ICache<TKey, TResult> {
|
||||
private readonly IAcquireContextContext _acquireContextContext;
|
||||
private readonly ConcurrentDictionary<TKey, CacheEntry> _entries;
|
||||
|
||||
public Cache() {
|
||||
public Cache(IAcquireContextContext acquireContextContext) {
|
||||
_acquireContextContext = acquireContextContext;
|
||||
_entries = new ConcurrentDictionary<TKey, CacheEntry>();
|
||||
}
|
||||
|
||||
@@ -19,30 +21,30 @@ 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 (CacheAquireContext.ThreadInstance != null && entry.GetTokens() != null) {
|
||||
if (_acquireContextContext.Instance != null && entry.GetTokens() != null) {
|
||||
foreach (var token in entry.GetTokens())
|
||||
CacheAquireContext.ThreadInstance.Monitor(token);
|
||||
_acquireContextContext.Instance.Monitor(token);
|
||||
}
|
||||
|
||||
return entry.Result;
|
||||
}
|
||||
|
||||
|
||||
private static CacheEntry CreateEntry(TKey k, Func<AcquireContext<TKey>, TResult> acquire) {
|
||||
private CacheEntry CreateEntry(TKey k, Func<AcquireContext<TKey>, TResult> acquire) {
|
||||
var entry = new CacheEntry();
|
||||
var context = new AcquireContext<TKey>(k, entry.AddToken);
|
||||
|
||||
IAcquireContext parentContext = null;
|
||||
try {
|
||||
// Push context
|
||||
parentContext = CacheAquireContext.ThreadInstance;
|
||||
CacheAquireContext.ThreadInstance = context;
|
||||
parentContext = _acquireContextContext.Instance;
|
||||
_acquireContextContext.Instance = context;
|
||||
|
||||
entry.Result = acquire(context);
|
||||
}
|
||||
finally {
|
||||
// Pop context
|
||||
CacheAquireContext.ThreadInstance = parentContext;
|
||||
_acquireContextContext.Instance = parentContext;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
@@ -64,12 +66,4 @@ namespace Orchard.Caching {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Keep track of nested caches contexts on a given thread
|
||||
/// </summary>
|
||||
internal static class CacheAquireContext {
|
||||
[ThreadStatic]
|
||||
public static IAcquireContext ThreadInstance;
|
||||
}
|
||||
}
|
||||
|
||||
56
src/Orchard/Caching/DefaultAcquireContextContext.cs
Normal file
56
src/Orchard/Caching/DefaultAcquireContextContext.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,13 @@ 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 ConcurrentDictionary<CacheKey, object> _caches = new ConcurrentDictionary<CacheKey, object>();
|
||||
|
||||
public DefaultCacheHolder(IAcquireContextContext acquireContextContext) {
|
||||
_acquireContextContext = acquireContextContext;
|
||||
}
|
||||
|
||||
class CacheKey : Tuple<Type, Type, Type> {
|
||||
public CacheKey(Type component, Type key, Type result)
|
||||
: base(component, key, result) {
|
||||
@@ -24,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>());
|
||||
var result = _caches.GetOrAdd(cacheKey, k => new Cache<TKey, TResult>(_acquireContextContext));
|
||||
return (Cache<TKey, TResult>)result;
|
||||
}
|
||||
}
|
||||
|
||||
5
src/Orchard/Caching/IAcquireContextContext.cs
Normal file
5
src/Orchard/Caching/IAcquireContextContext.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
namespace Orchard.Caching {
|
||||
public interface IAcquireContextContext {
|
||||
IAcquireContext Instance { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -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<DefaultAcquireContextContext>().As<IAcquireContextContext>().SingleInstance();
|
||||
builder.RegisterType<DefaultAsyncTokenProvider>().As<IAsyncTokenProvider>().SingleInstance();
|
||||
builder.RegisterType<DefaultHostEnvironment>().As<IHostEnvironment>().SingleInstance();
|
||||
builder.RegisterType<DefaultHostLocalRestart>().As<IHostLocalRestart>().SingleInstance();
|
||||
|
||||
@@ -148,6 +148,8 @@
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Caching\DefaultAcquireContextContext.cs" />
|
||||
<Compile Include="Caching\IAcquireContextContext.cs" />
|
||||
<Compile Include="ContentManagement\ContentIdentity.cs" />
|
||||
<Compile Include="ContentManagement\ContentItemBehavior.cs" />
|
||||
<Compile Include="ContentManagement\ContentPartBehavior.cs" />
|
||||
@@ -178,6 +180,7 @@
|
||||
<Compile Include="Caching\DefaultAsyncTokenProvider.cs" />
|
||||
<Compile Include="Environment\Extensions\ExtensionMonitoringCoordinator.cs" />
|
||||
<Compile Include="Caching\IAsyncTokenProvider.cs" />
|
||||
<Compile Include="Environment\Extensions\Folders\CoreModuleFolders.cs" />
|
||||
<Compile Include="Environment\Extensions\Folders\IExtensionHarvester.cs" />
|
||||
<Compile Include="Environment\Extensions\IExtensionMonitoringCoordinator.cs" />
|
||||
<Compile Include="Environment\Extensions\OrchardSuppressDependencyAttribute.cs" />
|
||||
|
||||
Reference in New Issue
Block a user