Skip to content

Commit

Permalink
Key-dependent cache entry options
Browse files Browse the repository at this point in the history
  • Loading branch information
gleb-osokin committed Jan 28, 2025
1 parent 707b594 commit b36f349
Show file tree
Hide file tree
Showing 30 changed files with 710 additions and 174 deletions.
1 change: 1 addition & 0 deletions docs/Options.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ All these informations are fully available via IntelliSense, auto-suggest or sim
| ---: | :---: | :---: | :--- |
| `CacheName` | `string` | `"FusionCache"` | The name of the cache: it can be used for identification, and in a multi-node scenario it is typically shared between nodes to create a logical association. |
| `DefaultEntryOptions` | `FusionCacheEntryOptions` | *see below* | This is the default entry options object that will be used when one is not passed to each method call that need one, and as a starting point when duplicating one, either via the explicit `FusionCache.CreateOptions(...)` method or in one of the *overloads* of each *core method*. |
| `KeyDependentEntryOptions` | `KeyDependentFusionCacheEntryOptions[]` | `[]` | entry options overrides for specific key prefixes.
| `DistributedCacheCircuitBreakerDuration` | `TimeSpan` | `none` | The duration of the circuit-breaker used when working with the distributed cache. |
| `CacheKeyPrefix` | `string?` | `null` | A prefix that will be added to each cache key for each call: it can be useful when working with multiple named caches. With the builder it can be set using the `WithCacheKeyPrefix(...)` method. |
| `DistributedCacheKeyModifierMode` | `CacheKeyModifierMode` | `Prefix` | Specify the mode in which cache key will be changed for the distributed cache (eg: to specify the wire format version). |
Expand Down
26 changes: 22 additions & 4 deletions src/ZiggyCreatures.FusionCache/FusionCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public sealed partial class FusionCache
private readonly ILogger<FusionCache>? _logger;
internal readonly FusionCacheEntryOptions _defaultEntryOptions;
internal readonly FusionCacheEntryOptions _tryUpdateEntryOptions;
private readonly IKeyedFusionCacheEntryOptionsProvider _keyDependentEntryOptionsProvider;

// MEMORY LOCKER
private IFusionCacheMemoryLocker _memoryLocker;
Expand Down Expand Up @@ -85,7 +86,13 @@ public sealed partial class FusionCache
/// <param name="memoryCache">The <see cref="IMemoryCache"/> instance to use. If null, one will be automatically created and managed.</param>
/// <param name="logger">The <see cref="ILogger{TCategoryName}"/> instance to use. If null, logging will be completely disabled.</param>
/// <param name="memoryLocker">The <see cref="IFusionCacheMemoryLocker"/> instance to use. If <see langword="null"/>, a standard one will be automatically created and managed.</param>
public FusionCache(IOptions<FusionCacheOptions> optionsAccessor, IMemoryCache? memoryCache = null, ILogger<FusionCache>? logger = null, IFusionCacheMemoryLocker? memoryLocker = null)
/// <param name="keyDependentEntryOptionsProvider">The <see cref="IKeyedFusionCacheEntryOptionsProvider"/> instance to use for key-dependent entry options. If <see langwork="null"/>, a default <see cref="KeyPrefixBasedEntryOptionsProvider"/> will be used.</param>
public FusionCache(
IOptions<FusionCacheOptions> optionsAccessor,
IMemoryCache? memoryCache = null,
ILogger<FusionCache>? logger = null,
IFusionCacheMemoryLocker? memoryLocker = null,
IKeyedFusionCacheEntryOptionsProvider? keyDependentEntryOptionsProvider = null)
{
if (optionsAccessor is null)
throw new ArgumentNullException(nameof(optionsAccessor));
Expand All @@ -97,6 +104,8 @@ public FusionCache(IOptions<FusionCacheOptions> optionsAccessor, IMemoryCache? m
_options = _options.Duplicate();

_defaultEntryOptions = _options.DefaultEntryOptions;
_keyDependentEntryOptionsProvider = keyDependentEntryOptionsProvider ??
new KeyPrefixBasedEntryOptionsProvider(_options);

// TRY UPDATE OPTIONS
_tryUpdateEntryOptions ??= new FusionCacheEntryOptions()
Expand Down Expand Up @@ -239,6 +248,17 @@ public FusionCacheEntryOptions CreateEntryOptions(Action<FusionCacheEntryOptions
return res;
}

/// <inheritdoc/>
public FusionCacheEntryOptions CreateEntryOptions(string key, Action<FusionCacheEntryOptions>? setupAction = null, TimeSpan? duration = null)
{
var res = GetEntryOptions(key).Duplicate(duration);
setupAction?.Invoke(res);
return res;
}

private FusionCacheEntryOptions GetEntryOptions(string key) =>
_keyDependentEntryOptionsProvider.GetEntryOptions(key) ?? _defaultEntryOptions;

private static void ValidateCacheKey(string key)
{
if (key is null)
Expand Down Expand Up @@ -1086,10 +1106,8 @@ private void UpdateAdaptiveOptions<TValue>(FusionCacheFactoryExecutionContext<TV
}
}

internal TValue GetValueFromMemoryEntry<TValue>(string operationId, string key, IFusionCacheMemoryEntry entry, FusionCacheEntryOptions? options)
internal TValue GetValueFromMemoryEntry<TValue>(string operationId, string key, IFusionCacheMemoryEntry entry, FusionCacheEntryOptions options)
{
options ??= _defaultEntryOptions;

if (options.EnableAutoClone == false)
return entry.GetValue<TValue>();

Expand Down
22 changes: 22 additions & 0 deletions src/ZiggyCreatures.FusionCache/FusionCacheBuilderExtMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using ZiggyCreatures.Caching.Fusion.Backplane;
using ZiggyCreatures.Caching.Fusion.Internals.Builder;
using ZiggyCreatures.Caching.Fusion.Locking;
using ZiggyCreatures.Caching.Fusion.MicrosoftHybridCache;
using ZiggyCreatures.Caching.Fusion.Plugins;
Expand Down Expand Up @@ -729,6 +730,27 @@ public static IFusionCacheBuilder WithMemoryLocker(this IFusionCacheBuilder buil
return builder;
}

/// <summary>
/// Specify custom configuration for <see cref="IKeyedFusionCacheEntryOptionsProvider" /> registration. />
/// </summary>
/// <param name="builder">The <see cref="IFusionCacheBuilder" /> to act upon.</param>
/// <param name="config">The configuration action to adjust the registration.</param>
/// <returns>The <see cref="IFusionCacheBuilder"/> so that additional calls can be chained.</returns>
public static IFusionCacheBuilder WithKeyDependentEntryOptionsProvider(
this IFusionCacheBuilder builder,
Action<CustomServiceRegistration<IKeyedFusionCacheEntryOptionsProvider>> config)
{
var registration = new CustomServiceRegistration<IKeyedFusionCacheEntryOptionsProvider>
{
ThrowIfMissing = true
};

config(registration);

builder.KeyDependentEntryOptionsProvider = registration;
return builder;
}

#endregion

#region SERIALIZER
Expand Down
Loading

0 comments on commit b36f349

Please sign in to comment.