mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-09-19 01:57:55 +08:00
Simplify caching of NHibernate configuration
--HG-- branch : dev
This commit is contained in:
@@ -18,7 +18,6 @@ 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<SessionConfigurationCache>().As<ISessionConfigurationCache>().SingleInstance();
|
||||
builder.RegisterType<DefaultDependenciesFolder>().As<IDependenciesFolder>();
|
||||
return builder.Build();
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using NHibernate.Cfg;
|
||||
using Orchard.Environment.ShellBuilders.Models;
|
||||
|
||||
namespace Orchard.Data {
|
||||
public interface ISessionConfigurationCache {
|
||||
Configuration GetConfiguration(ShellBlueprint shellBlueprint);
|
||||
public interface ISessionConfigurationCache : ISingletonDependency {
|
||||
Configuration GetConfiguration(Func<Configuration> builder);
|
||||
}
|
||||
}
|
@@ -1,50 +1,108 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using NHibernate.Cfg;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Environment.ShellBuilders.Models;
|
||||
using Orchard.FileSystems.AppData;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Utility;
|
||||
|
||||
namespace Orchard.Data {
|
||||
public class SessionConfigurationCache : ISessionConfigurationCache {
|
||||
private readonly ShellSettings _shellSettings;
|
||||
private readonly ShellBlueprint _shellBlueprint;
|
||||
private readonly IAppDataFolder _appDataFolder;
|
||||
|
||||
public SessionConfigurationCache(IAppDataFolder appDataFolder) {
|
||||
public SessionConfigurationCache(ShellSettings shellSettings, ShellBlueprint shellBlueprint, IAppDataFolder appDataFolder) {
|
||||
_shellSettings = shellSettings;
|
||||
_shellBlueprint = shellBlueprint;
|
||||
_appDataFolder = appDataFolder;
|
||||
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public void StoreConfiguration(string shellName, Configuration config) {
|
||||
var pathName = GetPathName(shellName);
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public Configuration GetConfiguration(Func<Configuration> builder) {
|
||||
var hash = ComputeHash(_shellBlueprint).Value;
|
||||
|
||||
// Return previous configuration if it exsists and has the same hash as
|
||||
// the current blueprint.
|
||||
var previousConfig = ReadConfiguration(_shellSettings.Name);
|
||||
if (previousConfig != null) {
|
||||
if (previousConfig.ShellName == _shellSettings.Name && previousConfig.Hash == hash) {
|
||||
return previousConfig.Configuration;
|
||||
}
|
||||
}
|
||||
|
||||
// Create cache and persist it
|
||||
var cache = new ConfigurationCache {
|
||||
ShellName = _shellSettings.Name,
|
||||
Hash = hash,
|
||||
Configuration = builder()
|
||||
};
|
||||
|
||||
StoreConfiguration(cache);
|
||||
return cache.Configuration;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ConfigurationCache {
|
||||
public string ShellName { get; set; }
|
||||
public string Hash { get; set; }
|
||||
public Configuration Configuration { get; set; }
|
||||
}
|
||||
|
||||
private void StoreConfiguration(ConfigurationCache cache) {
|
||||
var pathName = GetPathName(cache.ShellName);
|
||||
|
||||
using (var stream = _appDataFolder.CreateFile(pathName)) {
|
||||
new BinaryFormatter().Serialize(stream, config);
|
||||
new BinaryFormatter().Serialize(stream, cache);
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteConfiguration(string shellName) {
|
||||
var pathName = GetPathName(shellName);
|
||||
_appDataFolder.DeleteFile(pathName);
|
||||
}
|
||||
|
||||
public void DeleteAll() {
|
||||
if (!_appDataFolder.DirectoryExists("Sites"))
|
||||
return;
|
||||
|
||||
foreach (var shellName in _appDataFolder.ListDirectories("Sites"))
|
||||
DeleteConfiguration(shellName);
|
||||
}
|
||||
|
||||
public Configuration GetConfiguration(string shellName) {
|
||||
private ConfigurationCache ReadConfiguration(string shellName) {
|
||||
var pathName = GetPathName(shellName);
|
||||
|
||||
if (!_appDataFolder.FileExists(pathName)) {
|
||||
if (!_appDataFolder.FileExists(pathName))
|
||||
return null;
|
||||
|
||||
try {
|
||||
using (var stream = _appDataFolder.OpenFile(pathName)) {
|
||||
return new BinaryFormatter().Deserialize(stream) as ConfigurationCache;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
for (var scan = e; scan != null; scan = scan.InnerException)
|
||||
Logger.Warning("The cached NHibernate configuration cache can't be read: {0}", scan.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
using (var stream = _appDataFolder.OpenFile(pathName)) {
|
||||
return new BinaryFormatter().Deserialize(stream) as Configuration;
|
||||
private Hash ComputeHash(ShellBlueprint shellBlueprint) {
|
||||
// We need to hash the assemnly names, record names and property names
|
||||
var hash = new Hash();
|
||||
|
||||
foreach (var tableName in shellBlueprint.Records.Select(x => x.TableName)) {
|
||||
hash.AddString(tableName);
|
||||
}
|
||||
|
||||
foreach (var recordType in shellBlueprint.Records.Select(x => x.Type)) {
|
||||
hash.AddTypeReference(recordType);
|
||||
|
||||
foreach (var property in recordType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public)) {
|
||||
hash.AddString(property.Name);
|
||||
hash.AddTypeReference(property.PropertyType);
|
||||
}
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
private string GetPathName(string shellName) {
|
||||
return _appDataFolder.Combine("Sites", shellName, "mappings.bin");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -55,8 +55,8 @@ namespace Orchard.Data {
|
||||
}
|
||||
|
||||
public Configuration GetConfiguration() {
|
||||
lock ( this ) {
|
||||
if ( _configuration == null ) {
|
||||
lock (this) {
|
||||
if (_configuration == null) {
|
||||
_configuration = BuildConfiguration();
|
||||
}
|
||||
}
|
||||
@@ -73,15 +73,10 @@ namespace Orchard.Data {
|
||||
private Configuration BuildConfiguration() {
|
||||
var parameters = GetSessionFactoryParameters();
|
||||
|
||||
var config = _sessionConfigurationCache.GetConfiguration(_shellSettings.Name);
|
||||
|
||||
if ( config == null ) {
|
||||
config = _dataServicesProviderFactory
|
||||
var config = _sessionConfigurationCache.GetConfiguration(() =>
|
||||
_dataServicesProviderFactory
|
||||
.CreateProvider(parameters)
|
||||
.BuildConfiguration(parameters);
|
||||
|
||||
_sessionConfigurationCache.StoreConfiguration(_shellSettings.Name, config);
|
||||
}
|
||||
.BuildConfiguration(parameters));
|
||||
|
||||
return config;
|
||||
}
|
||||
|
@@ -53,7 +53,6 @@ namespace Orchard.Environment {
|
||||
builder.RegisterType<DefaultOrchardHost>().As<IOrchardHost>().As<IEventHandler>().SingleInstance();
|
||||
{
|
||||
builder.RegisterType<ShellSettingsManager>().As<IShellSettingsManager>().SingleInstance();
|
||||
builder.RegisterType<SessionConfigurationCache>().As<ISessionConfigurationCache>().SingleInstance();
|
||||
|
||||
builder.RegisterType<ShellContextFactory>().As<IShellContextFactory>().SingleInstance();
|
||||
{
|
||||
|
@@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Autofac;
|
||||
using Orchard.Data;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Environment.Descriptor;
|
||||
using Orchard.Environment.Descriptor.Models;
|
||||
@@ -36,17 +34,14 @@ namespace Orchard.Environment.ShellBuilders {
|
||||
private readonly IShellDescriptorCache _shellDescriptorCache;
|
||||
private readonly ICompositionStrategy _compositionStrategy;
|
||||
private readonly IShellContainerFactory _shellContainerFactory;
|
||||
private readonly ISessionConfigurationCache _sessionConfigurationCache;
|
||||
|
||||
public ShellContextFactory(
|
||||
IShellDescriptorCache shellDescriptorCache,
|
||||
ICompositionStrategy compositionStrategy,
|
||||
IShellContainerFactory shellContainerFactory,
|
||||
ISessionConfigurationCache sessionConfigurationCache) {
|
||||
IShellContainerFactory shellContainerFactory) {
|
||||
_shellDescriptorCache = shellDescriptorCache;
|
||||
_compositionStrategy = compositionStrategy;
|
||||
_shellContainerFactory = shellContainerFactory;
|
||||
_sessionConfigurationCache = sessionConfigurationCache;
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
@@ -74,7 +69,6 @@ namespace Orchard.Environment.ShellBuilders {
|
||||
if (currentDescriptor != null && knownDescriptor.SerialNumber != currentDescriptor.SerialNumber) {
|
||||
Logger.Information("Newer descriptor obtained. Rebuilding shell container.");
|
||||
|
||||
_sessionConfigurationCache.DeleteConfiguration(settings.Name);
|
||||
_shellDescriptorCache.Store(settings.Name, currentDescriptor);
|
||||
blueprint = _compositionStrategy.Compose(settings, currentDescriptor);
|
||||
shellScope = _shellContainerFactory.CreateContainer(settings, blueprint);
|
||||
|
@@ -13,13 +13,11 @@ namespace Orchard.FileSystems.Dependencies {
|
||||
private const string FileName = "dependencies.xml";
|
||||
private readonly ICacheManager _cacheManager;
|
||||
private readonly IAppDataFolder _appDataFolder;
|
||||
private readonly ISessionConfigurationCache _sessionConfigurationCache;
|
||||
private readonly InvalidationToken _writeThroughToken;
|
||||
|
||||
public DefaultDependenciesFolder(ICacheManager cacheManager, IAppDataFolder appDataFolder, ISessionConfigurationCache sessionConfigurationCache) {
|
||||
public DefaultDependenciesFolder(ICacheManager cacheManager, IAppDataFolder appDataFolder) {
|
||||
_cacheManager = cacheManager;
|
||||
_appDataFolder = appDataFolder;
|
||||
_sessionConfigurationCache = sessionConfigurationCache;
|
||||
_writeThroughToken = new InvalidationToken();
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
@@ -52,8 +50,8 @@ namespace Orchard.FileSystems.Dependencies {
|
||||
public void StoreDescriptors(IEnumerable<DependencyDescriptor> dependencyDescriptors) {
|
||||
var existingDescriptors = LoadDescriptors().OrderBy(d => d.Name);
|
||||
var newDescriptors = dependencyDescriptors.OrderBy(d => d.Name);
|
||||
|
||||
if (!newDescriptors.SequenceEqual(existingDescriptors, new DependencyDescriptorComparer())) {
|
||||
_sessionConfigurationCache.DeleteAll();
|
||||
WriteDependencies(PersistencePath, dependencyDescriptors);
|
||||
}
|
||||
}
|
||||
|
@@ -360,6 +360,7 @@
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ContentManagement\DataMigrations\FrameworkDataMigration.cs" />
|
||||
<Compile Include="Utility\Hash.cs" />
|
||||
<Compile Include="Data\ISessionConfigurationCache.cs" />
|
||||
<Compile Include="Data\Migration\Generator\ISchemaCommandGenerator.cs" />
|
||||
<Compile Include="Data\Migration\Interpreters\AbstractDataMigrationInterpreter.cs" />
|
||||
|
23
src/Orchard/Utility/Hash.cs
Normal file
23
src/Orchard/Utility/Hash.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace Orchard.Utility {
|
||||
/// <summary>
|
||||
/// Compute an (almost) unique hash value from various sources.
|
||||
/// This allows computing hash keys that are easily storable
|
||||
/// and comparable from heterogenous components.
|
||||
/// </summary>
|
||||
public class Hash {
|
||||
private long _hash;
|
||||
|
||||
public string Value { get { return _hash.ToString(); } }
|
||||
|
||||
public void AddString(string value) {
|
||||
_hash += value.GetHashCode();
|
||||
}
|
||||
|
||||
public void AddTypeReference(Type type) {
|
||||
AddString(type.AssemblyQualifiedName);
|
||||
AddString(type.FullName);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user