diff --git a/src/ZiggyCreatures.FusionCache/FusionCache.cs b/src/ZiggyCreatures.FusionCache/FusionCache.cs index 99a24346..3db2832c 100644 --- a/src/ZiggyCreatures.FusionCache/FusionCache.cs +++ b/src/ZiggyCreatures.FusionCache/FusionCache.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; @@ -42,6 +43,10 @@ public partial class FusionCache private readonly List _plugins; private AutoRecoveryService _autoRecovery; + private FusionCacheEntryOptions _tryUpdateOptions; + private static readonly MethodInfo __methodInfoTryUpdateMemoryEntryFromDistributedEntryAsyncOpenGeneric = typeof(FusionCache).GetMethod(nameof(TryUpdateMemoryEntryFromDistributedEntryAsync), BindingFlags.NonPublic | BindingFlags.Instance); + private static readonly ConcurrentDictionary __methodInfoTryUpdateMemoryEntryFromDistributedEntryAsyncCache = new ConcurrentDictionary(); + /// /// Creates a new instance. /// @@ -671,8 +676,6 @@ internal bool MustAwaitBackplaneOperations(FusionCacheEntryOptions options) return false; } - private static readonly MethodInfo __methodInfoTryUpdateMemoryEntryFromDistributedEntryAsyncOpenGeneric = typeof(FusionCache).GetMethod(nameof(TryUpdateMemoryEntryFromDistributedEntryAsync), BindingFlags.NonPublic | BindingFlags.Instance); - internal async ValueTask<(bool error, bool isSame, bool hasUpdated)> TryUpdateMemoryEntryFromDistributedEntryUntypedAsync(string operationId, string cacheKey, FusionCacheMemoryEntry memoryEntry) { if (_logger?.IsEnabled(LogLevel.Trace) ?? false) @@ -706,7 +709,8 @@ internal bool MustAwaitBackplaneOperations(FusionCacheEntryOptions options) return (true, false, false); } - var methodInfo = __methodInfoTryUpdateMemoryEntryFromDistributedEntryAsyncOpenGeneric.MakeGenericMethod(memoryEntry.ValueType); + var methodInfo = __methodInfoTryUpdateMemoryEntryFromDistributedEntryAsyncCache.GetOrAdd(memoryEntry.ValueType, x => __methodInfoTryUpdateMemoryEntryFromDistributedEntryAsyncOpenGeneric.MakeGenericMethod(x)); + // SIGNATURE PARAMS: string operationId, string cacheKey, DistributedCacheAccessor dca, FusionCacheMemoryEntry memoryEntry return await ((ValueTask<(bool error, bool isSame, bool hasUpdated)>)methodInfo.Invoke(this, new object[] { operationId, cacheKey, dca, memoryEntry })).ConfigureAwait(false); } @@ -719,7 +723,6 @@ internal bool MustAwaitBackplaneOperations(FusionCacheEntryOptions options) } } - private FusionCacheEntryOptions _tryUpdateOptions; private async ValueTask<(bool error, bool isSame, bool hasUpdated)> TryUpdateMemoryEntryFromDistributedEntryAsync(string operationId, string cacheKey, DistributedCacheAccessor dca, FusionCacheMemoryEntry memoryEntry) { try diff --git a/src/ZiggyCreatures.FusionCache/Internals/Distributed/DistributedCacheAccessor.cs b/src/ZiggyCreatures.FusionCache/Internals/Distributed/DistributedCacheAccessor.cs index e883bb3e..58c2f13c 100644 --- a/src/ZiggyCreatures.FusionCache/Internals/Distributed/DistributedCacheAccessor.cs +++ b/src/ZiggyCreatures.FusionCache/Internals/Distributed/DistributedCacheAccessor.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Reflection; using System.Runtime.CompilerServices; using System.Threading; @@ -13,6 +14,17 @@ namespace ZiggyCreatures.Caching.Fusion.Internals.Distributed; internal sealed partial class DistributedCacheAccessor { + private readonly IDistributedCache _cache; + private readonly IFusionCacheSerializer _serializer; + private readonly FusionCacheOptions _options; + private readonly ILogger? _logger; + private readonly FusionCacheDistributedEventsHub _events; + private readonly SimpleCircuitBreaker _breaker; + private readonly string _wireFormatToken; + + private static readonly MethodInfo __methodInfoSetEntryAsyncOpenGeneric = typeof(DistributedCacheAccessor).GetMethod(nameof(SetEntryAsync), BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + private static readonly ConcurrentDictionary __methodInfoSetEntryAsyncCache = new ConcurrentDictionary(); + public DistributedCacheAccessor(IDistributedCache distributedCache, IFusionCacheSerializer serializer, FusionCacheOptions options, ILogger? logger, FusionCacheDistributedEventsHub events) { if (distributedCache is null) @@ -48,14 +60,6 @@ public DistributedCacheAccessor(IDistributedCache distributedCache, IFusionCache }; } - private readonly IDistributedCache _cache; - private readonly IFusionCacheSerializer _serializer; - private readonly FusionCacheOptions _options; - private readonly ILogger? _logger; - private readonly FusionCacheDistributedEventsHub _events; - private readonly SimpleCircuitBreaker _breaker; - private readonly string _wireFormatToken; - [MethodImpl(MethodImplOptions.AggressiveInlining)] private string MaybeProcessCacheKey(string key) { @@ -121,8 +125,6 @@ private void ProcessError(string operationId, string key, Exception exc, string _logger.Log(_options.DistributedCacheErrorsLogLevel, exc, "FUSION [N={CacheName} I={CacheInstanceId}] (O={CacheOperationId} K={CacheKey}): [DC] an error occurred while " + actionDescription, _options.CacheName, _options.InstanceId, operationId, key); } - private static readonly MethodInfo __methodInfoSetEntryAsyncOpenGeneric = typeof(DistributedCacheAccessor).GetMethod(nameof(SetEntryAsync), BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - public async ValueTask SetEntryUntypedAsync(string operationId, string key, FusionCacheMemoryEntry memoryEntry, FusionCacheEntryOptions options, bool isBackground, CancellationToken token) { try @@ -130,7 +132,7 @@ public async ValueTask SetEntryUntypedAsync(string operationId, string key if (memoryEntry is null) return false; - var methodInfo = __methodInfoSetEntryAsyncOpenGeneric.MakeGenericMethod(memoryEntry.ValueType); + var methodInfo = __methodInfoSetEntryAsyncCache.GetOrAdd(memoryEntry.ValueType, x => __methodInfoSetEntryAsyncOpenGeneric.MakeGenericMethod(x)); // SIGNATURE PARAMS: string operationId, string key, IFusionCacheEntry entry, FusionCacheEntryOptions options, bool isBackground, CancellationToken token return await ((ValueTask)methodInfo.Invoke(this, new object[] { operationId, key, memoryEntry, options, isBackground, token })).ConfigureAwait(false);