Improved the Azure database cache provider.

This commit is contained in:
Daniel Stolt
2013-08-28 04:14:47 +02:00
committed by Sebastien Ros
parent 8020447191
commit a690b9cc66
2 changed files with 56 additions and 37 deletions

View File

@@ -9,12 +9,13 @@ namespace Orchard.Azure.Services.Caching.Database {
public class AzureCacheClient : ICache { public class AzureCacheClient : ICache {
public AzureCacheClient(string cacheHostIdentifier, string cacheName, string region) { public AzureCacheClient(string cacheHostIdentifier, string cacheName, string region, bool enableCompression, TimeSpan? expirationTime) {
var dataCacheFactoryConfiguration = new DataCacheFactoryConfiguration() { var dataCacheFactoryConfiguration = new DataCacheFactoryConfiguration() {
AutoDiscoverProperty = new DataCacheAutoDiscoverProperty(true, cacheHostIdentifier), AutoDiscoverProperty = new DataCacheAutoDiscoverProperty(true, cacheHostIdentifier),
MaxConnectionsToServer = 32, MaxConnectionsToServer = 32,
UseLegacyProtocol = false UseLegacyProtocol = false,
IsCompressionEnabled = enableCompression
}; };
var dataCacheFactory = new DataCacheFactory(dataCacheFactoryConfiguration); var dataCacheFactory = new DataCacheFactory(dataCacheFactoryConfiguration);
@@ -29,6 +30,8 @@ namespace Orchard.Azure.Services.Caching.Database {
// region strings yielding the same transformed region string. // region strings yielding the same transformed region string.
_regionAlphaNumeric = new String(Array.FindAll(_region.ToCharArray(), c => Char.IsLetterOrDigit(c))) + _region.GetHashCode().ToString(); _regionAlphaNumeric = new String(Array.FindAll(_region.ToCharArray(), c => Char.IsLetterOrDigit(c))) + _region.GetHashCode().ToString();
_expirationTime = expirationTime;
if (_logger.IsDebugEnabled) if (_logger.IsDebugEnabled)
_logger.DebugFormat("Creating cache with CacheName='{0}' and Region='{1}' (original Region='{2}').", cacheName, _regionAlphaNumeric, _region); _logger.DebugFormat("Creating cache with CacheName='{0}' and Region='{1}' (original Region='{2}').", cacheName, _regionAlphaNumeric, _region);
@@ -39,17 +42,18 @@ namespace Orchard.Azure.Services.Caching.Database {
_cache.CreateRegion(_regionAlphaNumeric); _cache.CreateRegion(_regionAlphaNumeric);
_lockHandleDictionary = new ConcurrentDictionary<object, DataCacheLockHandle>(); //_lockHandleDictionary = new ConcurrentDictionary<object, DataCacheLockHandle>();
_lockTimeout = TimeSpan.FromSeconds(30); //_lockTimeout = TimeSpan.FromSeconds(30);
} }
private const string _defaultRegion = "NHibernate"; private const string _defaultRegion = "NHibernate";
private readonly IInternalLogger _logger; private readonly IInternalLogger _logger;
private readonly string _region; private readonly string _region;
private readonly string _regionAlphaNumeric; private readonly string _regionAlphaNumeric;
private readonly TimeSpan? _expirationTime;
private readonly DataCache _cache; private readonly DataCache _cache;
private readonly ConcurrentDictionary<object, DataCacheLockHandle> _lockHandleDictionary; //private readonly ConcurrentDictionary<object, DataCacheLockHandle> _lockHandleDictionary;
private readonly TimeSpan _lockTimeout; //private readonly TimeSpan _lockTimeout;
#region ICache Members #region ICache Members
@@ -72,7 +76,10 @@ namespace Orchard.Azure.Services.Caching.Database {
if (_logger.IsDebugEnabled) if (_logger.IsDebugEnabled)
_logger.DebugFormat("Put() invoked with key='{0}' and value='{1}' in region '{2}'.", key, value, _regionAlphaNumeric); _logger.DebugFormat("Put() invoked with key='{0}' and value='{1}' in region '{2}'.", key, value, _regionAlphaNumeric);
_cache.Put(key.ToString(), value, _regionAlphaNumeric); if (_expirationTime.HasValue)
_cache.Put(key.ToString(), value, _expirationTime.Value, _regionAlphaNumeric);
else
_cache.Put(key.ToString(), value, _regionAlphaNumeric);
} }
public void Remove(object key) { public void Remove(object key) {
@@ -112,44 +119,44 @@ namespace Orchard.Azure.Services.Caching.Database {
// TODO: Try to understand how it's used, and make locking more robust. // TODO: Try to understand how it's used, and make locking more robust.
public void Lock(object key) { public void Lock(object key) {
if (key == null) //if (key == null)
throw new ArgumentNullException("key", "The parameter 'key' must not be null."); // throw new ArgumentNullException("key", "The parameter 'key' must not be null.");
if (_logger.IsDebugEnabled) //if (_logger.IsDebugEnabled)
_logger.DebugFormat("Lock() invoked with key='{0}' in region '{1}'.", key, _regionAlphaNumeric); // _logger.DebugFormat("Lock() invoked with key='{0}' in region '{1}'.", key, _regionAlphaNumeric);
try { //try {
DataCacheLockHandle lockHandle = null; // DataCacheLockHandle lockHandle = null;
_cache.GetAndLock(key.ToString(), _lockTimeout, out lockHandle, _regionAlphaNumeric); // _cache.GetAndLock(key.ToString(), _lockTimeout, out lockHandle, _regionAlphaNumeric);
_lockHandleDictionary.TryAdd(key, lockHandle); // _lockHandleDictionary.TryAdd(key, lockHandle);
} //}
catch (Exception ex) { //catch (Exception ex) {
if (_logger.IsErrorEnabled) // if (_logger.IsErrorEnabled)
_logger.Error("Exception thrown while trying to lock object in cache.", ex); // _logger.Error("Exception thrown while trying to lock object in cache.", ex);
throw; // throw;
} //}
} }
// TODO: Try to understand how it's used, and make locking more robust. // TODO: Try to understand how it's used, and make locking more robust.
public void Unlock(object key) { public void Unlock(object key) {
if (key == null) //if (key == null)
throw new ArgumentNullException("key", "The parameter 'key' must not be null."); // throw new ArgumentNullException("key", "The parameter 'key' must not be null.");
if (_logger.IsDebugEnabled) //if (_logger.IsDebugEnabled)
_logger.DebugFormat("Unlock() invoked with key='{0}' in region '{1}'.", key, _regionAlphaNumeric); // _logger.DebugFormat("Unlock() invoked with key='{0}' in region '{1}'.", key, _regionAlphaNumeric);
try { //try {
DataCacheLockHandle lockHandle = null; // DataCacheLockHandle lockHandle = null;
if (_lockHandleDictionary.TryRemove(key, out lockHandle)) // if (_lockHandleDictionary.TryRemove(key, out lockHandle))
_cache.Unlock(key.ToString(), lockHandle, _regionAlphaNumeric); // _cache.Unlock(key.ToString(), lockHandle, _regionAlphaNumeric);
} //}
catch (Exception ex) { //catch (Exception ex) {
if (_logger.IsErrorEnabled) // if (_logger.IsErrorEnabled)
_logger.Error("Exception thrown while trying to unlock object in cache.", ex); // _logger.Error("Exception thrown while trying to unlock object in cache.", ex);
throw; // throw;
} //}
} }
// TODO: Try to understand what this is for and how it's used. // TODO: Try to understand what this is for and how it's used.
@@ -163,7 +170,8 @@ namespace Orchard.Azure.Services.Caching.Database {
// TODO: Try to understand what this is for and how it's used. // TODO: Try to understand what this is for and how it's used.
public int Timeout { public int Timeout {
get { get {
return Timestamper.OneMs * (int)_lockTimeout.TotalMilliseconds; //return Timestamper.OneMs * (int)_lockTimeout.TotalMilliseconds;
return Timestamper.OneMs * 60000;
} }
} }

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.WindowsAzure.ServiceRuntime; using Microsoft.WindowsAzure.ServiceRuntime;
using NHibernate.Cache; using NHibernate.Cache;
using System;
namespace Orchard.Azure.Services.Caching.Database { namespace Orchard.Azure.Services.Caching.Database {
@@ -9,7 +10,17 @@ namespace Orchard.Azure.Services.Caching.Database {
#region ICacheProvider Members #region ICacheProvider Members
public ICache BuildCache(string regionName, IDictionary<string, string> properties) { public ICache BuildCache(string regionName, IDictionary<string, string> properties) {
return new AzureCacheClient(AzureCacheConfiguration.CacheHostIdentifier, AzureCacheConfiguration.CacheName, regionName); bool enableCompression = false;
string enableCompressionString;
if (properties.TryGetValue("compression_enabled", out enableCompressionString))
enableCompression = Boolean.Parse(enableCompressionString);
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);
} }
public long NextTimestamp() { public long NextTimestamp() {