From 1969ba1b411d435ddd73d849739ee963188285da Mon Sep 17 00:00:00 2001 From: catcherwong Date: Wed, 31 Jan 2018 20:11:59 +0800 Subject: [PATCH] :construction: SQLite and Redis Caching provider impl RemoveByPrefix method. --- .../Controllers/ValuesController.cs | 10 +- src/EasyCaching.Core/IEasyCachingProvider.cs | 12 ++ .../IHybridCachingProvider.cs | 7 ++ .../HybridCacheServiceCollectionExtensions.cs | 1 + .../HybridCachingProvider.cs | 15 ++- .../InMemoryCachingProvider.cs | 10 ++ .../DefaultMemcachedCachingProvider.cs | 10 ++ .../DefaultRedisCachingProvider.cs | 114 +++++++++++++++++- src/EasyCaching.SQLite/ConstSQL.cs | 5 + .../SQLiteCachingProvider.cs | 22 ++++ 10 files changed, 195 insertions(+), 11 deletions(-) create mode 100644 src/EasyCaching.Core/IHybridCachingProvider.cs diff --git a/sample/EasyCaching.Demo.HybridCache/Controllers/ValuesController.cs b/sample/EasyCaching.Demo.HybridCache/Controllers/ValuesController.cs index 0c284855..3360c753 100644 --- a/sample/EasyCaching.Demo.HybridCache/Controllers/ValuesController.cs +++ b/sample/EasyCaching.Demo.HybridCache/Controllers/ValuesController.cs @@ -1,10 +1,10 @@ namespace EasyCaching.Demo.HybridCache.Controllers -{ - using EasyCaching.HybridCache; +{ + using EasyCaching.Core; using Microsoft.AspNetCore.Mvc; - using System; - using System.Threading.Tasks; - + using System; + using System.Threading.Tasks; + [Route("api/[controller]")] public class ValuesController : Controller { diff --git a/src/EasyCaching.Core/IEasyCachingProvider.cs b/src/EasyCaching.Core/IEasyCachingProvider.cs index 2a65fe8c..e6e248d9 100644 --- a/src/EasyCaching.Core/IEasyCachingProvider.cs +++ b/src/EasyCaching.Core/IEasyCachingProvider.cs @@ -114,5 +114,17 @@ public interface IEasyCachingProvider /// Expiration. /// The 1st type parameter. Task RefreshAsync(string cacheKey, T cacheValue, TimeSpan expiration) where T : class; + + /// + /// Removes cached item by cachekey's prefix. + /// + /// Prefix of CacheKey. + void RemoveByPrefix(string prefix); + + /// + /// Removes cached item by cachekey's prefix async. + /// + /// Prefix of CacheKey. + Task RemoveByPrefixAsync(string prefix); } } diff --git a/src/EasyCaching.Core/IHybridCachingProvider.cs b/src/EasyCaching.Core/IHybridCachingProvider.cs new file mode 100644 index 00000000..44d2ff79 --- /dev/null +++ b/src/EasyCaching.Core/IHybridCachingProvider.cs @@ -0,0 +1,7 @@ +namespace EasyCaching.Core +{ + /// + /// Hybrid caching provider. + /// + public interface IHybridCachingProvider : IEasyCachingProvider { } +} diff --git a/src/EasyCaching.HybridCache/HybridCacheServiceCollectionExtensions.cs b/src/EasyCaching.HybridCache/HybridCacheServiceCollectionExtensions.cs index 123b916b..b6ac9599 100644 --- a/src/EasyCaching.HybridCache/HybridCacheServiceCollectionExtensions.cs +++ b/src/EasyCaching.HybridCache/HybridCacheServiceCollectionExtensions.cs @@ -1,5 +1,6 @@ namespace EasyCaching.HybridCache { + using EasyCaching.Core; using EasyCaching.Core.Internal; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; diff --git a/src/EasyCaching.HybridCache/HybridCachingProvider.cs b/src/EasyCaching.HybridCache/HybridCachingProvider.cs index 9e182b67..6406a9df 100644 --- a/src/EasyCaching.HybridCache/HybridCachingProvider.cs +++ b/src/EasyCaching.HybridCache/HybridCachingProvider.cs @@ -5,11 +5,6 @@ using System; using System.Threading.Tasks; - /// - /// Hybrid caching provider. - /// - public interface IHybridCachingProvider : IEasyCachingProvider{} - /// /// Hybrid caching provider. /// @@ -331,5 +326,15 @@ public async Task RefreshAsync(string cacheKey, T cacheValue, TimeSpan expira await this.RemoveAsync(cacheKey); await this.SetAsync(cacheKey, cacheValue, expiration); } + + public void RemoveByPrefix(string prefix) + { + throw new NotImplementedException(); + } + + public Task RemoveByPrefixAsync(string prefix) + { + throw new NotImplementedException(); + } } } diff --git a/src/EasyCaching.InMemory/InMemoryCachingProvider.cs b/src/EasyCaching.InMemory/InMemoryCachingProvider.cs index 1e21f246..541144c0 100644 --- a/src/EasyCaching.InMemory/InMemoryCachingProvider.cs +++ b/src/EasyCaching.InMemory/InMemoryCachingProvider.cs @@ -247,5 +247,15 @@ public async Task RefreshAsync(string cacheKey, T cacheValue, TimeSpan expira await this.RemoveAsync(cacheKey); await this.SetAsync(cacheKey, cacheValue, expiration); } + + public void RemoveByPrefix(string prefix) + { + throw new NotImplementedException(); + } + + public Task RemoveByPrefixAsync(string prefix) + { + throw new NotImplementedException(); + } } } diff --git a/src/EasyCaching.Memcached/DefaultMemcachedCachingProvider.cs b/src/EasyCaching.Memcached/DefaultMemcachedCachingProvider.cs index 4a687473..d0876868 100644 --- a/src/EasyCaching.Memcached/DefaultMemcachedCachingProvider.cs +++ b/src/EasyCaching.Memcached/DefaultMemcachedCachingProvider.cs @@ -251,5 +251,15 @@ public async Task RefreshAsync(string cacheKey, T cacheValue, TimeSpan expira await this.RemoveAsync(cacheKey); await this.SetAsync(cacheKey, cacheValue, expiration); } + + public void RemoveByPrefix(string prefix) + { + throw new NotImplementedException(); + } + + public Task RemoveByPrefixAsync(string prefix) + { + throw new NotImplementedException(); + } } } diff --git a/src/EasyCaching.Redis/DefaultRedisCachingProvider.cs b/src/EasyCaching.Redis/DefaultRedisCachingProvider.cs index be8b0bd7..94886aee 100644 --- a/src/EasyCaching.Redis/DefaultRedisCachingProvider.cs +++ b/src/EasyCaching.Redis/DefaultRedisCachingProvider.cs @@ -4,6 +4,8 @@ using EasyCaching.Core.Internal; using StackExchange.Redis; using System; + using System.Collections.Generic; + using System.Linq; using System.Threading.Tasks; /// @@ -16,6 +18,11 @@ public class DefaultRedisCachingProvider : IEasyCachingProvider /// private readonly IDatabase _cache; + /// + /// The servers. + /// + private readonly IEnumerable _servers; + /// /// The db provider. /// @@ -28,7 +35,7 @@ public class DefaultRedisCachingProvider : IEasyCachingProvider /// /// - /// is not distributed cache. + /// is distributed cache. /// public bool IsDistributedCache => false; @@ -47,6 +54,7 @@ public DefaultRedisCachingProvider( _dbProvider = dbProvider; _serializer = serializer; _cache = _dbProvider.GetDatabase(); + _servers = _dbProvider.GetServerList(); } /// @@ -279,5 +287,109 @@ public async Task RefreshAsync(string cacheKey, T cacheValue, TimeSpan expira await this.RemoveAsync(cacheKey); await this.SetAsync(cacheKey, cacheValue, expiration); } + + /// + /// Removes cached item by cachekey's prefix. + /// + /// Prefix of CacheKey. + public void RemoveByPrefix(string prefix) + { + ArgumentCheck.NotNullOrWhiteSpace(prefix, nameof(prefix)); + + this.HandlePrefix(prefix); + + foreach (var server in _servers) + { + this.HandleKeyDelWithTran(server, prefix); + } + } + + /// + /// Removes cached item by cachekey's prefix async. + /// + /// Prefix of CacheKey. + public async Task RemoveByPrefixAsync(string prefix) + { + ArgumentCheck.NotNullOrWhiteSpace(prefix, nameof(prefix)); + + this.HandlePrefix(prefix); + + foreach (var server in _servers) + { + await this.HandleKeyDelWithTranAsync(server, prefix); + } + } + + /// + /// Delete keys of Redis using transaction. + /// + /// Server. + /// Prefix. + private void HandleKeyDelWithTran(IServer server, string prefix) + { + int count = 1; + do + { + var keys = server.Keys(pattern: prefix, pageSize: 100); + count = keys.Count(); + if (count > 0) + { + var tran = _cache.CreateTransaction(); + + tran.KeyDeleteAsync(keys.ToArray()); + + tran.Execute(CommandFlags.FireAndForget); + } + } + while (count <= 0); + } + + /// + /// Delete keys of Redis using transaction async. + /// + /// The key del with tran async. + /// Server. + /// Prefix. + private async Task HandleKeyDelWithTranAsync(IServer server, string prefix) + { + int count = 1; + do + { + var keys = server.Keys(pattern: prefix, pageSize: 100); + count = keys.Count(); + if (count > 0) + { + var tran = _cache.CreateTransaction(); + + await tran.KeyDeleteAsync(keys.ToArray()); + + await tran.ExecuteAsync(CommandFlags.FireAndForget); + } + } + while (count <= 0); + } + + /// + /// Handles the prefix of CacheKey. + /// + /// Prefix of CacheKey. + /// + private void HandlePrefix(string prefix) + { + // Forbid + if (prefix.Equals("*")) + { + throw new ArgumentException("the prefix should not to *"); + } + + // Don't start with * + prefix = new System.Text.RegularExpressions.Regex("^\\*+").Replace(prefix, ""); + + // End with * + if (!prefix.EndsWith("*", StringComparison.OrdinalIgnoreCase)) + { + prefix = string.Concat(prefix, "*"); + } + } } } diff --git a/src/EasyCaching.SQLite/ConstSQL.cs b/src/EasyCaching.SQLite/ConstSQL.cs index ec8b0e3a..88a6755e 100644 --- a/src/EasyCaching.SQLite/ConstSQL.cs +++ b/src/EasyCaching.SQLite/ConstSQL.cs @@ -31,6 +31,11 @@ FROM [easycaching] /// public const string REMOVESQL = @"DELETE FROM [easycaching] WHERE [cachekey] = @cachekey "; + /// + /// The removebyprefixsql. + /// + public const string REMOVEBYPREFIXSQL = @"DELETE FROM [easycaching] WHERE [cachekey] like @cachekey "; + /// /// The existssql. /// diff --git a/src/EasyCaching.SQLite/SQLiteCachingProvider.cs b/src/EasyCaching.SQLite/SQLiteCachingProvider.cs index 90e21886..fbc1e640 100644 --- a/src/EasyCaching.SQLite/SQLiteCachingProvider.cs +++ b/src/EasyCaching.SQLite/SQLiteCachingProvider.cs @@ -302,5 +302,27 @@ public async Task RefreshAsync(string cacheKey, T cacheValue, TimeSpan expira await this.RemoveAsync(cacheKey); await this.SetAsync(cacheKey, cacheValue, expiration); } + + /// + /// Removes cached item by cachekey's prefix. + /// + /// Prefix of CacheKey. + public void RemoveByPrefix(string prefix) + { + ArgumentCheck.NotNullOrWhiteSpace(prefix, nameof(prefix)); + + _cache.Execute(ConstSQL.REMOVEBYPREFIXSQL, new { cachekey = string.Concat(prefix, "%") }); + } + + /// + /// Removes cached item by cachekey's prefix async. + /// + /// Prefix of CacheKey. + public async Task RemoveByPrefixAsync(string prefix) + { + ArgumentCheck.NotNullOrWhiteSpace(prefix, nameof(prefix)); + + await _cache.ExecuteAsync(ConstSQL.REMOVEBYPREFIXSQL, new { cachekey = string.Concat(prefix ,"%") }); + } } }