Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Key-dependent cache entry options #367

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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