diff options
Diffstat (limited to 'lib/VNLib.Plugins.Extensions.VNCache')
-rw-r--r-- | lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ICacheExpirationStrategy.cs | 2 | ||||
-rw-r--r-- | lib/VNLib.Plugins.Extensions.VNCache/src/MemoryCache.cs | 30 | ||||
-rw-r--r-- | lib/VNLib.Plugins.Extensions.VNCache/src/MemoryCacheConfig.cs | 48 | ||||
-rw-r--r-- | lib/VNLib.Plugins.Extensions.VNCache/src/MemoryCacheOperator.cs (renamed from lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/IExpirableCacheEntity.cs) | 37 | ||||
-rw-r--r-- | lib/VNLib.Plugins.Extensions.VNCache/src/RemoteBackedMemoryCache.cs | 35 | ||||
-rw-r--r-- | lib/VNLib.Plugins.Extensions.VNCache/src/RemoteCacheOperator.cs | 88 | ||||
-rw-r--r-- | lib/VNLib.Plugins.Extensions.VNCache/src/VnCacheClient.cs | 28 | ||||
-rw-r--r-- | lib/VNLib.Plugins.Extensions.VNCache/src/VnCacheClientConfig.cs | 104 | ||||
-rw-r--r-- | lib/VNLib.Plugins.Extensions.VNCache/src/VnGlobalCache.cs | 74 |
9 files changed, 405 insertions, 41 deletions
diff --git a/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ICacheExpirationStrategy.cs b/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ICacheExpirationStrategy.cs index f9ff54c..299834b 100644 --- a/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ICacheExpirationStrategy.cs +++ b/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ICacheExpirationStrategy.cs @@ -42,7 +42,7 @@ namespace VNLib.Plugins.Extensions.VNCache.DataModel /// </summary> /// <typeparam name="T"></typeparam> /// <param name="expired"></param> - void OnExpired<T>(T expired) where T : IExpirableCacheEntity; + void OnExpired<T>(T expired); } } diff --git a/lib/VNLib.Plugins.Extensions.VNCache/src/MemoryCache.cs b/lib/VNLib.Plugins.Extensions.VNCache/src/MemoryCache.cs index 92d7048..a62b5db 100644 --- a/lib/VNLib.Plugins.Extensions.VNCache/src/MemoryCache.cs +++ b/lib/VNLib.Plugins.Extensions.VNCache/src/MemoryCache.cs @@ -48,7 +48,7 @@ namespace VNLib.Plugins.Extensions.VNCache | Table Size: {ts} | Bucket Size: {bs} | Max Objects: {obj} - | Memory Estimations: + | Max Memory Estimations: | 4K blocks: {4k}Mb | 8K blocks: {8k}Mb | 16K blocks: {16K}Mb @@ -61,17 +61,29 @@ namespace VNLib.Plugins.Extensions.VNCache private readonly IUnmangedHeap _bufferHeap; public MemoryCache(PluginBase pbase, IConfigScope config) + :this( + config[VNCacheExtensions.MEMORY_CACHE_CONFIG_KEY].Deserialize<MemoryCacheConfig>()!, + pbase.IsDebug(), + pbase.Log + ) { - //Get nested memory cache config - MemoryCacheConfig memCacheConfig = config[VNCacheExtensions.MEMORY_CACHE_CONFIG_KEY].Deserialize<MemoryCacheConfig>()!; + } + + public MemoryCache(MemoryCacheConfig config):this(config, false, null) + {} + + private MemoryCache(MemoryCacheConfig config, bool isDebug, ILogProvider? log) + { + //Validate config + config.Validate(); - if (pbase.IsDebug()) + if (isDebug) { //Use the debug heap IUnmangedHeap newHeap = MemoryUtil.InitializeNewHeapForProcess(); //Wrap in diag heap - _bufferHeap = new TrackedHeapWrapper(newHeap); + _bufferHeap = new TrackedHeapWrapper(newHeap); } else { @@ -80,7 +92,7 @@ namespace VNLib.Plugins.Extensions.VNCache } //Setup cache table - _memCache = new BlobCacheTable(memCacheConfig.TableSize, memCacheConfig.BucketSize, _bufferHeap, null); + _memCache = new BlobCacheTable(config.TableSize, config.BucketSize, _bufferHeap, null); /* * Default to json serialization by using the default @@ -91,10 +103,10 @@ namespace VNLib.Plugins.Extensions.VNCache _serialzer = defaultSerializer; _deserialzer = defaultSerializer; - PrintDebug(pbase.Log, memCacheConfig); + PrintDebug(log, config); } - private static void PrintDebug(ILogProvider log, MemoryCacheConfig config) + private static void PrintDebug(ILogProvider? log, MemoryCacheConfig config) { long maxObjects = config.BucketSize * config.TableSize; @@ -102,7 +114,7 @@ namespace VNLib.Plugins.Extensions.VNCache long size8kMb = (maxObjects * 8128)/MB_DIVISOR; long size16kMb = (maxObjects * 16384)/MB_DIVISOR; - log.Debug(DEBUG_TEMPLATE, config.TableSize, config.BucketSize, maxObjects, size4kMb, size8kMb, size16kMb); + log?.Debug(DEBUG_TEMPLATE, config.TableSize, config.BucketSize, maxObjects, size4kMb, size8kMb, size16kMb); } ///<inheritdoc/> diff --git a/lib/VNLib.Plugins.Extensions.VNCache/src/MemoryCacheConfig.cs b/lib/VNLib.Plugins.Extensions.VNCache/src/MemoryCacheConfig.cs index bcd821b..f34ae91 100644 --- a/lib/VNLib.Plugins.Extensions.VNCache/src/MemoryCacheConfig.cs +++ b/lib/VNLib.Plugins.Extensions.VNCache/src/MemoryCacheConfig.cs @@ -25,24 +25,41 @@ using System; using System.Text.Json.Serialization; +using VNLib.Plugins.Extensions.Loading; + namespace VNLib.Plugins.Extensions.VNCache { - internal sealed class MemoryCacheConfig : ICacheRefreshPolicy + /// <summary> + /// Memorycache configuration object. Json-(de)serializable + /// </summary> + public sealed class MemoryCacheConfig : ICacheRefreshPolicy, IOnConfigValidation { + /// <summary> + /// The number of buckets within the cache table + /// </summary> [JsonPropertyName("buckets")] public uint TableSize { get; set; } = 10; + /// <summary> + /// The number of cache entries within each bucket + /// </summary> [JsonPropertyName("bucket_size")] public uint BucketSize { get; set; } = 5000; + /// <summary> + /// The maxium size (in bytes) of each cache entry within any bucket + /// </summary> [JsonPropertyName("max_object_size")] public uint MaxBlobSize { get; set; } = 16 * 1024; [JsonIgnore] public TimeSpan MaxCacheAge { get; set; } = TimeSpan.FromMinutes(1); + /// <summary> + /// When refresh intervals are configured, The maxium cache entry age in seconds. + /// </summary> [JsonPropertyName("max_age_sec")] - public uint MaxAgeSec + public uint MaxAgeSeconds { get => (uint)MaxCacheAge.TotalSeconds; set => MaxCacheAge = TimeSpan.FromSeconds(value); @@ -50,16 +67,37 @@ namespace VNLib.Plugins.Extensions.VNCache /* * Default disable cache */ + [JsonIgnore] public TimeSpan RefreshInterval { get; set; } = TimeSpan.Zero; + /// <summary> + /// The time (in seconds) a cache entry refresh interval will occur + /// if scheduled on a plugin + /// </summary> [JsonPropertyName("refresh_interval_sec")] - public uint RefreshSec + public uint RefreshIntervalSeconds { get => (uint)RefreshInterval.TotalSeconds; set => RefreshInterval = TimeSpan.FromSeconds(value); } - [JsonPropertyName("write_through")] - public bool WriteThrough { get; set; } = true; + ///<inheritdoc/> + public void Validate() + { + if(TableSize == 0) + { + throw new ArgumentException("You must specify a cache bucket table size", "buckets"); + } + + if(BucketSize == 0) + { + throw new ArgumentException("You must specify the maxium number of entires allowed in each bucket ", "bucket_size"); + } + + if(MaxBlobSize < 16) + { + throw new ArgumentException("You must configure a maximum object size", "max_object_size"); + } + } } }
\ No newline at end of file diff --git a/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/IExpirableCacheEntity.cs b/lib/VNLib.Plugins.Extensions.VNCache/src/MemoryCacheOperator.cs index a47d3ca..9791068 100644 --- a/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/IExpirableCacheEntity.cs +++ b/lib/VNLib.Plugins.Extensions.VNCache/src/MemoryCacheOperator.cs @@ -3,10 +3,10 @@ * * Library: VNLib * Package: VNLib.Plugins.Extensions.VNCache -* File: IExpirableCacheEntity.cs +* File: VnGlobalCache.cs * -* IExpirableCacheEntity.cs is part of VNLib.Plugins.Extensions.VNCache -* which is part of the larger VNLib collection of libraries and utilities. +* VnGlobalCache.cs is part of VNLib.Plugins.Extensions.VNCache which is part of the larger +* VNLib collection of libraries and utilities. * * VNLib.Plugins.Extensions.VNCache is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -22,18 +22,33 @@ * along with this program. If not, see https://www.gnu.org/licenses/. */ -namespace VNLib.Plugins.Extensions.VNCache.DataModel +using VNLib.Data.Caching; +using VNLib.Utils; + +namespace VNLib.Plugins.Extensions.VNCache { /// <summary> - /// A cache entity that has a controllable expiration + /// A disposable memory cache operator handle. When cache use is complete, you should + /// dispose this handle. You may want to schedule it for cleanup on a <see cref="PluginBase"/> /// </summary> - public interface IExpirableCacheEntity : ICacheEntity + public sealed class MemoryCacheOperator : VnDisposeable { + private readonly MemoryCache _cache; + + internal MemoryCacheOperator(MemoryCache cache) + { + _cache = cache; + } + /// <summary> - /// A serializable value set by the cache subsystem to - /// handle stale cache entires + /// The configured global cache instance /// </summary> - long Expires { get; set; } + public IGlobalCacheProvider Cache => _cache; + + ///<inheritdoc/> + protected override void Free() + { + _cache.Dispose(); + } } - -} +}
\ No newline at end of file diff --git a/lib/VNLib.Plugins.Extensions.VNCache/src/RemoteBackedMemoryCache.cs b/lib/VNLib.Plugins.Extensions.VNCache/src/RemoteBackedMemoryCache.cs index fb0e9e2..ffe9108 100644 --- a/lib/VNLib.Plugins.Extensions.VNCache/src/RemoteBackedMemoryCache.cs +++ b/lib/VNLib.Plugins.Extensions.VNCache/src/RemoteBackedMemoryCache.cs @@ -42,6 +42,16 @@ using VNLib.Plugins.Extensions.Loading.Events; namespace VNLib.Plugins.Extensions.VNCache { + /* + * A combinaed cache object that uses the blob cache data structures + * from the ObjectCache server library to implement similar memory cache + * features. All update operations are write-through operations, and a timer + * may be scheduled to refresh memorycache against the server (eventually) + * + * Memory cache is destroyed when the connection to the cache server is + * lost or is exiting + */ + [ConfigurationName(VNCacheExtensions.CACHE_CONFIG_KEY)] internal sealed class RemoteBackedMemoryCache : VnCacheClient, IIntervalScheduleable { @@ -53,10 +63,14 @@ namespace VNLib.Plugins.Extensions.VNCache public RemoteBackedMemoryCache(PluginBase plugin, IConfigScope config) : base(plugin, config) { //Get nested memory cache config - MemoryCacheConfig memCacheConfig = config[VNCacheExtensions.MEMORY_CACHE_CONFIG_KEY].Deserialize<MemoryCacheConfig>()!; + MemoryCacheConfig? memCacheConfig = config[VNCacheExtensions.MEMORY_CACHE_CONFIG_KEY].Deserialize<MemoryCacheConfig>(); + + _ = memCacheConfig ?? throw new ArgumentNullException(VNCacheExtensions.MEMORY_CACHE_CONFIG_KEY, "Missing required memory configuration variable"); + + memCacheConfig.Validate(); //Setup cache table - _memCache = new BlobCacheTable(memCacheConfig.TableSize, memCacheConfig.BucketSize, Client.Config.BufferHeap ?? MemoryUtil.Shared, null); + _memCache = new BlobCacheTable(memCacheConfig.TableSize, memCacheConfig.BucketSize, Client.Config.BufferHeap, null); _cacheConfig = memCacheConfig; @@ -76,6 +90,23 @@ namespace VNLib.Plugins.Extensions.VNCache } } + public RemoteBackedMemoryCache(VnCacheClientConfig client, MemoryCacheConfig memCache, ILogProvider? debugLog):base(client, debugLog) + { + //Setup mem cache table + _memCache = new BlobCacheTable(memCache.TableSize, memCache.BucketSize, Client.Config.BufferHeap, null); + + _cacheConfig = memCache; + + /* + * Default to json serialization by using the default + * serializer and JSON options + */ + + JsonCacheObjectSerializer defaultSerializer = new(); + _serialzer = defaultSerializer; + _deserialzer = defaultSerializer; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void CheckConnected() { diff --git a/lib/VNLib.Plugins.Extensions.VNCache/src/RemoteCacheOperator.cs b/lib/VNLib.Plugins.Extensions.VNCache/src/RemoteCacheOperator.cs new file mode 100644 index 0000000..1f0742d --- /dev/null +++ b/lib/VNLib.Plugins.Extensions.VNCache/src/RemoteCacheOperator.cs @@ -0,0 +1,88 @@ +/* +* Copyright (c) 2023 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.Plugins.Extensions.VNCache +* File: RemoteCacheOperator.cs +* +* RemoteCacheOperator.cs is part of VNLib.Plugins.Extensions.VNCache which is +* part of the larger VNLib collection of libraries and utilities. +* +* VNLib.Plugins.Extensions.VNCache is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* VNLib.Plugins.Extensions.VNCache is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +*/ + +using System; +using System.Threading; +using System.Threading.Tasks; + +using VNLib.Data.Caching; +using VNLib.Plugins.Extensions.Loading; +using VNLib.Utils.Logging; + +namespace VNLib.Plugins.Extensions.VNCache +{ + /// <summary> + /// Represents a handle to a VNCache cache client, that exposes a cancellable + /// <see cref="IAsyncBackgroundWork"/> to run inside a <see cref="PluginBase"/> + /// or standlone in your own background work handler + /// </summary> + /// <remarks> + /// The background work method must be sheduled for the cache client to be + /// connected to the backing store + /// </remarks> + public sealed class RemoteCacheOperator : IAsyncBackgroundWork, IAsyncConfigurable + { + private readonly VnCacheClient _client; + private CancellationTokenSource? _tokenSource; + + internal RemoteCacheOperator(VnCacheClient client) + { + _client = client; + } + + /// <summary> + /// The configured global cache instance + /// </summary> + public IGlobalCacheProvider Cache => _client; + + ///<inheritdoc/> + ///<exception cref="ArgumentNullException"></exception> + public async Task DoWorkAsync(ILogProvider pluginLog, CancellationToken exitToken) + { + _ = pluginLog ?? throw new ArgumentNullException(nameof(pluginLog)); + + //Create cts linked to the exit token to allow user cancellation of the listener + using(_tokenSource = CancellationTokenSource.CreateLinkedTokenSource(exitToken)) + { + //Do work with linked source + await _client.DoWorkAsync(pluginLog, _tokenSource.Token) + .ConfigureAwait(false); + } + + //Remove cts + _tokenSource = null; + } + + /// <summary> + /// Cancels the background cache client listener + /// </summary> + public void CancelListener() => _tokenSource?.Cancel(); + + ///<inheritdoc/> + public Task ConfigureServiceAsync(PluginBase plugin) + { + return _client.ConfigureServiceAsync(plugin); + } + } +}
\ No newline at end of file diff --git a/lib/VNLib.Plugins.Extensions.VNCache/src/VnCacheClient.cs b/lib/VNLib.Plugins.Extensions.VNCache/src/VnCacheClient.cs index 1e1b74c..eea2de5 100644 --- a/lib/VNLib.Plugins.Extensions.VNCache/src/VnCacheClient.cs +++ b/lib/VNLib.Plugins.Extensions.VNCache/src/VnCacheClient.cs @@ -33,7 +33,6 @@ using System.Security.Cryptography; using VNLib.Utils.Memory; using VNLib.Utils.Logging; -using VNLib.Utils.Extensions; using VNLib.Hashing.IdentityUtility; using VNLib.Data.Caching; using VNLib.Data.Caching.Extensions; @@ -41,7 +40,6 @@ using VNLib.Data.Caching.ObjectCache; using VNLib.Net.Messaging.FBM.Client; using VNLib.Plugins.Extensions.Loading; - namespace VNLib.Plugins.Extensions.VNCache { public interface ICacheRefreshPolicy @@ -57,7 +55,7 @@ namespace VNLib.Plugins.Extensions.VNCache [ConfigurationName(VNCacheExtensions.CACHE_CONFIG_KEY)] internal class VnCacheClient : IGlobalCacheProvider, IAsyncBackgroundWork, IAsyncConfigurable { - private readonly TimeSpan RetryInterval; + private readonly VnCacheClientConfig _config; /// <summary> /// The internal client @@ -70,20 +68,23 @@ namespace VNLib.Plugins.Extensions.VNCache public bool IsConnected { get; private set; } public VnCacheClient(PluginBase pbase, IConfigScope config) + :this( + config.Deserialze<VnCacheClientConfig>(), + pbase.IsDebug() ? pbase.Log : null + ) + {} + + public VnCacheClient(VnCacheClientConfig config, ILogProvider? debugLog) { - //Get required configuration variables - int maxMessageSize = config["max_message_size"].GetInt32(); - string? brokerAddress = config["broker_address"].GetString() ?? throw new KeyNotFoundException("Missing required configuration variable broker_address"); - RetryInterval = config["retry_interval_sec"].GetTimeSpan(TimeParseType.Seconds); - TimeSpan timeout = config["request_timeout_sec"].GetTimeSpan(TimeParseType.Seconds); + //Validate config + (config as IOnConfigValidation).Validate(); - Uri brokerUri = new(brokerAddress); + _config = config; - //Setup debug log if the plugin is in debug mode - ILogProvider? debugLog = pbase.IsDebug() ? pbase.Log : null; + Uri brokerUri = new(config.BrokerAddress); //Init the client with default settings - FBMClientConfig conf = FBMDataCacheExtensions.GetDefaultConfig(MemoryUtil.Shared, maxMessageSize, timeout, debugLog); + FBMClientConfig conf = FBMDataCacheExtensions.GetDefaultConfig(MemoryUtil.Shared, config.MaxMessageSize!.Value, config.RequestTimeout, debugLog); Client = new(conf); @@ -92,6 +93,7 @@ namespace VNLib.Plugins.Extensions.VNCache .WithBroker(brokerUri) .WithTls(brokerUri.Scheme == Uri.UriSchemeHttps); } + public virtual async Task ConfigureServiceAsync(PluginBase plugin) { @@ -152,7 +154,7 @@ namespace VNLib.Plugins.Extensions.VNCache if (servers?.Length == 0) { pluginLog.Warn("No cluster nodes found, retrying"); - await Task.Delay(RetryInterval, exitToken); + await Task.Delay(_config.RetryInterval, exitToken); continue; } diff --git a/lib/VNLib.Plugins.Extensions.VNCache/src/VnCacheClientConfig.cs b/lib/VNLib.Plugins.Extensions.VNCache/src/VnCacheClientConfig.cs new file mode 100644 index 0000000..1d888ec --- /dev/null +++ b/lib/VNLib.Plugins.Extensions.VNCache/src/VnCacheClientConfig.cs @@ -0,0 +1,104 @@ +/* +* Copyright (c) 2023 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.Plugins.Extensions.VNCache +* File: VnCacheClientConfig.cs +* +* VnCacheClientConfig.cs is part of VNLib.Plugins.Extensions.VNCache which is part of the larger +* VNLib collection of libraries and utilities. +* +* VNLib.Plugins.Extensions.VNCache is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* VNLib.Plugins.Extensions.VNCache is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +*/ + +using System; +using System.Text.Json.Serialization; + +using VNLib.Plugins.Extensions.Loading; + +namespace VNLib.Plugins.Extensions.VNCache +{ + /// <summary> + /// Represents a remote VNCache client configuration + /// </summary> + public class VnCacheClientConfig : IOnConfigValidation + { + /// <summary> + /// The maximum size (in bytes) of messages sent to the + /// cache server. This value will be negotiated with the server + /// during a connection upgrade + /// </summary> + [JsonPropertyName("max_message_size")] + public int? MaxMessageSize { get; set; } + + /// <summary> + /// The broker server address + /// </summary> + [JsonPropertyName("broker_address")] + public string? BrokerAddress { get; set; } + + /// <summary> + /// The time (in seconds) to randomly delay polling the broker server + /// for available servers + /// </summary> + [JsonPropertyName("retry_interval_sec")] + public int? RetryIntervalSeconds { get; set; } + + /// <summary> + /// The maximum time (in seconds) for FBM cache operations are allowed + /// to take before timing out. + /// </summary> + /// <remarks> + /// NOTE: You should set this value to something reasonable as FBM messages can + /// be lost and cause deadlocks if your cache implementation does not rely on + /// CancellationTokens + /// </remarks> + [JsonPropertyName("request_timeout_sec")] + public int? RequestTimeoutSeconds { get; set; } + + /// <summary> + /// Retry interval in a timespan + /// </summary> + internal TimeSpan RetryInterval => TimeSpan.FromSeconds(RetryIntervalSeconds!.Value); + + /// <summary> + /// FBM Request timeout + /// </summary> + internal TimeSpan RequestTimeout => TimeSpan.FromSeconds(RequestTimeoutSeconds!.Value); + + void IOnConfigValidation.Validate() + { + if (!MaxMessageSize.HasValue || MaxMessageSize.Value < 1) + { + throw new ArgumentException("Your maxium message size should be a reasonable value greater than 0", "max_message_size"); + } + + if (!RetryIntervalSeconds.HasValue || RetryIntervalSeconds.Value < 1) + { + throw new ArgumentException("You must specify a retry interval period greater than 0", "retry_interval_sec"); + } + + //Allow a 0 timeout to disable timeouts, not recommended, but allowed + if(!RequestTimeoutSeconds.HasValue || RequestTimeoutSeconds.Value < 0) + { + throw new ArgumentException("You must specify a positive integer FBM message timoeut", "request_timeout_sec"); + } + + if(!Uri.TryCreate(BrokerAddress, UriKind.RelativeOrAbsolute, out _)) + { + throw new ArgumentException("You must specify a valid HTTP uri broker address", "broker_address"); + } + } + } +}
\ No newline at end of file diff --git a/lib/VNLib.Plugins.Extensions.VNCache/src/VnGlobalCache.cs b/lib/VNLib.Plugins.Extensions.VNCache/src/VnGlobalCache.cs index 3cdebe3..981786d 100644 --- a/lib/VNLib.Plugins.Extensions.VNCache/src/VnGlobalCache.cs +++ b/lib/VNLib.Plugins.Extensions.VNCache/src/VnGlobalCache.cs @@ -22,15 +22,18 @@ * along with this program. If not, see https://www.gnu.org/licenses/. */ +using System; using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using VNLib.Utils.Logging; using VNLib.Data.Caching; using VNLib.Plugins.Extensions.Loading; namespace VNLib.Plugins.Extensions.VNCache { + /// <summary> /// A wrapper to simplify a shared global cache client /// </summary> @@ -66,6 +69,77 @@ namespace VNLib.Plugins.Extensions.VNCache } } + + /// <summary> + /// Allows you to programatically create a remote-only VNCache instance + /// </summary> + /// <param name="config">The remote cache configuration, required for VNCache remote cache servers</param> + /// <param name="debugLog">An optional FBMClient debugging log provider, should be null unless debug logging is desired </param> + /// <returns>An opreator handle that can schedule the remote cache worker task</returns> + /// <exception cref="ArgumentNullException"></exception> + /// <remarks> + /// The returned <see cref="RemoteCacheOperator"/> implements the <see cref="IAsyncBackgroundWork"/> + /// interface and must be scheduled in order to maintain a connection with the remote cache store. + /// </remarks> + public static RemoteCacheOperator CreateRemoteCache(VnCacheClientConfig config, ILogProvider? debugLog = null) + { + _ = config ?? throw new ArgumentNullException(nameof(config)); + + //Init client + VnCacheClient client = new(config, debugLog); + + //Return single handle + return new(client); + } + + /// <summary> + /// Allows you to programtically create your own instance if a VNCache remote server backed + /// memory cache programatically. + /// </summary> + /// <param name="remote">The remote cache configuration, required for VNCache remote cache servers</param> + /// <param name="memory">The local memory backed configuration</param> + /// <param name="debugLog">An optional FBMClient debugging log provider, should be null unless debug logging is desired </param> + /// <returns>An opreator handle that can schedule the remote cache worker task</returns> + /// <exception cref="ArgumentNullException"></exception> + /// <remarks> + /// The returned <see cref="RemoteCacheOperator"/> implements the <see cref="IAsyncBackgroundWork"/> + /// interface and must be scheduled in order to maintain a connection with the remote cache store. The memory cache + /// resources are released when the worker task exits. + /// </remarks> + public static RemoteCacheOperator CreateRemoteBackedMemoryCache(VnCacheClientConfig remote, MemoryCacheConfig memory, ILogProvider? debugLog) + { + _ = remote ?? throw new ArgumentNullException(nameof(remote)); + _ = memory ?? throw new ArgumentNullException(nameof(memory)); + + //Init client + RemoteBackedMemoryCache client = new(remote, memory, debugLog); + + //Return single handle + return new(client); + } + + /// <summary> + /// Allows you to programatically create a memory only <see cref="IGlobalCacheProvider"/> + /// cache instance. + /// </summary> + /// <param name="config">The memory cache configuration</param> + /// <returns> + /// A <see cref="MemoryCacheOperator"/> handle that holds a ready-to use cache instance. + /// This operator must be disposed to release held resources. + /// </returns> + /// <exception cref="ArgumentNullException"></exception> + public static MemoryCacheOperator CreateMemoryCache(MemoryCacheConfig config) + { + _ = config ?? throw new ArgumentNullException(nameof(config)); + + //Init client + MemoryCache cache = new(config); + + //Return single handle + return new(cache); + } + + ///<inheritdoc/> public bool IsConnected => _client.IsConnected; |