mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-04-05 21:01:35 +08:00
Added support for Windows Azure Shared Cache to Orchard.Azure.DatabaseCache.
This commit is contained in:
parent
a690b9cc66
commit
375738df93
@ -9,49 +9,36 @@ namespace Orchard.Azure.Services.Caching.Database {
|
||||
|
||||
public class AzureCacheClient : ICache {
|
||||
|
||||
public AzureCacheClient(string cacheHostIdentifier, string cacheName, string region, bool enableCompression, TimeSpan? expirationTime) {
|
||||
|
||||
var dataCacheFactoryConfiguration = new DataCacheFactoryConfiguration() {
|
||||
AutoDiscoverProperty = new DataCacheAutoDiscoverProperty(true, cacheHostIdentifier),
|
||||
MaxConnectionsToServer = 32,
|
||||
UseLegacyProtocol = false,
|
||||
IsCompressionEnabled = enableCompression
|
||||
};
|
||||
|
||||
var dataCacheFactory = new DataCacheFactory(dataCacheFactoryConfiguration);
|
||||
|
||||
public AzureCacheClient(DataCache cache, bool isSharedCaching, string region, TimeSpan? expirationTime) {
|
||||
_logger = LoggerProvider.LoggerFor(typeof(AzureCacheClient));
|
||||
_cache = cache;
|
||||
_isSharedCaching = isSharedCaching;
|
||||
_region = region ?? _defaultRegion;
|
||||
|
||||
// Azure Cache supports only alphanumeric strings for regions and
|
||||
// Orchard can get a lot more creative than that. Remove all non
|
||||
// alphanumering characters from the region, and append the hash code
|
||||
// of the original string to mitigate the risk of two distinct original
|
||||
// region strings yielding the same transformed region string.
|
||||
_regionAlphaNumeric = new String(Array.FindAll(_region.ToCharArray(), c => Char.IsLetterOrDigit(c))) + _region.GetHashCode().ToString();
|
||||
|
||||
_expirationTime = expirationTime;
|
||||
|
||||
if (_logger.IsDebugEnabled)
|
||||
_logger.DebugFormat("Creating cache with CacheName='{0}' and Region='{1}' (original Region='{2}').", cacheName, _regionAlphaNumeric, _region);
|
||||
|
||||
if (!String.IsNullOrEmpty(cacheName))
|
||||
_cache = dataCacheFactory.GetCache(cacheName);
|
||||
else
|
||||
_cache = dataCacheFactory.GetDefaultCache();
|
||||
|
||||
_cache.CreateRegion(_regionAlphaNumeric);
|
||||
|
||||
if (!isSharedCaching)
|
||||
_cache.CreateRegion(_regionAlphaNumeric);
|
||||
|
||||
//_lockHandleDictionary = new ConcurrentDictionary<object, DataCacheLockHandle>();
|
||||
//_lockTimeout = TimeSpan.FromSeconds(30);
|
||||
|
||||
if (_logger.IsDebugEnabled)
|
||||
_logger.DebugFormat("Created an AzureCacheClient for region '{0}' (original region '{1}').", _regionAlphaNumeric, _region);
|
||||
}
|
||||
|
||||
private const string _defaultRegion = "NHibernate";
|
||||
private readonly IInternalLogger _logger;
|
||||
private readonly DataCache _cache;
|
||||
private readonly bool _isSharedCaching;
|
||||
private readonly string _region;
|
||||
private readonly string _regionAlphaNumeric;
|
||||
private readonly TimeSpan? _expirationTime;
|
||||
private readonly DataCache _cache;
|
||||
//private readonly ConcurrentDictionary<object, DataCacheLockHandle> _lockHandleDictionary;
|
||||
//private readonly TimeSpan _lockTimeout;
|
||||
|
||||
@ -64,6 +51,9 @@ namespace Orchard.Azure.Services.Caching.Database {
|
||||
if (_logger.IsDebugEnabled)
|
||||
_logger.DebugFormat("Get() invoked with key='{0}' in region '{1}'.", key, _regionAlphaNumeric);
|
||||
|
||||
if (_isSharedCaching)
|
||||
return _cache.Get(GetSharedCachingKey(key));
|
||||
|
||||
return _cache.Get(key.ToString(), _regionAlphaNumeric);
|
||||
}
|
||||
|
||||
@ -76,7 +66,9 @@ namespace Orchard.Azure.Services.Caching.Database {
|
||||
if (_logger.IsDebugEnabled)
|
||||
_logger.DebugFormat("Put() invoked with key='{0}' and value='{1}' in region '{2}'.", key, value, _regionAlphaNumeric);
|
||||
|
||||
if (_expirationTime.HasValue)
|
||||
if (_isSharedCaching)
|
||||
_cache.Put(GetSharedCachingKey(key), value);
|
||||
else if (_expirationTime.HasValue)
|
||||
_cache.Put(key.ToString(), value, _expirationTime.Value, _regionAlphaNumeric);
|
||||
else
|
||||
_cache.Put(key.ToString(), value, _regionAlphaNumeric);
|
||||
@ -89,12 +81,18 @@ namespace Orchard.Azure.Services.Caching.Database {
|
||||
if (_logger.IsDebugEnabled)
|
||||
_logger.DebugFormat("Remove() invoked with key='{0}' in region '{1}'.", key, _regionAlphaNumeric);
|
||||
|
||||
if (_isSharedCaching)
|
||||
_cache.Remove(key.ToString());
|
||||
|
||||
_cache.Remove(key.ToString(), _regionAlphaNumeric);
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
if (_logger.IsDebugEnabled)
|
||||
_logger.DebugFormat("Clear() invoked in region '{0}'.", _regionAlphaNumeric);
|
||||
|
||||
if (_isSharedCaching)
|
||||
return; // Can't remove an individual region with Shared Caching.
|
||||
|
||||
_cache.ClearRegion(_regionAlphaNumeric);
|
||||
}
|
||||
@ -184,5 +182,9 @@ namespace Orchard.Azure.Services.Caching.Database {
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private string GetSharedCachingKey(object key) {
|
||||
return String.Format("{0}_{1}", _region, key);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
using NHibernate.Cfg.Loquacious;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NHibernate.Cfg.Loquacious;
|
||||
using Orchard;
|
||||
using Orchard.Data;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.Logging;
|
||||
using System.Linq;
|
||||
|
||||
namespace Orchard.Azure.Services.Caching.Database {
|
||||
|
||||
@ -14,6 +15,7 @@ namespace Orchard.Azure.Services.Caching.Database {
|
||||
|
||||
public static string CacheHostIdentifier;
|
||||
public static string CacheName;
|
||||
public static bool IsSharedCaching;
|
||||
|
||||
public AzureCacheConfiguration(IShellSettingsManager shellSettingsManager, ShellSettings shellSettings)
|
||||
: base() {
|
||||
@ -40,6 +42,7 @@ namespace Orchard.Azure.Services.Caching.Database {
|
||||
|
||||
CacheHostIdentifier = shellSettings[Constants.DatabaseCacheHostIdentifierSettingName];
|
||||
CacheName = shellSettings[Constants.DatabaseCacheCacheNameSettingName];
|
||||
IsSharedCaching = Boolean.Parse(shellSettings[Constants.DatabaseCacheIsSharedCachingSettingName]);
|
||||
|
||||
_shellSettings = shellSettings;
|
||||
}
|
||||
|
@ -2,11 +2,54 @@ using System.Collections.Generic;
|
||||
using Microsoft.WindowsAzure.ServiceRuntime;
|
||||
using NHibernate.Cache;
|
||||
using System;
|
||||
using Microsoft.ApplicationServer.Caching;
|
||||
using NHibernate;
|
||||
|
||||
namespace Orchard.Azure.Services.Caching.Database {
|
||||
|
||||
public class AzureCacheProvider : ICacheProvider {
|
||||
|
||||
#region DataCache repository
|
||||
|
||||
private static IDictionary<string, DataCache> _cacheDictionary = new Dictionary<string, DataCache>();
|
||||
|
||||
private static DataCache GetCache(IInternalLogger logger, string cacheHostIdentifier, string cacheName, bool enableCompression) {
|
||||
string key = String.Format("{0}_{1}_{2}", cacheHostIdentifier, cacheName, enableCompression);
|
||||
if (!_cacheDictionary.ContainsKey(key)) {
|
||||
var dataCacheFactoryConfiguration = new DataCacheFactoryConfiguration() {
|
||||
AutoDiscoverProperty = new DataCacheAutoDiscoverProperty(true, AzureCacheConfiguration.CacheHostIdentifier),
|
||||
MaxConnectionsToServer = 32,
|
||||
UseLegacyProtocol = false
|
||||
};
|
||||
|
||||
var dataCacheFactory = new DataCacheFactory(dataCacheFactoryConfiguration);
|
||||
|
||||
if (logger.IsDebugEnabled)
|
||||
logger.DebugFormat("Creating DataCache with CacheHostIdentifier='{0}' and CacheName='{1}'.", cacheHostIdentifier, cacheName);
|
||||
|
||||
DataCache newCache;
|
||||
if (!String.IsNullOrEmpty(cacheName))
|
||||
newCache = dataCacheFactory.GetCache(cacheName);
|
||||
else
|
||||
newCache = dataCacheFactory.GetDefaultCache();
|
||||
_cacheDictionary[key] = newCache;
|
||||
}
|
||||
else {
|
||||
if (logger.IsDebugEnabled)
|
||||
logger.DebugFormat("Reusing existing DataCache with CacheHostIdentifier='{0}' and CacheName='{1}'.", cacheHostIdentifier, cacheName);
|
||||
}
|
||||
|
||||
return _cacheDictionary[key];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public AzureCacheProvider() {
|
||||
_logger = LoggerProvider.LoggerFor(typeof(AzureCacheProvider));
|
||||
}
|
||||
|
||||
private readonly IInternalLogger _logger;
|
||||
|
||||
#region ICacheProvider Members
|
||||
|
||||
public ICache BuildCache(string regionName, IDictionary<string, string> properties) {
|
||||
@ -15,12 +58,17 @@ namespace Orchard.Azure.Services.Caching.Database {
|
||||
if (properties.TryGetValue("compression_enabled", out enableCompressionString))
|
||||
enableCompression = Boolean.Parse(enableCompressionString);
|
||||
|
||||
// Using static fields to communicate host identifier and cache name from AzureCacheConfiguration to
|
||||
// this class might cause problems in multi-tenancy scenarios when tenants have different settings
|
||||
// for these in shell settings. We should think of something more robust.
|
||||
var cache = GetCache(_logger, AzureCacheConfiguration.CacheHostIdentifier, AzureCacheConfiguration.CacheName, enableCompression);
|
||||
|
||||
TimeSpan? expiration = null;
|
||||
string expirationString;
|
||||
if (properties.TryGetValue("expiration", out expirationString) || properties.TryGetValue(global::NHibernate.Cfg.Environment.CacheDefaultExpiration, out expirationString))
|
||||
expiration = TimeSpan.FromSeconds(Int32.Parse(expirationString));
|
||||
|
||||
return new AzureCacheClient(AzureCacheConfiguration.CacheHostIdentifier, AzureCacheConfiguration.CacheName, regionName, enableCompression, expiration);
|
||||
|
||||
return new AzureCacheClient(cache, AzureCacheConfiguration.IsSharedCaching, regionName, expiration);
|
||||
}
|
||||
|
||||
public long NextTimestamp() {
|
||||
|
Loading…
Reference in New Issue
Block a user