mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Supporting lazy cache manager resolution
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Autofac;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Caching;
|
||||
@@ -78,6 +80,42 @@ namespace Orchard.Tests.Caching {
|
||||
Is.Not.SameAs(c2.CacheManager.GetCache<string, string>()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CacheManagerIsNotBlocking() {
|
||||
var hits = 0;
|
||||
string result = "";
|
||||
|
||||
Enumerable.Range(0, 5).AsParallel().ForAll(x =>
|
||||
result = _cacheManager.Get("testItem", ctx => {
|
||||
// by waiting for 100ms we expect all the calls to Get
|
||||
// to enter this lambda
|
||||
Thread.Sleep(100);
|
||||
hits++;
|
||||
return "testResult";
|
||||
})
|
||||
);
|
||||
|
||||
Assert.That(result, Is.EqualTo("testResult"));
|
||||
Assert.That(hits, Is.GreaterThan(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CacheManagerIsBlocking() {
|
||||
var hits = 0;
|
||||
string result = "";
|
||||
|
||||
Enumerable.Range(0, 5).AsParallel().ForAll(x =>
|
||||
result = _cacheManager.Get("testItem", true, ctx => {
|
||||
Thread.Sleep(100);
|
||||
hits++;
|
||||
return "testResult";
|
||||
})
|
||||
);
|
||||
|
||||
Assert.That(result, Is.EqualTo("testResult"));
|
||||
Assert.That(hits, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
class ComponentOne {
|
||||
public ICacheManager CacheManager { get; set; }
|
||||
|
||||
|
@@ -125,7 +125,7 @@ namespace Orchard.Core.Settings.Metadata {
|
||||
}
|
||||
|
||||
private IDictionary<string, ContentTypeDefinition> AcquireContentTypeDefinitions() {
|
||||
return _cacheManager.Get("ContentTypeDefinitions", ctx => {
|
||||
return _cacheManager.Get("ContentTypeDefinitions", true, ctx => {
|
||||
MonitorContentDefinitionSignal(ctx);
|
||||
|
||||
AcquireContentPartDefinitions();
|
||||
@@ -140,7 +140,7 @@ namespace Orchard.Core.Settings.Metadata {
|
||||
}
|
||||
|
||||
private IDictionary<string, ContentPartDefinition> AcquireContentPartDefinitions() {
|
||||
return _cacheManager.Get("ContentPartDefinitions", ctx => {
|
||||
return _cacheManager.Get("ContentPartDefinitions", true, ctx => {
|
||||
MonitorContentDefinitionSignal(ctx);
|
||||
|
||||
var contentPartDefinitionRecords = _partDefinitionRepository.Table
|
||||
@@ -153,7 +153,7 @@ namespace Orchard.Core.Settings.Metadata {
|
||||
}
|
||||
|
||||
private IDictionary<string, ContentFieldDefinition> AcquireContentFieldDefinitions() {
|
||||
return _cacheManager.Get("ContentFieldDefinitions", ctx => {
|
||||
return _cacheManager.Get("ContentFieldDefinitions", true, ctx => {
|
||||
MonitorContentDefinitionSignal(ctx);
|
||||
|
||||
return _fieldDefinitionRepository.Table.Select(Build).ToDictionary(x => x.Name, y => y);
|
||||
|
@@ -24,7 +24,7 @@ namespace Orchard.Core.Settings.Services {
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public ISite GetSiteSettings() {
|
||||
var siteId = _cacheManager.Get("SiteId", ctx => {
|
||||
var siteId = _cacheManager.Get("SiteId", true, ctx => {
|
||||
var site = _contentManager.Query("Site")
|
||||
.List()
|
||||
.FirstOrDefault();
|
||||
|
@@ -22,7 +22,7 @@ namespace Orchard.ContentTypes.Services {
|
||||
}
|
||||
|
||||
public IEnumerable<StereotypeDescription> GetStereotypes() {
|
||||
return _cacheManager.Get("ContentType.Stereotypes", context => {
|
||||
return _cacheManager.Get("ContentType.Stereotypes", true, context => {
|
||||
|
||||
// TODO: Implement a signal in ContentDefinitionManager that gets raised whenever a type definition is updated.
|
||||
// For now, we'll just cache the stereotypes for 1 minute.
|
||||
|
@@ -38,7 +38,7 @@ namespace Orchard.Layouts.Services {
|
||||
public IEnumerable<ElementDescriptor> DescribeElements(DescribeElementsContext context) {
|
||||
var contentType = context.Content != null ? context.Content.ContentItem.ContentType : default(string);
|
||||
var cacheKey = String.Format("LayoutElementTypes-{0}-{1}", contentType ?? "AnyType", context.CacheVaryParam);
|
||||
return _cacheManager.Get(cacheKey, acquireContext => {
|
||||
return _cacheManager.Get(cacheKey, true, acquireContext => {
|
||||
var harvesterContext = new HarvestElementsContext {
|
||||
Content = context.Content
|
||||
};
|
||||
@@ -55,7 +55,7 @@ namespace Orchard.Layouts.Services {
|
||||
|
||||
public IEnumerable<CategoryDescriptor> GetCategories(DescribeElementsContext context) {
|
||||
var contentType = context.Content != null ? context.Content.ContentItem.ContentType : default(string);
|
||||
return _cacheManager.Get(String.Format("ElementCategories-{0}-{1}", contentType ?? "AnyType", context.CacheVaryParam), acquireContext => {
|
||||
return _cacheManager.Get(String.Format("ElementCategories-{0}-{1}", contentType ?? "AnyType", context.CacheVaryParam), true, acquireContext => {
|
||||
var elements = DescribeElements(context);
|
||||
var categoryDictionary = GetCategories();
|
||||
var categoryDescriptorDictionary = new Dictionary<string, CategoryDescriptor>();
|
||||
|
@@ -58,7 +58,7 @@ namespace Orchard.MediaProcessing.Services {
|
||||
}
|
||||
|
||||
private IDictionary<string, string> GetProfileCache(string profile) {
|
||||
return _cacheManager.Get("MediaProcessing_" + profile, ctx => {
|
||||
return _cacheManager.Get("MediaProcessing_" + profile, true, ctx => {
|
||||
ctx.Monitor(_signals.When("MediaProcessing_Saved_" + profile));
|
||||
var dictionary = new Dictionary<string, string>();
|
||||
|
||||
|
@@ -32,7 +32,7 @@ namespace Orchard.MediaProcessing.Services {
|
||||
|
||||
public ImageProfilePart GetImageProfileByName(string name) {
|
||||
|
||||
var profileId = _cacheManager.Get("ProfileId_" + name, ctx => {
|
||||
var profileId = _cacheManager.Get("ProfileId_" + name, true, ctx => {
|
||||
var profile = _contentManager.Query<ImageProfilePart, ImageProfilePartRecord>()
|
||||
.Where(x => x.Name == name)
|
||||
.Slice(0, 1)
|
||||
|
@@ -461,7 +461,7 @@ namespace Orchard.OutputCache.Filters {
|
||||
|
||||
private CacheSettings CacheSettings {
|
||||
get {
|
||||
return _cacheSettings ?? (_cacheSettings = _cacheManager.Get(CacheSettings.CacheKey, context => {
|
||||
return _cacheSettings ?? (_cacheSettings = _cacheManager.Get(CacheSettings.CacheKey, true, context => {
|
||||
context.Monitor(_signals.When(CacheSettings.CacheKey));
|
||||
return new CacheSettings(_workContext.CurrentSite.As<CacheSettingsPart>());
|
||||
}));
|
||||
|
@@ -99,7 +99,7 @@ namespace Orchard.OutputCache.Services {
|
||||
}
|
||||
|
||||
public IEnumerable<CacheRouteConfig> GetRouteConfigs() {
|
||||
return _cacheManager.Get(RouteConfigsCacheKey,
|
||||
return _cacheManager.Get(RouteConfigsCacheKey, true,
|
||||
ctx => {
|
||||
ctx.Monitor(_signals.When(RouteConfigsCacheKey));
|
||||
return _repository.Fetch(c => true).Select(c => new CacheRouteConfig { RouteKey = c.RouteKey, Duration = c.Duration, GraceTime = c.GraceTime }).ToReadOnlyCollection();
|
||||
|
@@ -14,7 +14,7 @@ namespace Orchard.Scripting.Dlr.Services {
|
||||
}
|
||||
|
||||
public object Evaluate(string expression, IEnumerable<IGlobalMethodProvider> providers) {
|
||||
object execContextType = _cacheManager.Get("---", ctx => (object)_scriptingManager.ExecuteExpression(@"
|
||||
object execContextType = _cacheManager.Get("---", true, ctx => (object)_scriptingManager.ExecuteExpression(@"
|
||||
class ExecBlock
|
||||
def initialize(callbacks)
|
||||
@callbacks = callbacks
|
||||
@@ -38,7 +38,7 @@ class ExecContext
|
||||
end
|
||||
ExecContext
|
||||
"));
|
||||
var ops = _cacheManager.Get("----", ctx => (ObjectOperations)_scriptingManager.ExecuteOperation(x => x));
|
||||
var ops = _cacheManager.Get("----", true, ctx => (ObjectOperations)_scriptingManager.ExecuteOperation(x => x));
|
||||
object execContext = _cacheManager.Get(expression, ctx => (object)ops.InvokeMember(execContextType, "alloc", expression));
|
||||
dynamic result = ops.InvokeMember(execContext, "evaluate", new CallbackApi(this, providers));
|
||||
return ConvertRubyValue(result);
|
||||
|
@@ -20,7 +20,7 @@ namespace Orchard.Scripting {
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public object Evaluate(string expression, IEnumerable<IGlobalMethodProvider> providers) {
|
||||
var expr = _cacheManager.Get(expression, ctx => {
|
||||
var expr = _cacheManager.Get(expression, true, ctx => {
|
||||
var ast = ParseExpression(expression);
|
||||
return new { Tree = ast, Errors = ast.GetErrors().ToList() };
|
||||
});
|
||||
|
@@ -32,7 +32,7 @@ namespace Orchard.Tags.Services {
|
||||
|
||||
public IEnumerable<TagCount> GetPopularTags(int buckets, string slug) {
|
||||
var cacheKey = "Orchard.Tags.TagCloud." + (slug ?? "") + '.' + buckets;
|
||||
return _cacheManager.Get(cacheKey,
|
||||
return _cacheManager.Get(cacheKey, true,
|
||||
ctx => {
|
||||
ctx.Monitor(_signals.When(TagCloudTagsChanged));
|
||||
IEnumerable<TagCount> tagCounts;
|
||||
|
@@ -55,7 +55,7 @@ namespace Orchard.Templates.Services {
|
||||
}
|
||||
|
||||
private IDictionary<string, TemplateResult> BuildShapeProcessors() {
|
||||
return _cacheManager.Get("Template.ShapeProcessors", ctx => {
|
||||
return _cacheManager.Get("Template.ShapeProcessors", true, ctx => {
|
||||
ctx.Monitor(_signals.When(DefaultTemplateService.TemplatesSignal));
|
||||
|
||||
// select all name of types which contains ShapePart
|
||||
|
@@ -5,4 +5,17 @@ namespace Orchard.Caching {
|
||||
TResult Get<TKey, TResult>(TKey key, Func<AcquireContext<TKey>, TResult> acquire);
|
||||
ICache<TKey, TResult> GetCache<TKey, TResult>();
|
||||
}
|
||||
|
||||
public static class CacheManagerExtensions {
|
||||
public static TResult Get<TKey, TResult>(this ICacheManager cacheManager, TKey key, bool lazy, Func<AcquireContext<TKey>, TResult> acquire) {
|
||||
// Wrap the call in a Lazy initializer to prevent multiple processes from
|
||||
// executing the same lambda in parallel.
|
||||
if (lazy) {
|
||||
return cacheManager.Get<TKey, Lazy<TResult>>(key, k => new Lazy<TResult>(() => acquire(k))).Value;
|
||||
}
|
||||
else {
|
||||
return cacheManager.Get(key, acquire);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -814,7 +814,7 @@ namespace Orchard.ContentManagement {
|
||||
}
|
||||
|
||||
private ContentTypeRecord AcquireContentTypeRecord(string contentType) {
|
||||
var contentTypeId = _cacheManager.Get(contentType + "_Record", ctx => {
|
||||
var contentTypeId = _cacheManager.Get(contentType + "_Record", true, ctx => {
|
||||
ctx.Monitor(_signals.When(contentType + "_Record"));
|
||||
|
||||
var contentTypeRecord = _contentTypeRepository.Get(x => x.Name == contentType);
|
||||
|
@@ -76,7 +76,7 @@ namespace Orchard.ContentManagement {
|
||||
}
|
||||
|
||||
private int GetContentTypeRecordId(string contentType) {
|
||||
return _cacheManager.Get(contentType + "_Record", ctx => {
|
||||
return _cacheManager.Get(contentType + "_Record", true, ctx => {
|
||||
ctx.Monitor(_signals.When(contentType + "_Record"));
|
||||
|
||||
var contentTypeRecord = _contentTypeRepository.Get(x => x.Name == contentType);
|
||||
|
@@ -37,7 +37,7 @@ namespace Orchard.DisplayManagement.Descriptors {
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public ShapeTable GetShapeTable(string themeName) {
|
||||
return _cacheManager.Get(themeName ?? "", x => {
|
||||
return _cacheManager.Get(themeName ?? "", true, x => {
|
||||
Logger.Information("Start building shape table");
|
||||
|
||||
var alterationSets = _parallelCacheContext.RunInParallel(_bindingStrategies, bindingStrategy => {
|
||||
|
@@ -30,7 +30,7 @@ namespace Orchard.DisplayManagement.Descriptors.ShapePlacementStrategy {
|
||||
public bool DisableMonitoring { get; set; }
|
||||
|
||||
public PlacementFile Parse(string virtualPath) {
|
||||
return _cacheManager.Get(virtualPath, context => {
|
||||
return _cacheManager.Get(virtualPath, true, context => {
|
||||
|
||||
if (!DisableMonitoring) {
|
||||
Logger.Debug("Monitoring virtual path \"{0}\"", virtualPath);
|
||||
|
@@ -77,7 +77,7 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy {
|
||||
var pathContexts = harvesterInfos.SelectMany(harvesterInfo => harvesterInfo.subPaths.Select(subPath => {
|
||||
var basePath = Path.Combine(extensionDescriptor.Location, extensionDescriptor.Id).Replace(Path.DirectorySeparatorChar, '/');
|
||||
var virtualPath = Path.Combine(basePath, subPath).Replace(Path.DirectorySeparatorChar, '/');
|
||||
var fileNames = _cacheManager.Get(virtualPath, ctx => {
|
||||
var fileNames = _cacheManager.Get(virtualPath, true, ctx => {
|
||||
if (!_virtualPathProvider.DirectoryExists(virtualPath))
|
||||
return new List<string>();
|
||||
|
||||
|
@@ -23,7 +23,7 @@ namespace Orchard.Environment.Extensions.Compilers {
|
||||
public bool DisableMonitoring { get; set; }
|
||||
|
||||
public ProjectFileDescriptor Parse(string virtualPath) {
|
||||
return _cacheManager.Get(virtualPath,
|
||||
return _cacheManager.Get(virtualPath, true,
|
||||
ctx => {
|
||||
if (!DisableMonitoring) {
|
||||
Logger.Debug("Monitoring virtual path \"{0}\"", virtualPath);
|
||||
|
@@ -45,7 +45,7 @@ namespace Orchard.Environment.Extensions {
|
||||
}
|
||||
|
||||
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
|
||||
return _cacheManager.Get("AvailableExtensions", ctx =>
|
||||
return _cacheManager.Get("AvailableExtensions", true, ctx =>
|
||||
_parallelCacheContext
|
||||
.RunInParallel(_folders, folder => folder.AvailableExtensions().ToList())
|
||||
.SelectMany(descriptors => descriptors)
|
||||
@@ -53,7 +53,7 @@ namespace Orchard.Environment.Extensions {
|
||||
}
|
||||
|
||||
public IEnumerable<FeatureDescriptor> AvailableFeatures() {
|
||||
return _cacheManager.Get("AvailableFeatures", ctx =>
|
||||
return _cacheManager.Get("AvailableFeatures", true, ctx =>
|
||||
AvailableExtensions()
|
||||
.SelectMany(ext => ext.Features)
|
||||
.OrderByDependenciesAndPriorities(HasDependency, GetPriority)
|
||||
@@ -93,7 +93,7 @@ namespace Orchard.Environment.Extensions {
|
||||
|
||||
var result =
|
||||
_parallelCacheContext
|
||||
.RunInParallel(featureDescriptors, descriptor => _cacheManager.Get(descriptor.Id, ctx => LoadFeature(descriptor)))
|
||||
.RunInParallel(featureDescriptors, descriptor => _cacheManager.Get(descriptor.Id, true, ctx => LoadFeature(descriptor)))
|
||||
.ToArray();
|
||||
|
||||
Logger.Information("Done loading features");
|
||||
@@ -107,7 +107,7 @@ namespace Orchard.Environment.Extensions {
|
||||
|
||||
ExtensionEntry extensionEntry;
|
||||
try {
|
||||
extensionEntry = _cacheManager.Get(extensionId, ctx => {
|
||||
extensionEntry = _cacheManager.Get(extensionId, true, ctx => {
|
||||
var entry = BuildEntry(extensionDescriptor);
|
||||
if (entry != null) {
|
||||
ctx.Monitor(_asyncTokenProvider.GetToken(monitor => {
|
||||
|
@@ -56,7 +56,7 @@ namespace Orchard.Environment.Extensions.Folders {
|
||||
private IEnumerable<ExtensionDescriptor> HarvestExtensions(string path, string extensionType, string manifestName, bool manifestIsOptional) {
|
||||
string key = string.Format("{0}-{1}-{2}", path, manifestName, extensionType);
|
||||
|
||||
return _cacheManager.Get(key, ctx => {
|
||||
return _cacheManager.Get(key, true, ctx => {
|
||||
if (!DisableMonitoring) {
|
||||
Logger.Debug("Monitoring virtual path \"{0}\"", path);
|
||||
ctx.Monitor(_webSiteFolder.WhenPathChanges(path));
|
||||
@@ -135,7 +135,7 @@ namespace Orchard.Environment.Extensions.Folders {
|
||||
}
|
||||
|
||||
private ExtensionDescriptor GetExtensionDescriptor(string locationPath, string extensionId, string extensionType, string manifestPath, bool manifestIsOptional) {
|
||||
return _cacheManager.Get(manifestPath, context => {
|
||||
return _cacheManager.Get(manifestPath, true, context => {
|
||||
if (!DisableMonitoring) {
|
||||
Logger.Debug("Monitoring virtual path \"{0}\"", manifestPath);
|
||||
context.Monitor(_webSiteFolder.WhenPathChanges(manifestPath));
|
||||
|
@@ -37,7 +37,7 @@ namespace Orchard.Environment {
|
||||
public string Resolve(string shortName) {
|
||||
// A few common .net framework assemblies are referenced by the Orchard.Framework assembly.
|
||||
// Look into those to see if we can find the assembly we are looking for.
|
||||
var orchardFrameworkReferences = _cacheManager.Get(typeof(IAssemblyLoader), ctx =>
|
||||
var orchardFrameworkReferences = _cacheManager.Get(typeof(IAssemblyLoader), true, ctx =>
|
||||
ctx.Key.Assembly
|
||||
.GetReferencedAssemblies()
|
||||
.GroupBy(n => AssemblyLoaderExtensions.ExtractAssemblyShortName(n.FullName), StringComparer.OrdinalIgnoreCase)
|
||||
|
@@ -34,7 +34,7 @@ namespace Orchard.FileSystems.Dependencies {
|
||||
}
|
||||
|
||||
public IEnumerable<DependencyDescriptor> LoadDescriptors() {
|
||||
return _cacheManager.Get(PersistencePath,
|
||||
return _cacheManager.Get(PersistencePath, true,
|
||||
ctx => {
|
||||
_appDataFolder.CreateDirectory(BasePath);
|
||||
|
||||
|
@@ -65,7 +65,7 @@ namespace Orchard.FileSystems.Dependencies {
|
||||
}
|
||||
|
||||
public IEnumerable<ActivatedExtensionDescriptor> LoadDescriptors() {
|
||||
return _cacheManager.Get(PersistencePath, ctx => {
|
||||
return _cacheManager.Get(PersistencePath, true, ctx => {
|
||||
_appDataFolder.CreateDirectory(BasePath);
|
||||
|
||||
if (!DisableMonitoring) {
|
||||
|
@@ -26,7 +26,7 @@ namespace Orchard.Localization.Services {
|
||||
}
|
||||
|
||||
public IEnumerable<string> ListCultures() {
|
||||
return _cacheManager.Get("Cultures", context => {
|
||||
return _cacheManager.Get("Cultures", true, context => {
|
||||
context.Monitor(_signals.When("culturesChanged"));
|
||||
|
||||
return _cultureRepository.Table.Select(o => o.Culture).ToList();
|
||||
|
@@ -90,7 +90,7 @@ namespace Orchard.Localization.Services {
|
||||
// Cache entry will be invalidated any time the directories hosting
|
||||
// the .po files are modified.
|
||||
private CultureDictionary LoadCulture(string culture) {
|
||||
return _cacheManager.Get(culture, ctx => {
|
||||
return _cacheManager.Get(culture, true, ctx => {
|
||||
ctx.Monitor(_signals.When("culturesChanged"));
|
||||
return new CultureDictionary {
|
||||
CultureName = culture,
|
||||
|
Reference in New Issue
Block a user