using Newtonsoft.Json; using System.Collections.Concurrent; using System.Reflection; using HealthMonitor.Util.Entities.Interfaces; namespace HealthMonitor.Core.Cache { public class EntityCacheHandler : IEntityCacheHandler { /// /// 结构示例 /// { /// "id_xxx": //实体的id值 /// [ /// "key_yyy_1", //缓存有该实体的缓存键 /// "key_yyy_2", /// ... /// ], /// ... /// } /// private ConcurrentDictionary>> _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>>(); _m_GetPrimaryKey = entityType.GetMethod(nameof(IEntity.GetPrimaryKey))!; } public IEnumerable? 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; } public void SetEntityCache(string key, object param, bool isEnumerable = false) { if (param == null) return; IEnumerable value; if (isEnumerable) value = (param as IEnumerable)!; else value = new List { param }; RedisHelper.SetAsync(key, value, DurableSecond); MapKeyToEntity(key, value!); } public void DeleteEntityCache(string key) { RedisHelper.DelAsync(key); } public IEnumerable? UnmapKeyFromEntity(object entity) { if (entity == null) return null; string id = _m_GetPrimaryKey.Invoke(entity, null) + ""; //if (!_mapper.TryRemove(id, out List> rels)) return null; if (!_mapper.TryRemove(id, out var rels)) return null; return rels.Select(e => e.Item1).Distinct(); } public void CleanUpExpiredMapper() { if (_mapper.Keys.Count == 0) { //释放内存 _mapper.Clear(); _mapper = new ConcurrentDictionary>>(); return; } foreach (var id in _mapper.Keys) { // if (!_mapper.TryRemove(id, out List> rels)) continue; if (!_mapper.TryRemove(id, out var 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; }); } } /// /// 附加缓存键和实体主键(或实体主键列表)的映射关系 /// /// /// 实体列表 private void MapKeyToEntity(string key, IEnumerable 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> { new Tuple(key, DateTime.Now) }, (_, _presentValue) => { _presentValue.Add(new Tuple(key, DateTime.Now)); return _presentValue; }); } } } }