Feature list not refreshed when adding a new module

Update cache manager to rely on a thread static variable to
keep track of nested calls to ICacheManager.Get().

This fixes this particular bug of IExtensionManager caching the list
of available features: instead of storing the result of the computation
in a field (which is incorrect), use the cache manager.

Work Items: 16867

--HG--
branch : dev
This commit is contained in:
Renaud Paquay
2010-11-24 19:14:29 -08:00
parent c8fbbbe53e
commit 80a4c43ded
5 changed files with 40 additions and 10 deletions

View File

@@ -1,7 +1,11 @@
using System;
namespace Orchard.Caching {
public class AcquireContext<TKey> {
public interface IAcquireContext {
Action<IVolatileToken> Monitor { get; }
}
public class AcquireContext<TKey> : IAcquireContext {
public AcquireContext(TKey key, Action<IVolatileToken> monitor) {
Key = key;
Monitor = monitor;

View File

@@ -17,13 +17,33 @@ namespace Orchard.Caching {
k => CreateEntry(k, acquire),
// "Update" lamdba
(k, currentEntry) => (currentEntry.Tokens.All(t => t.IsCurrent) ? currentEntry : CreateEntry(k, acquire)));
// Bubble up volatile tokens to parent context
if (CacheAquireContext.ThreadInstance != null) {
foreach (var token in entry.Tokens)
CacheAquireContext.ThreadInstance.Monitor(token);
}
return entry.Result;
}
private static CacheEntry CreateEntry(TKey k, Func<AcquireContext<TKey>, TResult> acquire) {
var entry = new CacheEntry { Tokens = new List<IVolatileToken>() };
var context = new AcquireContext<TKey>(k, volatileItem => entry.Tokens.Add(volatileItem));
entry.Result = acquire(context);
IAcquireContext parentContext = null;
try {
// Push context
parentContext = CacheAquireContext.ThreadInstance;
CacheAquireContext.ThreadInstance = context;
entry.Result = acquire(context);
}
finally {
// Pop context
CacheAquireContext.ThreadInstance = parentContext;
}
return entry;
}
@@ -32,4 +52,12 @@ namespace Orchard.Caching {
public IList<IVolatileToken> Tokens { get; set; }
}
}
/// <summary>
/// Keep track of nested caches contexts on a given thread
/// </summary>
internal static class CacheAquireContext {
[ThreadStatic]
public static IAcquireContext ThreadInstance;
}
}

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard.Caching;
using Orchard.Environment.Extensions.Folders;
using Orchard.Environment.Extensions.Loaders;
@@ -16,7 +15,6 @@ namespace Orchard.Environment.Extensions {
private readonly IEnumerable<IExtensionFolders> _folders;
private readonly ICacheManager _cacheManager;
private readonly IEnumerable<IExtensionLoader> _loaders;
private IEnumerable<FeatureDescriptor> _featureDescriptors;
public Localizer T { get; set; }
public ILogger Logger { get; set; }
@@ -40,11 +38,8 @@ namespace Orchard.Environment.Extensions {
}
public IEnumerable<FeatureDescriptor> AvailableFeatures() {
if (_featureDescriptors == null || _featureDescriptors.Count() == 0) {
_featureDescriptors = AvailableExtensions().SelectMany(ext => ext.Features).OrderByDependencies(HasDependency).ToReadOnlyCollection();
return _featureDescriptors;
}
return _featureDescriptors;
return _cacheManager.Get("...", ctx =>
AvailableExtensions().SelectMany(ext => ext.Features).OrderByDependencies(HasDependency).ToReadOnlyCollection());
}
/// <summary>

View File

@@ -47,7 +47,6 @@ namespace Orchard.Environment.Extensions.Folders {
foreach (var subfolderPath in subfolderPaths) {
var extensionId = Path.GetFileName(subfolderPath.TrimEnd('/', '\\'));
var manifestPath = Path.Combine(subfolderPath, _manifestName);
ctx.Monitor(_webSiteFolder.WhenPathChanges(manifestPath));
try {
var descriptor = GetExtensionDescriptor(path, extensionId, manifestPath);
if (descriptor != null)

View File

@@ -89,6 +89,10 @@ namespace Orchard.FileSystems.VirtualPath {
}
public bool IsCurrent { get; set; }
public string VirtualPath { get; private set; }
public override string ToString() {
return string.Format("IsCurrent: {0}, VirtualPath: \"{1}\"", IsCurrent, VirtualPath);
}
}
class Thunk {