mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-11-24 16:53:10 +08:00
Fixing Redis connection creation
With the previous code, when multiple threads tried to create a Redis connection, the ConcurrentDictionary would have called the factory delegate multiple times and added only one of the resulting connections. This is by design, and a solution is to use a Lazy object to defer the creation of the connection. Multiple Lazy objects will be created but it doesn't have any impact.
This commit is contained in:
@@ -8,7 +8,7 @@ using StackExchange.Redis;
|
||||
namespace Orchard.Redis.Configuration {
|
||||
|
||||
public class RedisConnectionProvider : IRedisConnectionProvider {
|
||||
private static ConcurrentDictionary<string, ConnectionMultiplexer> _connectionMultiplexers = new ConcurrentDictionary<string, ConnectionMultiplexer>();
|
||||
private static ConcurrentDictionary<string, Lazy<ConnectionMultiplexer>> _connectionMultiplexers = new ConcurrentDictionary<string, Lazy<ConnectionMultiplexer>>();
|
||||
private readonly ShellSettings _shellSettings;
|
||||
|
||||
public RedisConnectionProvider(ShellSettings shellSettings) {
|
||||
@@ -37,12 +37,16 @@ namespace Orchard.Redis.Configuration {
|
||||
throw new ArgumentNullException("connectionString");
|
||||
}
|
||||
|
||||
var connectionMultiplexer = _connectionMultiplexers.GetOrAdd(connectionString, cfg => {
|
||||
Logger.Debug("Creating a new cache client for: {0}", connectionString);
|
||||
return ConnectionMultiplexer.Connect(connectionString);
|
||||
});
|
||||
// when using ConcurrentDictionary, multiple threads can create the value
|
||||
// at the same time, so we need to pass a Lazy so that it's only
|
||||
// the object which is added that will create a ConnectionMultiplexer,
|
||||
// even when a delegate is passed
|
||||
|
||||
return connectionMultiplexer;
|
||||
return _connectionMultiplexers.GetOrAdd(connectionString,
|
||||
new Lazy<ConnectionMultiplexer>(() => {
|
||||
Logger.Debug("Creating a new cache client for: {0}", connectionString);
|
||||
return ConnectionMultiplexer.Connect(connectionString);
|
||||
})).Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace Orchard.Redis.OutputCache {
|
||||
|
||||
[OrchardFeature("Orchard.Redis.OutputCache")]
|
||||
[OrchardSuppressDependency("Orchard.OutputCache.Services.DefaultCacheStorageProvider")]
|
||||
public class RedisOutputCacheStorageProvider : Component, IOutputCacheStorageProvider {
|
||||
public class RedisOutputCacheStorageProvider : IOutputCacheStorageProvider {
|
||||
|
||||
private readonly ShellSettings _shellSettings;
|
||||
private readonly IRedisConnectionProvider _redisConnectionProvider;
|
||||
@@ -23,18 +23,22 @@ namespace Orchard.Redis.OutputCache {
|
||||
|
||||
public const string ConnectionStringKey = "Orchard.Redis.OutputCache";
|
||||
private readonly string _connectionString;
|
||||
private readonly ConnectionMultiplexer _connectionMultiplexer;
|
||||
|
||||
public RedisOutputCacheStorageProvider(ShellSettings shellSettings, IRedisConnectionProvider redisConnectionProvider) {
|
||||
_shellSettings = shellSettings;
|
||||
_redisConnectionProvider = redisConnectionProvider;
|
||||
_connectionString = _redisConnectionProvider.GetConnectionString(ConnectionStringKey);
|
||||
_connectionMultiplexer = _redisConnectionProvider.GetConnection(_connectionString);
|
||||
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public IDatabase Database {
|
||||
get {
|
||||
return _redisConnectionProvider.GetConnection(_connectionString).GetDatabase();
|
||||
return _connectionMultiplexer.GetDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,9 +101,8 @@ namespace Orchard.Redis.OutputCache {
|
||||
_keysCache = new HashSet<string>();
|
||||
var prefix = GetLocalizedKey("");
|
||||
|
||||
var connection = _redisConnectionProvider.GetConnection(_connectionString);
|
||||
foreach (var endPoint in connection.GetEndPoints()) {
|
||||
var server = connection.GetServer(endPoint);
|
||||
foreach (var endPoint in _connectionMultiplexer.GetEndPoints()) {
|
||||
var server = _connectionMultiplexer.GetServer(endPoint);
|
||||
foreach (var key in server.Keys(pattern: GetLocalizedKey("*"))) {
|
||||
_keysCache.Add(key.ToString().Substring(prefix.Length));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user