From a866d831efc95900de2326f09531a54a65f18ea2 Mon Sep 17 00:00:00 2001 From: vnugent Date: Sat, 8 Apr 2023 16:43:02 -0400 Subject: Expose public configuration api --- .../src/DataModel/ICacheExpirationStrategy.cs | 2 +- .../src/DataModel/IExpirableCacheEntity.cs | 39 -------- .../src/MemoryCache.cs | 30 ++++-- .../src/MemoryCacheConfig.cs | 48 +++++++++- .../src/MemoryCacheOperator.cs | 54 +++++++++++ .../src/RemoteBackedMemoryCache.cs | 35 ++++++- .../src/RemoteCacheOperator.cs | 88 +++++++++++++++++ .../src/VnCacheClient.cs | 28 +++--- .../src/VnCacheClientConfig.cs | 104 +++++++++++++++++++++ .../src/VnGlobalCache.cs | 74 +++++++++++++++ 10 files changed, 433 insertions(+), 69 deletions(-) delete mode 100644 lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/IExpirableCacheEntity.cs create mode 100644 lib/VNLib.Plugins.Extensions.VNCache/src/MemoryCacheOperator.cs create mode 100644 lib/VNLib.Plugins.Extensions.VNCache/src/RemoteCacheOperator.cs create mode 100644 lib/VNLib.Plugins.Extensions.VNCache/src/VnCacheClientConfig.cs (limited to 'lib/VNLib.Plugins.Extensions.VNCache/src') 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 /// /// /// - void OnExpired(T expired) where T : IExpirableCacheEntity; + void OnExpired(T expired); } } diff --git a/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/IExpirableCacheEntity.cs b/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/IExpirableCacheEntity.cs deleted file mode 100644 index a47d3ca..0000000 --- a/lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/IExpirableCacheEntity.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright (c) 2023 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Plugins.Extensions.VNCache -* File: IExpirableCacheEntity.cs -* -* IExpirableCacheEntity.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/. -*/ - -namespace VNLib.Plugins.Extensions.VNCache.DataModel -{ - /// - /// A cache entity that has a controllable expiration - /// - public interface IExpirableCacheEntity : ICacheEntity - { - /// - /// A serializable value set by the cache subsystem to - /// handle stale cache entires - /// - long Expires { get; set; } - } - -} 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()!, + pbase.IsDebug(), + pbase.Log + ) { - //Get nested memory cache config - MemoryCacheConfig memCacheConfig = config[VNCacheExtensions.MEMORY_CACHE_CONFIG_KEY].Deserialize()!; + } + + 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); } /// 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 + /// + /// Memorycache configuration object. Json-(de)serializable + /// + public sealed class MemoryCacheConfig : ICacheRefreshPolicy, IOnConfigValidation { + /// + /// The number of buckets within the cache table + /// [JsonPropertyName("buckets")] public uint TableSize { get; set; } = 10; + /// + /// The number of cache entries within each bucket + /// [JsonPropertyName("bucket_size")] public uint BucketSize { get; set; } = 5000; + /// + /// The maxium size (in bytes) of each cache entry within any bucket + /// [JsonPropertyName("max_object_size")] public uint MaxBlobSize { get; set; } = 16 * 1024; [JsonIgnore] public TimeSpan MaxCacheAge { get; set; } = TimeSpan.FromMinutes(1); + /// + /// When refresh intervals are configured, The maxium cache entry age in seconds. + /// [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; + /// + /// The time (in seconds) a cache entry refresh interval will occur + /// if scheduled on a plugin + /// [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; + /// + 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/MemoryCacheOperator.cs b/lib/VNLib.Plugins.Extensions.VNCache/src/MemoryCacheOperator.cs new file mode 100644 index 0000000..9791068 --- /dev/null +++ b/lib/VNLib.Plugins.Extensions.VNCache/src/MemoryCacheOperator.cs @@ -0,0 +1,54 @@ +/* +* Copyright (c) 2023 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.Plugins.Extensions.VNCache +* File: VnGlobalCache.cs +* +* 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 +* 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 VNLib.Data.Caching; +using VNLib.Utils; + +namespace VNLib.Plugins.Extensions.VNCache +{ + /// + /// 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 + /// + public sealed class MemoryCacheOperator : VnDisposeable + { + private readonly MemoryCache _cache; + + internal MemoryCacheOperator(MemoryCache cache) + { + _cache = cache; + } + + /// + /// The configured global cache instance + /// + public IGlobalCacheProvider Cache => _cache; + + /// + 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? memCacheConfig = config[VNCacheExtensions.MEMORY_CACHE_CONFIG_KEY].Deserialize(); + + _ = 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 +{ + /// + /// Represents a handle to a VNCache cache client, that exposes a cancellable + /// to run inside a + /// or standlone in your own background work handler + /// + /// + /// The background work method must be sheduled for the cache client to be + /// connected to the backing store + /// + public sealed class RemoteCacheOperator : IAsyncBackgroundWork, IAsyncConfigurable + { + private readonly VnCacheClient _client; + private CancellationTokenSource? _tokenSource; + + internal RemoteCacheOperator(VnCacheClient client) + { + _client = client; + } + + /// + /// The configured global cache instance + /// + public IGlobalCacheProvider Cache => _client; + + /// + /// + 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; + } + + /// + /// Cancels the background cache client listener + /// + public void CancelListener() => _tokenSource?.Cancel(); + + /// + 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; /// /// 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(), + 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 +{ + /// + /// Represents a remote VNCache client configuration + /// + public class VnCacheClientConfig : IOnConfigValidation + { + /// + /// The maximum size (in bytes) of messages sent to the + /// cache server. This value will be negotiated with the server + /// during a connection upgrade + /// + [JsonPropertyName("max_message_size")] + public int? MaxMessageSize { get; set; } + + /// + /// The broker server address + /// + [JsonPropertyName("broker_address")] + public string? BrokerAddress { get; set; } + + /// + /// The time (in seconds) to randomly delay polling the broker server + /// for available servers + /// + [JsonPropertyName("retry_interval_sec")] + public int? RetryIntervalSeconds { get; set; } + + /// + /// The maximum time (in seconds) for FBM cache operations are allowed + /// to take before timing out. + /// + /// + /// 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 + /// + [JsonPropertyName("request_timeout_sec")] + public int? RequestTimeoutSeconds { get; set; } + + /// + /// Retry interval in a timespan + /// + internal TimeSpan RetryInterval => TimeSpan.FromSeconds(RetryIntervalSeconds!.Value); + + /// + /// FBM Request timeout + /// + 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 { + /// /// A wrapper to simplify a shared global cache client /// @@ -66,6 +69,77 @@ namespace VNLib.Plugins.Extensions.VNCache } } + + /// + /// Allows you to programatically create a remote-only VNCache instance + /// + /// The remote cache configuration, required for VNCache remote cache servers + /// An optional FBMClient debugging log provider, should be null unless debug logging is desired + /// An opreator handle that can schedule the remote cache worker task + /// + /// + /// The returned implements the + /// interface and must be scheduled in order to maintain a connection with the remote cache store. + /// + 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); + } + + /// + /// Allows you to programtically create your own instance if a VNCache remote server backed + /// memory cache programatically. + /// + /// The remote cache configuration, required for VNCache remote cache servers + /// The local memory backed configuration + /// An optional FBMClient debugging log provider, should be null unless debug logging is desired + /// An opreator handle that can schedule the remote cache worker task + /// + /// + /// The returned implements the + /// 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. + /// + 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); + } + + /// + /// Allows you to programatically create a memory only + /// cache instance. + /// + /// The memory cache configuration + /// + /// A handle that holds a ready-to use cache instance. + /// This operator must be disposed to release held resources. + /// + /// + public static MemoryCacheOperator CreateMemoryCache(MemoryCacheConfig config) + { + _ = config ?? throw new ArgumentNullException(nameof(config)); + + //Init client + MemoryCache cache = new(config); + + //Return single handle + return new(cache); + } + + /// public bool IsConnected => _client.IsConnected; -- cgit