添加项目文件。
This commit is contained in:
7
TightWiki.Caching/IWikiCacheKey.cs
Normal file
7
TightWiki.Caching/IWikiCacheKey.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace TightWiki.Caching
|
||||
{
|
||||
public interface IWikiCacheKey
|
||||
{
|
||||
public string Key { get; set; }
|
||||
}
|
||||
}
|
||||
18
TightWiki.Caching/TightWiki.Caching.csproj
Normal file
18
TightWiki.Caching/TightWiki.Caching.csproj
Normal file
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Version>2.20.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||
<DebugSymbols>False</DebugSymbols>
|
||||
<DebugType>None</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Runtime.Caching" Version="9.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
186
TightWiki.Caching/WikiCache.cs
Normal file
186
TightWiki.Caching/WikiCache.cs
Normal file
@@ -0,0 +1,186 @@
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.Caching;
|
||||
|
||||
namespace TightWiki.Caching
|
||||
{
|
||||
public class WikiCache
|
||||
{
|
||||
public enum Category
|
||||
{
|
||||
User,
|
||||
Page,
|
||||
Search,
|
||||
Emoji,
|
||||
Configuration
|
||||
}
|
||||
|
||||
public static int DefaultCacheSeconds { get; set; }
|
||||
private static MemoryCache? _memCache;
|
||||
public static ulong CachePuts { get; set; }
|
||||
public static ulong CacheGets { get; set; }
|
||||
public static ulong CacheHits { get; set; }
|
||||
public static ulong CacheMisses { get; set; }
|
||||
public static int CacheItemCount => MemCache.Count();
|
||||
public static double CacheMemoryLimit => MemCache.CacheMemoryLimit;
|
||||
|
||||
public static MemoryCache MemCache => _memCache ?? throw new Exception("Cache has not been initialized.");
|
||||
|
||||
public static void Initialize(int cacheMemoryLimitMB, int defaultCacheSeconds)
|
||||
{
|
||||
DefaultCacheSeconds = defaultCacheSeconds;
|
||||
var config = new NameValueCollection
|
||||
{
|
||||
//config.Add("pollingInterval", "00:05:00");
|
||||
//config.Add("physicalMemoryLimitPercentage", "0");
|
||||
{ "CacheMemoryLimitMegabytes", cacheMemoryLimitMB.ToString() }
|
||||
};
|
||||
_memCache?.Dispose();
|
||||
_memCache = new MemoryCache("TightWikiCache", config);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an item from the cache.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <returns></returns>
|
||||
public static T? Get<T>(IWikiCacheKey cacheKey)
|
||||
{
|
||||
CacheGets++;
|
||||
var result = (T)MemCache.Get(cacheKey.Key);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
CacheMisses++;
|
||||
}
|
||||
|
||||
CacheHits++;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the cache contains a given key.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <returns></returns>
|
||||
public static bool Contains(IWikiCacheKey cacheKey)
|
||||
{
|
||||
CacheGets++;
|
||||
if (MemCache.Contains(cacheKey.Key))
|
||||
{
|
||||
CacheHits++;
|
||||
return true;
|
||||
}
|
||||
|
||||
CacheMisses++;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an item from the cache.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <returns></returns>
|
||||
public static bool TryGet<T>(IWikiCacheKey cacheKey, [NotNullWhen(true)] out T result)
|
||||
{
|
||||
CacheGets++;
|
||||
if ((result = (T)MemCache.Get(cacheKey.Key)) == null)
|
||||
{
|
||||
CacheMisses++;
|
||||
return false;
|
||||
}
|
||||
|
||||
CacheHits++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an item to the cache. If the item is already in the cache, this will reset its expiration.
|
||||
/// </summary>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="seconds"></param>
|
||||
public static void Put(IWikiCacheKey cacheKey, object value, int? seconds = null)
|
||||
{
|
||||
CachePuts++;
|
||||
|
||||
seconds ??= DefaultCacheSeconds;
|
||||
if (seconds <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var policy = new CacheItemPolicy()
|
||||
{
|
||||
AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(seconds ?? DefaultCacheSeconds)
|
||||
};
|
||||
MemCache.Add(cacheKey.Key, value, policy);
|
||||
}
|
||||
|
||||
public static void Put(IWikiCacheKey cacheKey, object value, CacheItemPolicy policy)
|
||||
{
|
||||
CachePuts++;
|
||||
MemCache.Add(cacheKey.Key, value, policy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all entries from the cache.
|
||||
/// </summary>
|
||||
public static void Clear()
|
||||
{
|
||||
if (_memCache == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var items = MemCache.ToList();
|
||||
foreach (var a in items)
|
||||
{
|
||||
MemCache.Remove(a.Key);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes cache entries that begin with the given cache key.
|
||||
/// </summary>
|
||||
/// <param name="category"></param>
|
||||
public static void ClearCategory(WikiCacheKey cacheKey)
|
||||
{
|
||||
var keys = new List<string>();
|
||||
|
||||
foreach (var item in MemCache)
|
||||
{
|
||||
if (item.Key.StartsWith(cacheKey.Key))
|
||||
{
|
||||
keys.Add(item.Key);
|
||||
}
|
||||
}
|
||||
|
||||
keys.ForEach(o => MemCache.Remove(o));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes cache entries in a given category.
|
||||
/// </summary>
|
||||
/// <param name="category"></param>
|
||||
public static void ClearCategory(Category category)
|
||||
{
|
||||
var cacheKey = WikiCacheKey.Build(category);
|
||||
|
||||
var keys = new List<string>();
|
||||
|
||||
foreach (var item in MemCache)
|
||||
{
|
||||
if (item.Key.StartsWith(cacheKey.Key))
|
||||
{
|
||||
keys.Add(item.Key);
|
||||
}
|
||||
}
|
||||
|
||||
keys.ForEach(o => MemCache.Remove(o));
|
||||
}
|
||||
}
|
||||
}
|
||||
19
TightWiki.Caching/WikiCacheKey.cs
Normal file
19
TightWiki.Caching/WikiCacheKey.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using static TightWiki.Caching.WikiCache;
|
||||
|
||||
namespace TightWiki.Caching
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains a verbatim cache key.
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
public class WikiCacheKey(string key) : IWikiCacheKey
|
||||
{
|
||||
public string Key { get; set; } = key;
|
||||
|
||||
public static WikiCacheKey Build(Category category, object?[] segments)
|
||||
=> new($"[{category}]:[{string.Join("]:[", segments)}]");
|
||||
|
||||
public static WikiCacheKey Build(Category category)
|
||||
=> new($"[{category}]");
|
||||
}
|
||||
}
|
||||
26
TightWiki.Caching/WikiCacheKeyFunction.cs
Normal file
26
TightWiki.Caching/WikiCacheKeyFunction.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using static TightWiki.Caching.WikiCache;
|
||||
|
||||
namespace TightWiki.Caching
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains a verbatim cache key which also includes the calling function name.
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
public class WikiCacheKeyFunction(string key) : IWikiCacheKey
|
||||
{
|
||||
public string Key { get; set; } = key;
|
||||
|
||||
/// <summary>
|
||||
/// Builds a cache key which includes the calling function name.
|
||||
/// </summary>
|
||||
public static WikiCacheKeyFunction Build(Category category, object?[] segments, [CallerMemberName] string callingFunction = "")
|
||||
=> new($"[{category}]:[{string.Join("]:[", segments)}]:[{callingFunction}]");
|
||||
|
||||
/// <summary>
|
||||
/// Builds a cache key which includes the calling function name.
|
||||
/// </summary>
|
||||
public static WikiCacheKeyFunction Build(Category category, [CallerMemberName] string callingFunction = "")
|
||||
=> new($"[{category}]:[{callingFunction}]");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user