You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
319 lines
9.2 KiB
319 lines
9.2 KiB
|
3 months ago
|
//------------------------------------------------------------------------------
|
||
|
|
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||
|
|
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||
|
|
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||
|
|
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||
|
|
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||
|
|
// Github源代码仓库:https://github.com/RRQM
|
||
|
|
// API首页:https://www.yuque.com/rrqm/touchsocket/index
|
||
|
|
// 交流QQ群:234762506
|
||
|
|
// 感谢您的下载和使用
|
||
|
|
//------------------------------------------------------------------------------
|
||
|
|
//------------------------------------------------------------------------------
|
||
|
|
using System;
|
||
|
|
using System.Collections;
|
||
|
|
using System.Collections.Concurrent;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Threading;
|
||
|
|
using System.Threading.Tasks;
|
||
|
|
|
||
|
|
namespace TouchSocket.Core
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// 一个简单的内存缓存
|
||
|
|
/// </summary>
|
||
|
|
public class MemoryCache<TKey, TValue> : IEnumerable<ICacheEntry<TKey, TValue>>, ICache<TKey, TValue>
|
||
|
|
{
|
||
|
|
private readonly ConcurrentDictionary<TKey, ICacheEntry<TKey, TValue>> m_pairs = new ConcurrentDictionary<TKey, ICacheEntry<TKey, TValue>>();
|
||
|
|
private readonly Timer m_timer;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 一个简单的内存缓存
|
||
|
|
/// </summary>
|
||
|
|
public MemoryCache()
|
||
|
|
{
|
||
|
|
m_timer = new Timer((o) =>
|
||
|
|
{
|
||
|
|
List<TKey> list = new List<TKey>();
|
||
|
|
foreach (var item in m_pairs)
|
||
|
|
{
|
||
|
|
if (DateTime.Now - item.Value.UpdateTime > item.Value.Duration)
|
||
|
|
{
|
||
|
|
list.Add(item.Key);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
foreach (var item in list)
|
||
|
|
{
|
||
|
|
OnRemove(item, out _);
|
||
|
|
}
|
||
|
|
}, null, 0, 60 * 1000);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 当每个元素超时被移除时触发。
|
||
|
|
/// </summary>
|
||
|
|
public Action<ICacheEntry<TKey, TValue>> Remove { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="entity"></param>
|
||
|
|
public bool AddCache(ICacheEntry<TKey, TValue> entity)
|
||
|
|
{
|
||
|
|
return m_pairs.TryAdd(entity.Key, entity);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="entity"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public Task<bool> AddCacheAsync(ICacheEntry<TKey, TValue> entity)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
return AddCache(entity);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 清空所有缓存
|
||
|
|
/// </summary>
|
||
|
|
public void ClearCache()
|
||
|
|
{
|
||
|
|
m_pairs.Clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
public Task ClearCacheAsync()
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
ClearCache();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="key"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public bool ContainsCache(TKey key)
|
||
|
|
{
|
||
|
|
if (m_pairs.TryGetValue(key, out ICacheEntry<TKey, TValue> cache))
|
||
|
|
{
|
||
|
|
if (cache.Duration == TimeSpan.Zero)
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (DateTime.Now - cache.UpdateTime > cache.Duration)
|
||
|
|
{
|
||
|
|
OnRemove(key, out _);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="key"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public Task<bool> ContainsCacheAsync(TKey key)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
return ContainsCache(key);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 获取缓存实体。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="key"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public ICacheEntry<TKey, TValue> GetCache(TKey key)
|
||
|
|
{
|
||
|
|
ICacheEntry<TKey, TValue> cache;
|
||
|
|
if (m_pairs.TryGetValue(key, out cache))
|
||
|
|
{
|
||
|
|
if (cache.Duration == TimeSpan.Zero)
|
||
|
|
{
|
||
|
|
return cache;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (DateTime.Now - cache.UpdateTime > cache.Duration)
|
||
|
|
{
|
||
|
|
OnRemove(key, out _);
|
||
|
|
return default;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return cache;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return default;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="key"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public Task<ICacheEntry<TKey, TValue>> GetCacheAsync(TKey key)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
return GetCache(key);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <returns></returns>
|
||
|
|
public IEnumerator<ICacheEntry<TKey, TValue>> GetEnumerator()
|
||
|
|
{
|
||
|
|
return m_pairs.Values.GetEnumerator();
|
||
|
|
}
|
||
|
|
|
||
|
|
IEnumerator IEnumerable.GetEnumerator()
|
||
|
|
{
|
||
|
|
return GetEnumerator();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 移除缓存
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="key"></param>
|
||
|
|
/// <param name="entity"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public bool RemoveCache(TKey key, out ICacheEntry<TKey, TValue> entity)
|
||
|
|
{
|
||
|
|
return OnRemove(key, out entity);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 移除缓存
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="key"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public bool RemoveCache(TKey key)
|
||
|
|
{
|
||
|
|
return OnRemove(key, out _);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="key"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public Task<bool> RemoveCacheAsync(TKey key)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
return RemoveCache(key);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="entity"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public bool SetCache(ICacheEntry<TKey, TValue> entity)
|
||
|
|
{
|
||
|
|
m_pairs.AddOrUpdate(entity.Key, entity, (k, v) =>
|
||
|
|
{
|
||
|
|
return entity;
|
||
|
|
});
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="entity"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public Task<bool> SetCacheAsync(ICacheEntry<TKey, TValue> entity)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
return SetCache(entity);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 获取对应的值。
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="key"></param>
|
||
|
|
/// <param name="value"></param>
|
||
|
|
/// <param name="update"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public bool TryGetValue(TKey key, out TValue value, bool update = false)
|
||
|
|
{
|
||
|
|
if (m_pairs.TryGetValue(key, out ICacheEntry<TKey, TValue> cache))
|
||
|
|
{
|
||
|
|
if (cache.Duration == TimeSpan.Zero)
|
||
|
|
{
|
||
|
|
if (update)
|
||
|
|
{
|
||
|
|
cache.UpdateTime = DateTime.Now;
|
||
|
|
}
|
||
|
|
value = cache.Value;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (DateTime.Now - cache.UpdateTime > cache.Duration)
|
||
|
|
{
|
||
|
|
RemoveCache(key);
|
||
|
|
value = default;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (update)
|
||
|
|
{
|
||
|
|
cache.UpdateTime = DateTime.Now;
|
||
|
|
}
|
||
|
|
value = (TValue)cache.Value;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
value = default;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
private bool OnRemove(TKey key, out ICacheEntry<TKey, TValue> cache)
|
||
|
|
{
|
||
|
|
if (m_pairs.TryRemove(key, out cache))
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
Remove?.Invoke(cache);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|