aboutsummaryrefslogtreecommitdiff
path: root/lib/VNLib.Plugins.Extensions.VNCache
diff options
context:
space:
mode:
Diffstat (limited to 'lib/VNLib.Plugins.Extensions.VNCache')
-rw-r--r--lib/VNLib.Plugins.Extensions.VNCache/src/DataModel/ICacheExpirationStrategy.cs2
-rw-r--r--lib/VNLib.Plugins.Extensions.VNCache/src/MemoryCache.cs30
-rw-r--r--lib/VNLib.Plugins.Extensions.VNCache/src/MemoryCacheConfig.cs48
-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.cs35
-rw-r--r--lib/VNLib.Plugins.Extensions.VNCache/src/RemoteCacheOperator.cs88
-rw-r--r--lib/VNLib.Plugins.Extensions.VNCache/src/VnCacheClient.cs28
-rw-r--r--lib/VNLib.Plugins.Extensions.VNCache/src/VnCacheClientConfig.cs104
-rw-r--r--lib/VNLib.Plugins.Extensions.VNCache/src/VnGlobalCache.cs74
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;