From eecb61a132e631270d67336066b41390e8b23d5b Mon Sep 17 00:00:00 2001 From: Carl Woodhouse Date: Tue, 20 Oct 2015 12:35:34 +0100 Subject: [PATCH] Redis extensions use of keys #5958 --- .../Caching/RedisCacheStorageProvider.cs | 2 +- .../Extensions/RedisConnectionExtensions.cs | 40 ++++++++++++++++++ .../Extensions/RedisDatabaseExtensions.cs | 41 ------------------- .../Orchard.Redis/Orchard.Redis.csproj | 2 +- .../RedisOutputCacheStorageProvider.cs | 26 ++++++------ 5 files changed, 55 insertions(+), 56 deletions(-) create mode 100644 src/Orchard.Web/Modules/Orchard.Redis/Extensions/RedisConnectionExtensions.cs delete mode 100644 src/Orchard.Web/Modules/Orchard.Redis/Extensions/RedisDatabaseExtensions.cs diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Caching/RedisCacheStorageProvider.cs b/src/Orchard.Web/Modules/Orchard.Redis/Caching/RedisCacheStorageProvider.cs index 87a83c423..1af97e04d 100644 --- a/src/Orchard.Web/Modules/Orchard.Redis/Caching/RedisCacheStorageProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.Redis/Caching/RedisCacheStorageProvider.cs @@ -58,7 +58,7 @@ namespace Orchard.Redis.Caching { } public void Clear() { - Database.KeyDeleteWithPrefix(GetLocalizedKey("*")); + _connectionMultiplexer.KeyDeleteWithPrefix(GetLocalizedKey("*")); } private string GetLocalizedKey(string key) { diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Extensions/RedisConnectionExtensions.cs b/src/Orchard.Web/Modules/Orchard.Redis/Extensions/RedisConnectionExtensions.cs new file mode 100644 index 000000000..cb210aa9f --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Redis/Extensions/RedisConnectionExtensions.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using StackExchange.Redis; + +namespace Orchard.Redis.Extensions { + public static class RedisConnectionExtensions { + public static void KeyDeleteWithPrefix(this IConnectionMultiplexer connection, string prefix) { + var keys = GetKeys(connection, prefix); + var database = connection.GetDatabase(); + database.KeyDelete(keys.Select(key => (RedisKey)key).ToArray()); + } + + public static int KeyCount(this IConnectionMultiplexer connection, string prefix) { + return GetKeys(connection, prefix).Count(); + } + + // CYCLES EACH ENDPOINT FOR A CONNECTION SO KEYS ARE FETECHED IN A REDIS CLUSTER CONFIGURATION + // STACKEXCHANGECLIENT .KEYS WILL PERFORM SCAN ON REDIS SERVERS THAT SUPPORT IT + public static IEnumerable GetKeys(this IConnectionMultiplexer connection, string prefix) { + if (connection == null) { + throw new ArgumentException("Connection cannot be null", "connection"); + } + + if (string.IsNullOrWhiteSpace(prefix)) { + throw new ArgumentException("Prefix cannot be empty", "database"); + } + + var keys = new List(); + var databaseId = connection.GetDatabase().Database; + + foreach (var endPoint in connection.GetEndPoints()) { + var server = connection.GetServer(endPoint); + keys.AddRange(server.Keys(pattern: prefix, database: databaseId).Select(x => x.ToString())); + } + + return keys.Distinct(); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Extensions/RedisDatabaseExtensions.cs b/src/Orchard.Web/Modules/Orchard.Redis/Extensions/RedisDatabaseExtensions.cs deleted file mode 100644 index 2b223a064..000000000 --- a/src/Orchard.Web/Modules/Orchard.Redis/Extensions/RedisDatabaseExtensions.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using StackExchange.Redis; - -namespace Orchard.Redis.Extensions { - public static class RedisDatabaseExtensions { - - public static void KeyDeleteWithPrefix(this IDatabase database, string prefix) { - if (database == null) { - throw new ArgumentException("Database cannot be null", "database"); - } - - if (string.IsNullOrWhiteSpace(prefix)) { - throw new ArgumentException("Prefix cannot be empty", "database"); - } - - database.ScriptEvaluate(@" - local keys = redis.call('keys', ARGV[1]) - for i=1,#keys,5000 do - redis.call('del', unpack(keys, i, math.min(i+4999, #keys))) - end", values: new RedisValue[] { prefix }); - } - - public static int KeyCount(this IDatabase database, string prefix) { - if (database == null) { - throw new ArgumentException("Database cannot be null", "database"); - } - - if (string.IsNullOrWhiteSpace(prefix)) { - throw new ArgumentException("Prefix cannot be empty", "database"); - } - - var retVal = database.ScriptEvaluate("return table.getn(redis.call('keys', ARGV[1]))", values: new RedisValue[] { prefix }); - - if (retVal.IsNull) { - return 0; - } - - return (int)retVal; - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Redis/Orchard.Redis.csproj b/src/Orchard.Web/Modules/Orchard.Redis/Orchard.Redis.csproj index 1d3322824..d970f19f7 100644 --- a/src/Orchard.Web/Modules/Orchard.Redis/Orchard.Redis.csproj +++ b/src/Orchard.Web/Modules/Orchard.Redis/Orchard.Redis.csproj @@ -107,7 +107,7 @@ - + diff --git a/src/Orchard.Web/Modules/Orchard.Redis/OutputCache/RedisOutputCacheStorageProvider.cs b/src/Orchard.Web/Modules/Orchard.Redis/OutputCache/RedisOutputCacheStorageProvider.cs index 8b1edbc3d..63a89f8e4 100644 --- a/src/Orchard.Web/Modules/Orchard.Redis/OutputCache/RedisOutputCacheStorageProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.Redis/OutputCache/RedisOutputCacheStorageProvider.cs @@ -54,7 +54,7 @@ namespace Orchard.Redis.OutputCache { } public void Set(string key, CacheItem cacheItem) { - if(cacheItem == null) { + if (cacheItem == null) { throw new ArgumentNullException("cacheItem"); } @@ -74,7 +74,7 @@ namespace Orchard.Redis.OutputCache { } public void RemoveAll() { - Database.KeyDeleteWithPrefix(GetLocalizedKey("*")); + Database.KeyDelete(GetPrefixedKeys().Select(key => (RedisKey)key).ToArray()); } public CacheItem GetCacheItem(string key) { @@ -85,11 +85,11 @@ namespace Orchard.Redis.OutputCache { } using (var compressedStream = new MemoryStream(value)) { - if(compressedStream.Length == 0) { + if (compressedStream.Length == 0) { return null; } - using(var decompressedStream = Decompress(compressedStream)) { + using (var decompressedStream = Decompress(compressedStream)) { return Deserialize(decompressedStream); } } @@ -106,7 +106,7 @@ namespace Orchard.Redis.OutputCache { } public int GetCacheItemsCount() { - return Database.KeyCount(GetLocalizedKey("*")); + return GetPrefixedKeys().Count(); } /// @@ -123,19 +123,19 @@ namespace Orchard.Redis.OutputCache { /// /// The keys for the current tenant. private IEnumerable GetAllKeys() { + var prefix = GetLocalizedKey(""); + return GetPrefixedKeys().Select(x => x.Substring(prefix.Length)); + } + + private IEnumerable GetPrefixedKeys() { // prevent the same request from computing the list twice (count + list) if (_keysCache == null) { _keysCache = new HashSet(); - var prefix = GetLocalizedKey(""); - - 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)); - } + var keys = _connectionMultiplexer.GetKeys(GetLocalizedKey("*")); + foreach (var key in keys) { + _keysCache.Add(key); } } - return _keysCache; }