|
- using Newtonsoft.Json;
- using System.Collections.Concurrent;
- using System.Reflection;
- using HealthMonitor.Util.Entities.Interfaces;
-
- namespace HealthMonitor.Core.Cache
- {
- public class EntityCacheHandler : IEntityCacheHandler
- {
- /// <summary>
- /// 结构示例
- /// {
- /// "id_xxx": //实体的id值
- /// [
- /// "key_yyy_1", //缓存有该实体的缓存键
- /// "key_yyy_2",
- /// ...
- /// ],
- /// ...
- /// }
- /// </summary>
- private ConcurrentDictionary<string, List<Tuple<string, DateTime>>> _mapper;
- private readonly MethodInfo _m_GetPrimaryKey;
-
- public int DurableSecond { get; private set; }
- public Type EntityType { get; private set; }
-
- public EntityCacheHandler(Type entityType, int durableSeconds)
- {
- EntityType = entityType;
- DurableSecond = durableSeconds;
-
- _mapper = new ConcurrentDictionary<string, List<Tuple<string, DateTime>>>();
- _m_GetPrimaryKey = entityType.GetMethod(nameof(IEntity.GetPrimaryKey))!;
- }
-
- public IEnumerable<object>? GetEntitiesCache(string key)
- {
- string json = RedisHelper.Get(key);
- if (string.IsNullOrEmpty(json)) return null;
-
- var t = typeof(IEnumerable<>);
- return JsonConvert.DeserializeObject(json, t.MakeGenericType(EntityType)) as IEnumerable<object>;
- }
-
- public void SetEntityCache(string key, object param, bool isEnumerable = false)
- {
- if (param == null) return;
- IEnumerable<object> value;
- if (isEnumerable) value = (param as IEnumerable<object>)!;
- else value = new List<object> { param };
-
- RedisHelper.SetAsync(key, value, DurableSecond);
-
- MapKeyToEntity(key, value!);
- }
-
- public void DeleteEntityCache(string key)
- {
- RedisHelper.DelAsync(key);
- }
-
- public IEnumerable<string>? UnmapKeyFromEntity(object entity)
- {
- if (entity == null) return null;
-
- string id = _m_GetPrimaryKey.Invoke(entity, null) + "";
- if (!_mapper.TryRemove(id, out List<Tuple<string, DateTime>> rels)) return null;
-
- return rels.Select(e => e.Item1).Distinct();
- }
-
- public void CleanUpExpiredMapper()
- {
- if (_mapper.Keys.Count == 0)
- {
- //释放内存
- _mapper.Clear();
- _mapper = new ConcurrentDictionary<string, List<Tuple<string, DateTime>>>();
- return;
- }
- foreach (var id in _mapper.Keys)
- {
- if (!_mapper.TryRemove(id, out List<Tuple<string, DateTime>> rels)) continue;
-
- var availableList = rels.Where(t => DateTime.Now.Subtract(t.Item2).TotalSeconds < DurableSecond).ToList();
- _mapper.AddOrUpdate(id,
- _ => availableList,
- (_, _presentValue) =>
- {
- _presentValue.AddRange(availableList);
- return _presentValue;
- });
- }
- }
-
- /// <summary>
- /// 附加缓存键和实体主键(或实体主键列表)的映射关系
- /// </summary>
- /// <param name="key"></param>
- /// <param name="entities">实体列表</param>
- private void MapKeyToEntity(string key, IEnumerable<object> entities)
- {
- if (entities == null || entities.Count() == 0) return;
-
- foreach (var entity in entities)
- {
- string id = _m_GetPrimaryKey.Invoke(entity, null) + "";
-
- _mapper.AddOrUpdate(id,
- _ => new List<Tuple<string, DateTime>> { new Tuple<string, DateTime>(key, DateTime.Now) },
- (_, _presentValue) =>
- {
- _presentValue.Add(new Tuple<string, DateTime>(key, DateTime.Now));
- return _presentValue;
- });
- }
- }
- }
- }
|