|
@@ -0,0 +1,211 @@
|
|
|
+using StackExchange.Redis;
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Linq;
|
|
|
+using VCommon.Caching.Internals;
|
|
|
+using VCommon.Json;
|
|
|
+
|
|
|
+namespace VCommon.Caching
|
|
|
+{
|
|
|
+ public class CacheManager
|
|
|
+ {
|
|
|
+ private readonly RedisCacheAccess _cacheAccess;
|
|
|
+
|
|
|
+ public CacheManager(string server) => _cacheAccess = CacheAccess.CreateRedisAccessInstance(server);
|
|
|
+
|
|
|
+ public void KeyExpire(int db, string key, CacheExpire expire)
|
|
|
+ {
|
|
|
+ if (null != expire)
|
|
|
+ {
|
|
|
+ if (expire.To.HasValue) _cacheAccess.CacheOp(db, p => p.KeyExpire(key, expire.To.Value));
|
|
|
+ if (expire.Specified.HasValue) _cacheAccess.CacheOp(db, p => p.KeyExpire(key, expire.Specified.Value));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool KeyExist(int db, string key) => _cacheAccess.CacheOp(db, p => p.KeyExists(key));
|
|
|
+
|
|
|
+ public bool KeyDelete(int db, string key) => _cacheAccess.CacheOp(db, p => p.KeyDelete(key));
|
|
|
+
|
|
|
+ public void KeySetJson(int db, string key, object value, CacheExpire expire = null)
|
|
|
+ {
|
|
|
+ var json = VJsonSerializer.Serialize(value);
|
|
|
+ _cacheAccess.CacheOp(db, p => p.StringSet(key, json));
|
|
|
+ KeyExpire(db, key, expire);
|
|
|
+ }
|
|
|
+
|
|
|
+ public T KeyGetJson<T>(int db, string key) => VJsonSerializer.Deserialize<T>(_cacheAccess.CacheOp(db, p => p.StringGet(key)));
|
|
|
+
|
|
|
+ public void KeySet(int db, string key, CacheValue value, CacheExpire expire = null)
|
|
|
+ {
|
|
|
+ _cacheAccess.CacheOp(db, p => p.StringSet(key, value));
|
|
|
+ KeyExpire(db, key, expire);
|
|
|
+ }
|
|
|
+
|
|
|
+ public CacheValue KeyGet(int db, string key) => _cacheAccess.CacheOp(db, p => p.StringGet(key));
|
|
|
+
|
|
|
+ public bool HashFieldExist(int db, string hashKey, string hashField) => _cacheAccess.CacheOp(db, p => p.HashExists(hashKey, hashField));
|
|
|
+
|
|
|
+ public bool HashFieldDelete(int db, string hashKey, string hashField) => _cacheAccess.CacheOp(db, p => p.HashDelete(hashKey, hashField));
|
|
|
+
|
|
|
+ public long HashFieldDelete(int db, string hashKey, params string[] hashFields)
|
|
|
+ {
|
|
|
+ if (0 == hashFields.Length) return 0;
|
|
|
+ var fields = hashFields.Select(p => (RedisValue)p).ToArray();
|
|
|
+ return _cacheAccess.CacheOp(db, p => p.HashDelete(hashKey, fields));
|
|
|
+ }
|
|
|
+
|
|
|
+ public CacheValue HashFieldFetch(int db, string hashKey, string hashField, Func<CacheValue> missingCacheValueProvider, CacheExpire expire = null)
|
|
|
+ {
|
|
|
+ CacheValue cv = _cacheAccess.CacheOp(db, p => p.HashGet(hashKey, hashField));
|
|
|
+ if (false == cv.IsNull) return cv;
|
|
|
+
|
|
|
+ var through = missingCacheValueProvider();
|
|
|
+ if (through.IsNull) return through;
|
|
|
+
|
|
|
+ _cacheAccess.CacheOp(db, p => p.HashSet(hashKey, hashField, through));
|
|
|
+ KeyExpire(db, hashKey, expire);
|
|
|
+
|
|
|
+ return through;
|
|
|
+ }
|
|
|
+
|
|
|
+ public T HashFieldFetchJson<T>(int db, string hashKey, string hashField, Func<T> missingCacheValueProvider, CacheExpire expire = null)
|
|
|
+ {
|
|
|
+ string json = _cacheAccess.CacheOp(db, p => p.HashGet(hashKey, hashField));
|
|
|
+ if (null != json) return VJsonSerializer.Deserialize<T>(json);
|
|
|
+
|
|
|
+ var through = missingCacheValueProvider();
|
|
|
+
|
|
|
+ var json2 = VJsonSerializer.Serialize(through);
|
|
|
+ _cacheAccess.CacheOp(db, p => p.HashSet(hashKey, hashField, json2));
|
|
|
+ KeyExpire(db, hashKey, expire);
|
|
|
+
|
|
|
+ return through;
|
|
|
+ }
|
|
|
+
|
|
|
+ public T HashFieldGetJson<T>(int db, string hashKey, string hashField)
|
|
|
+ {
|
|
|
+ var json = (string)_cacheAccess.CacheOp(db, p => p.HashGet(hashKey, hashField));
|
|
|
+ return VJsonSerializer.Deserialize<T>(json);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void HashFieldSetJson<T>(int db, string hashKey, string hashField, T value, CacheExpire expire = null)
|
|
|
+ {
|
|
|
+ var json = VJsonSerializer.Serialize(value);
|
|
|
+ _cacheAccess.CacheOp(db, p => p.HashSet(hashKey, hashField, json));
|
|
|
+ KeyExpire(db, hashKey, expire);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void HashFieldSetJson<T>(int db, string hashKey, IReadOnlyDictionary<string, T> entries, CacheExpire expire = null)
|
|
|
+ {
|
|
|
+ var hashEntrys = entries.Select(p => new HashEntry(p.Key, VJsonSerializer.Serialize(p.Value))).ToArray();
|
|
|
+ _cacheAccess.CacheOp(db, p => p.HashSet(hashKey, hashEntrys));
|
|
|
+ KeyExpire(db, hashKey, expire);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void HashFieldPurgeAndSet(int db, string hashKey, IReadOnlyDictionary<string, CacheValue> hashFields)
|
|
|
+ {
|
|
|
+ var entries = hashFields.Select(p => new HashEntry(p.Key, p.Value)).ToArray();
|
|
|
+ if (0 == entries.Length) return;
|
|
|
+ _cacheAccess.CacheOp(db, p =>
|
|
|
+ {
|
|
|
+ var batch = p.CreateBatch();
|
|
|
+ batch.KeyDeleteAsync(hashKey);
|
|
|
+ batch.HashSetAsync(hashKey, entries);
|
|
|
+ batch.Execute();
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ public void HashFieldDeleteByPattern(int db, string hashKey, string pattern)
|
|
|
+ {
|
|
|
+ var entries = _cacheAccess.CacheOp(db, p => p.HashScan(hashKey, pattern, int.MaxValue)).Select(p => p.Name).ToArray();
|
|
|
+ _cacheAccess.CacheOp(db, p => p.HashDelete(hashKey, entries));
|
|
|
+ }
|
|
|
+
|
|
|
+ public IReadOnlyDictionary<string, CacheValue> HashFieldGetByPattern(int db, string hashKey, string pattern)
|
|
|
+ {
|
|
|
+ return _cacheAccess.CacheOp(db, p => p.HashScan(hashKey, pattern, int.MaxValue))
|
|
|
+ .ToDictionary(p => (string)p.Name, p => (CacheValue)p.Value);
|
|
|
+ }
|
|
|
+
|
|
|
+ public IReadOnlyDictionary<string, T> HashFieldGetByPatternJson<T>(int db, string hashKey, string pattern)
|
|
|
+ {
|
|
|
+ return _cacheAccess.CacheOp(db, p => p.HashScan(hashKey, pattern, int.MaxValue))
|
|
|
+ .ToDictionary(p => (string)p.Name, p => VJsonSerializer.Deserialize<T>(p.Value));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void HashFieldSet(int db, string hashKey, string hashField, CacheValue value, CacheExpire expire = null)
|
|
|
+ {
|
|
|
+ _cacheAccess.CacheOp(db, p => p.HashSet(hashKey, hashField, value));
|
|
|
+ KeyExpire(db, hashKey, expire);
|
|
|
+ }
|
|
|
+
|
|
|
+ public CacheValue HashFieldGet(int db, string hashKey, string hashField) => _cacheAccess.CacheOp(db, p => p.HashGet(hashKey, hashField));
|
|
|
+
|
|
|
+ public void HashFieldSet(int db, string hashKey, IReadOnlyDictionary<string, CacheValue> hashField, CacheExpire expire = null)
|
|
|
+ {
|
|
|
+ var entries = hashField.Select(p => new HashEntry(p.Key, p.Value)).ToArray();
|
|
|
+ if (0 == entries.Length) return;
|
|
|
+ _cacheAccess.CacheOp(db, p => p.HashSet(hashKey, entries));
|
|
|
+ KeyExpire(db, hashKey, expire);
|
|
|
+ }
|
|
|
+
|
|
|
+ public long HashFieldIncrement(int db, string hashKey, string hashField) => _cacheAccess.CacheOp(db, p => p.HashIncrement(hashKey, hashField));
|
|
|
+
|
|
|
+ public long HashFieldDecrement(int db, string hashKey, string hashField) => _cacheAccess.CacheOp(db, p => p.HashDecrement(hashKey, hashField));
|
|
|
+
|
|
|
+ public IReadOnlyDictionary<string, CacheValue> HashFieldGet(int db, string hashKey, params string[] hashFields)
|
|
|
+ {
|
|
|
+ if (0 == hashFields.Length) return new Dictionary<string, CacheValue>();
|
|
|
+
|
|
|
+ var keys = hashFields.Distinct().ToArray();
|
|
|
+ var fields = keys.Select(p => (RedisValue)p).ToArray();
|
|
|
+ return _cacheAccess.CacheOp(db, p => p.HashGet(hashKey, fields))
|
|
|
+ .Select((p, i) => new { k = keys[i], v = p })
|
|
|
+ .ToDictionary(p => p.k, p => (CacheValue)p.v);
|
|
|
+ }
|
|
|
+
|
|
|
+ public IReadOnlyDictionary<TK, TV> HashFieldsFetchAsDic<TK, TV>(int db, string key, IEnumerable<TK> hashFields,
|
|
|
+ Func<TK, string> convertHashField,
|
|
|
+ Func<IEnumerable<TK>, IReadOnlyDictionary<TK, TV>> missingCacheValueProvider,
|
|
|
+ Func<TV, CacheValue> convertValueToCache,
|
|
|
+ Func<CacheValue, TV> convertCacheToValue,
|
|
|
+ CacheExpire expire = null)
|
|
|
+ {
|
|
|
+ var result = new Dictionary<TK, TV>();
|
|
|
+
|
|
|
+ var missingFields = new List<TK>(); //get from cache,and collect missing
|
|
|
+ {
|
|
|
+ var fields = hashFields.Distinct().ToArray();
|
|
|
+ if (0 == fields.Length) return result;
|
|
|
+
|
|
|
+ var hf = fields.Select(p => (RedisValue)convertHashField(p)).ToArray();
|
|
|
+
|
|
|
+ var fromCache = _cacheAccess.CacheOp(db, p => p.HashGet(key, hf));
|
|
|
+
|
|
|
+ for (var i = 0; i < fromCache.Length; i++)
|
|
|
+ {
|
|
|
+ if (false == fromCache[i].HasValue) missingFields.Add(fields[i]);
|
|
|
+ else result[fields[i]] = convertCacheToValue(fromCache[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (0 != missingFields.Count) //get from db,and put cache
|
|
|
+ {
|
|
|
+ var fromDb = missingCacheValueProvider(missingFields);
|
|
|
+ var entries = fromDb.Select(p => new HashEntry(convertHashField(p.Key), convertValueToCache(p.Value)))
|
|
|
+ .Where(p => false == p.Value.IsNull)
|
|
|
+ .ToArray();
|
|
|
+ _cacheAccess.CacheOp(db, p => p.HashSet(key, entries));
|
|
|
+
|
|
|
+ //merge to result
|
|
|
+ foreach (var kvp in fromDb) result[kvp.Key] = kvp.Value;
|
|
|
+ }
|
|
|
+
|
|
|
+ KeyExpire(db, key, expire);
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ public string[] SearchKeys(int db, string pattern) => _cacheAccess.SearchKeys(db, pattern).Select(p => (string)p).ToArray();
|
|
|
+ }
|
|
|
+}
|