aboutsummaryrefslogtreecommitdiff
path: root/lib/VNLib.Data.Caching
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2023-11-02 01:50:05 -0400
committerLibravatar vnugent <public@vaughnnugent.com>2023-11-02 01:50:05 -0400
commitd2d812213b99ee17f9433f81871b694c4053ff23 (patch)
tree11a1106602112c134e65bf197ef701d1b8d63b67 /lib/VNLib.Data.Caching
parent483c014b938e2d55ea7c89b67f6d19ba2c2d5b5e (diff)
also carried away
Diffstat (limited to 'lib/VNLib.Data.Caching')
-rw-r--r--lib/VNLib.Data.Caching/src/ClientExtensions.cs297
-rw-r--r--lib/VNLib.Data.Caching/src/GlobalCacheExtensions.cs82
-rw-r--r--lib/VNLib.Data.Caching/src/ICacheObjectDeserializer.cs (renamed from lib/VNLib.Data.Caching/src/ICacheObjectDeserialzer.cs)6
-rw-r--r--lib/VNLib.Data.Caching/src/ICacheObjectSerializer.cs (renamed from lib/VNLib.Data.Caching/src/ICacheObjectSerialzer.cs)6
-rw-r--r--lib/VNLib.Data.Caching/src/IGlobalCacheProvider.cs43
-rw-r--r--lib/VNLib.Data.Caching/src/JsonCacheObjectSerializer.cs6
-rw-r--r--lib/VNLib.Data.Caching/src/WaitForChangeResult.cs23
7 files changed, 309 insertions, 154 deletions
diff --git a/lib/VNLib.Data.Caching/src/ClientExtensions.cs b/lib/VNLib.Data.Caching/src/ClientExtensions.cs
index 946c9b5..a2ec27d 100644
--- a/lib/VNLib.Data.Caching/src/ClientExtensions.cs
+++ b/lib/VNLib.Data.Caching/src/ClientExtensions.cs
@@ -24,7 +24,6 @@
using System;
using System.Linq;
-using System.Buffers;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
@@ -52,26 +51,7 @@ namespace VNLib.Data.Caching
private static void LogDebug(this FBMClient client, string message, params object?[] args)
{
client.Config.DebugLog?.Debug($"[CACHE] : {message}", args);
- }
-
- /// <summary>
- /// Gets an object from the server if it exists, and uses the default serialzer to
- /// recover the object
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="client"></param>
- /// <param name="objectId">The id of the object to get</param>
- /// <param name="cancellationToken">A token to cancel the operation</param>
- /// <returns>A task that completes to return the results of the response payload</returns>
- /// <exception cref="JsonException"></exception>
- /// <exception cref="OutOfMemoryException"></exception>
- /// <exception cref="InvalidStatusException"></exception>
- /// <exception cref="ObjectDisposedException"></exception>
- /// <exception cref="InvalidResponseException"></exception>
- public static Task<T?> GetObjectAsync<T>(this FBMClient client, string objectId, CancellationToken cancellationToken = default)
- {
- return GetObjectAsync<T>(client, objectId, DefaultSerializer, cancellationToken);
- }
+ }
/// <summary>
/// Updates the state of the object, and optionally updates the ID of the object. The data
@@ -95,37 +75,58 @@ namespace VNLib.Data.Caching
{
//Use the default/json serialzer if not specified
return AddOrUpdateObjectAsync(client, objectId, newId, data, DefaultSerializer, cancellationToken);
- }
+ }
/// <summary>
- /// Gets an object from the server if it exists
+ /// Updates the state of the object, and optionally updates the ID of the object. The data
+ /// parameter is serialized, buffered, and streamed to the remote server
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="client"></param>
- /// <param name="objectId">The id of the object to get</param>
+ /// <param name="objectId">The id of the object to update or replace</param>
+ /// <param name="newId">An optional parameter to specify a new ID for the old object</param>
+ /// <param name="data">The payload data to serialize and set as the data state of the session</param>
+ /// <param name="serializer">The custom serializer to used to serialze the object to binary</param>
/// <param name="cancellationToken">A token to cancel the operation</param>
- /// <param name="deserialzer">The custom data deserialzer used to deserialze the binary cache result</param>
- /// <returns>A task that completes to return the results of the response payload</returns>
+ /// <returns>A task that resolves when the server responds</returns>
+ /// <exception cref="OutOfMemoryException"></exception>
/// <exception cref="InvalidStatusException"></exception>
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="InvalidResponseException"></exception>
- public static async Task<T?> GetObjectAsync<T>(this FBMClient client, string objectId, ICacheObjectDeserialzer deserialzer, CancellationToken cancellationToken = default)
+ /// <exception cref="MessageTooLargeException"></exception>
+ /// <exception cref="ObjectNotFoundException"></exception>
+ public static async Task AddOrUpdateObjectAsync<T>(
+ this FBMClient client,
+ string objectId,
+ string? newId,
+ T data,
+ ICacheObjectSerializer serializer,
+ CancellationToken cancellationToken = default)
{
_ = client ?? throw new ArgumentNullException(nameof(client));
- _ = deserialzer ?? throw new ArgumentNullException(nameof(deserialzer));
+ _ = serializer ?? throw new ArgumentNullException(nameof(serializer));
- client.LogDebug("Getting object {id}", objectId);
+ client.LogDebug("Updating object {id}, newid {nid}", objectId, newId);
//Rent a new request
FBMRequest request = client.RentRequest();
try
{
//Set action as get/create
- request.WriteHeader(HeaderCommand.Action, Actions.Get);
+ request.WriteHeader(HeaderCommand.Action, Actions.AddOrUpdate);
- //Set object id header
+ //Set object-id header
request.WriteHeader(Constants.ObjectId, objectId);
+ //if new-id set, set the new-id header
+ if (!string.IsNullOrWhiteSpace(newId))
+ {
+ request.WriteHeader(Constants.NewObjectId, newId);
+ }
+
+ //Serialize the message using the request buffer
+ serializer.Serialize(data, request.GetBodyWriter());
+
//Make request
using FBMResponse response = await client.SendAsync(request, cancellationToken);
response.ThrowIfNotSet();
@@ -133,22 +134,22 @@ namespace VNLib.Data.Caching
//Get the status code
FBMMessageHeader status = response.Headers.FirstOrDefault(static a => a.Header == HeaderCommand.Status);
- //Check ok status code, then its safe to deserialize
- if (status.Value.Equals(ResponseCodes.Okay, StringComparison.Ordinal))
+ //Check status code
+ if (status.Value.Equals(ResponseCodes.Okay, StringComparison.OrdinalIgnoreCase))
{
- return deserialzer.Deserialze<T>(response.ResponseBody);
+ return;
}
-
- //Object may not exist on the server yet
- if (status.Value.Equals(ResponseCodes.NotFound, StringComparison.Ordinal))
+ else if (status.Value.Equals(ResponseCodes.NotFound, StringComparison.OrdinalIgnoreCase))
{
- return default;
+ throw new ObjectNotFoundException($"object {objectId} not found on remote server");
}
- throw new InvalidStatusException("Invalid status code recived for object get request", status.ToString());
+ //Invalid status
+ throw new InvalidStatusException("Invalid status code recived for object upsert request", status.ToString());
}
finally
{
+ //Return the request(clears data and reset)
client.ReturnRequest(request);
}
}
@@ -157,12 +158,10 @@ namespace VNLib.Data.Caching
/// Updates the state of the object, and optionally updates the ID of the object. The data
/// parameter is serialized, buffered, and streamed to the remote server
/// </summary>
- /// <typeparam name="T"></typeparam>
/// <param name="client"></param>
/// <param name="objectId">The id of the object to update or replace</param>
/// <param name="newId">An optional parameter to specify a new ID for the old object</param>
- /// <param name="data">The payload data to serialize and set as the data state of the session</param>
- /// <param name="serializer">The custom serializer to used to serialze the object to binary</param>
+ /// <param name="data">An <see cref="IObjectData"/> that represents the data to set</param>
/// <param name="cancellationToken">A token to cancel the operation</param>
/// <returns>A task that resolves when the server responds</returns>
/// <exception cref="OutOfMemoryException"></exception>
@@ -171,16 +170,32 @@ namespace VNLib.Data.Caching
/// <exception cref="InvalidResponseException"></exception>
/// <exception cref="MessageTooLargeException"></exception>
/// <exception cref="ObjectNotFoundException"></exception>
- public static async Task AddOrUpdateObjectAsync<T>(
- this FBMClient client,
- string objectId,
- string? newId,
- T data,
- ICacheObjectSerialzer serializer,
- CancellationToken cancellationToken = default)
+ public static Task AddOrUpdateObjectAsync(this FBMClient client, string objectId, string? newId, IObjectData data, CancellationToken cancellationToken = default)
+ {
+ return AddOrUpdateObjectAsync(client, objectId, newId, static d => d.GetData(), data, cancellationToken);
+ }
+
+ /// <summary>
+ /// Updates the state of the object, and optionally updates the ID of the object. The data
+ /// parameter is serialized, buffered, and streamed to the remote server
+ /// </summary>
+ /// <param name="client"></param>
+ /// <param name="objectId">The id of the object to update or replace</param>
+ /// <param name="newId">An optional parameter to specify a new ID for the old object</param>
+ /// <param name="callback">A callback method that will return the desired object data</param>
+ /// <param name="cancellationToken">A token to cancel the operation</param>
+ /// <param name="state">The state to be passed to the callback</param>
+ /// <returns>A task that resolves when the server responds</returns>
+ /// <exception cref="OutOfMemoryException"></exception>
+ /// <exception cref="InvalidStatusException"></exception>
+ /// <exception cref="ObjectDisposedException"></exception>
+ /// <exception cref="InvalidResponseException"></exception>
+ /// <exception cref="MessageTooLargeException"></exception>
+ /// <exception cref="ObjectNotFoundException"></exception>
+ public async static Task AddOrUpdateObjectAsync<T>(this FBMClient client, string objectId, string? newId, ObjectDataReader<T> callback, T state, CancellationToken cancellationToken = default)
{
_ = client ?? throw new ArgumentNullException(nameof(client));
- _ = serializer ?? throw new ArgumentNullException(nameof(serializer));
+ _ = callback ?? throw new ArgumentNullException(nameof(callback));
client.LogDebug("Updating object {id}, newid {nid}", objectId, newId);
@@ -200,11 +215,8 @@ namespace VNLib.Data.Caching
request.WriteHeader(Constants.NewObjectId, newId);
}
- //Get the body writer for the message
- IBufferWriter<byte> bodyWriter = request.GetBodyWriter();
-
- //Serialize the message
- serializer.Serialize(data, bodyWriter);
+ //Write the message body as the objet data
+ request.WriteBody(callback(state));
//Make request
using FBMResponse response = await client.SendAsync(request, cancellationToken);
@@ -234,45 +246,70 @@ namespace VNLib.Data.Caching
}
/// <summary>
- /// Asynchronously deletes an object in the remote store
+ /// Gets an object from the server if it exists, and uses the default serialzer to
+ /// recover the object
/// </summary>
+ /// <typeparam name="T"></typeparam>
/// <param name="client"></param>
- /// <param name="objectId">The id of the object to update or replace</param>
+ /// <param name="objectId">The id of the object to get</param>
/// <param name="cancellationToken">A token to cancel the operation</param>
- /// <returns>A task that resolves when the operation has completed</returns>
+ /// <returns>A task that completes to return the results of the response payload</returns>
+ /// <exception cref="JsonException"></exception>
+ /// <exception cref="OutOfMemoryException"></exception>
/// <exception cref="InvalidStatusException"></exception>
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="InvalidResponseException"></exception>
- /// <exception cref="ObjectNotFoundException"></exception>
- public static async Task DeleteObjectAsync(this FBMClient client, string objectId, CancellationToken cancellationToken = default)
+ public static Task<T?> GetObjectAsync<T>(this FBMClient client, string objectId, CancellationToken cancellationToken = default)
+ {
+ return GetObjectAsync<T>(client, objectId, DefaultSerializer, cancellationToken);
+ }
+
+ /// <summary>
+ /// Gets an object from the server if it exists
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="client"></param>
+ /// <param name="objectId">The id of the object to get</param>
+ /// <param name="cancellationToken">A token to cancel the operation</param>
+ /// <param name="deserialzer">The custom data deserialzer used to deserialze the binary cache result</param>
+ /// <returns>A task that completes to return the results of the response payload</returns>
+ /// <exception cref="InvalidStatusException"></exception>
+ /// <exception cref="ObjectDisposedException"></exception>
+ /// <exception cref="InvalidResponseException"></exception>
+ public static async Task<T?> GetObjectAsync<T>(this FBMClient client, string objectId, ICacheObjectDeserializer deserialzer, CancellationToken cancellationToken = default)
{
_ = client ?? throw new ArgumentNullException(nameof(client));
+ _ = deserialzer ?? throw new ArgumentNullException(nameof(deserialzer));
+
+ client.LogDebug("Getting object {id}", objectId);
- client.LogDebug("Deleting object {id}", objectId);
-
//Rent a new request
FBMRequest request = client.RentRequest();
try
{
- //Set action as delete
- request.WriteHeader(HeaderCommand.Action, Actions.Delete);
- //Set session-id header
+ //Set action as get/create
+ request.WriteHeader(HeaderCommand.Action, Actions.Get);
+
+ //Set object id header
request.WriteHeader(Constants.ObjectId, objectId);
//Make request
using FBMResponse response = await client.SendAsync(request, cancellationToken);
response.ThrowIfNotSet();
-
+
//Get the status code
FBMMessageHeader status = response.Headers.FirstOrDefault(static a => a.Header == HeaderCommand.Status);
-
+
+ //Check ok status code, then its safe to deserialize
if (status.Value.Equals(ResponseCodes.Okay, StringComparison.Ordinal))
{
- return;
+ return deserialzer.Deserialize<T>(response.ResponseBody);
}
- else if(status.Value.Equals(ResponseCodes.NotFound, StringComparison.OrdinalIgnoreCase))
+
+ //Object may not exist on the server yet
+ if (status.Value.Equals(ResponseCodes.NotFound, StringComparison.Ordinal))
{
- throw new ObjectNotFoundException($"object {objectId} not found on remote server");
+ return default;
}
throw new InvalidStatusException("Invalid status code recived for object get request", status.ToString());
@@ -284,47 +321,54 @@ namespace VNLib.Data.Caching
}
/// <summary>
- /// Updates the state of the object, and optionally updates the ID of the object. The data
- /// parameter is serialized, buffered, and streamed to the remote server
+ /// Gets an object from the server if it exists. If data is retreived, it sets
+ /// the <see cref="IObjectData.SetData(ReadOnlySpan{byte})"/>, if no data is
+ /// found, this method returns and never calls SetData.
/// </summary>
/// <param name="client"></param>
- /// <param name="objectId">The id of the object to update or replace</param>
- /// <param name="newId">An optional parameter to specify a new ID for the old object</param>
- /// <param name="data">An <see cref="IObjectData"/> that represents the data to set</param>
+ /// <param name="objectId">The id of the object to get</param>
+ /// <param name="data">An object data instance used to store the found object data</param>
/// <param name="cancellationToken">A token to cancel the operation</param>
- /// <returns>A task that resolves when the server responds</returns>
- /// <exception cref="OutOfMemoryException"></exception>
+ /// <returns>A task that completes to return the results of the response payload</returns>
/// <exception cref="InvalidStatusException"></exception>
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="InvalidResponseException"></exception>
- /// <exception cref="MessageTooLargeException"></exception>
- /// <exception cref="ObjectNotFoundException"></exception>
- public async static Task AddOrUpdateObjectAsync(this FBMClient client, string objectId, string? newId, IObjectData data, CancellationToken cancellationToken = default)
+ public static Task<bool> GetObjectAsync(this FBMClient client, string objectId, IObjectData data, CancellationToken cancellationToken = default)
+ {
+ return GetObjectAsync(client, objectId, static (p, d) => p.SetData(d), data, cancellationToken);
+ }
+
+ /// <summary>
+ /// Gets an object from the server if it exists. If data is retreived, it sets
+ /// the <see cref="IObjectData.SetData(ReadOnlySpan{byte})"/>, if no data is
+ /// found, this method returns and never calls SetData.
+ /// </summary>
+ /// <param name="client"></param>
+ /// <param name="objectId">The id of the object to get</param>
+ /// <param name="setter">A callback method used to store the recovered object data</param>
+ /// <param name="state">The state parameter to pass to the callback method</param>
+ /// <param name="cancellationToken">A token to cancel the operation</param>
+ /// <returns>When complete, true if the object was found, false if not found, and an exception otherwise</returns>
+ /// <exception cref="InvalidStatusException"></exception>
+ /// <exception cref="ObjectDisposedException"></exception>
+ /// <exception cref="InvalidResponseException"></exception>
+ public static async Task<bool> GetObjectAsync<T>(this FBMClient client, string objectId, ObjectDataSet<T> setter, T state, CancellationToken cancellationToken = default)
{
_ = client ?? throw new ArgumentNullException(nameof(client));
- _ = data ?? throw new ArgumentNullException(nameof(data));
+ _ = setter ?? throw new ArgumentNullException(nameof(setter));
- client.LogDebug("Updating object {id}, newid {nid}", objectId, newId);
+ client.LogDebug("Getting object {id}", objectId);
//Rent a new request
FBMRequest request = client.RentRequest();
try
{
//Set action as get/create
- request.WriteHeader(HeaderCommand.Action, Actions.AddOrUpdate);
+ request.WriteHeader(HeaderCommand.Action, Actions.Get);
- //Set session-id header
+ //Set object id header
request.WriteHeader(Constants.ObjectId, objectId);
- //if new-id set, set the new-id header
- if (!string.IsNullOrWhiteSpace(newId))
- {
- request.WriteHeader(Constants.NewObjectId, newId);
- }
-
- //Write the message body as the objet data
- request.WriteBody(data.GetData());
-
//Make request
using FBMResponse response = await client.SendAsync(request, cancellationToken);
response.ThrowIfNotSet();
@@ -332,54 +376,52 @@ namespace VNLib.Data.Caching
//Get the status code
FBMMessageHeader status = response.Headers.FirstOrDefault(static a => a.Header == HeaderCommand.Status);
- //Check status code
- if (status.Value.Equals(ResponseCodes.Okay, StringComparison.OrdinalIgnoreCase))
+ //Check ok status code, then its safe to deserialize
+ if (status.Value.Equals(ResponseCodes.Okay, StringComparison.Ordinal))
{
- return;
+ //Write the object data
+ setter(state, response.ResponseBody);
+ return true;
}
- else if (status.Value.Equals(ResponseCodes.NotFound, StringComparison.OrdinalIgnoreCase))
+
+ //Object may not exist on the server yet
+ if (status.Value.Equals(ResponseCodes.NotFound, StringComparison.Ordinal))
{
- throw new ObjectNotFoundException($"object {objectId} not found on remote server");
+ return false;
}
- //Invalid status
- throw new InvalidStatusException("Invalid status code recived for object upsert request", status.ToString());
+ throw new InvalidStatusException("Invalid status code recived for object get request", status.ToString());
}
finally
{
- //Return the request(clears data and reset)
client.ReturnRequest(request);
}
}
/// <summary>
- /// Gets an object from the server if it exists. If data is retreived, it sets
- /// the <see cref="IObjectData.SetData(ReadOnlySpan{byte})"/>, if no data is
- /// found, this method returns and never calls SetData.
+ /// Asynchronously deletes an object in the remote store
/// </summary>
/// <param name="client"></param>
- /// <param name="objectId">The id of the object to get</param>
+ /// <param name="objectId">The id of the object to update or replace</param>
/// <param name="cancellationToken">A token to cancel the operation</param>
- /// <param name="data">An <see cref="IObjectData"/> that represents the object data to set</param>
- /// <returns>A task that completes to return the results of the response payload</returns>
+ /// <returns>A task that resolves when the operation has completed</returns>
/// <exception cref="InvalidStatusException"></exception>
/// <exception cref="ObjectDisposedException"></exception>
/// <exception cref="InvalidResponseException"></exception>
- public static async Task GetObjectAsync(this FBMClient client, string objectId, IObjectData data, CancellationToken cancellationToken = default)
+ /// <exception cref="ObjectNotFoundException"></exception>
+ public static async Task<bool> DeleteObjectAsync(this FBMClient client, string objectId, CancellationToken cancellationToken = default)
{
_ = client ?? throw new ArgumentNullException(nameof(client));
- _ = data ?? throw new ArgumentNullException(nameof(data));
- client.LogDebug("Getting object {id}", objectId);
+ client.LogDebug("Deleting object {id}", objectId);
//Rent a new request
FBMRequest request = client.RentRequest();
try
{
- //Set action as get/create
- request.WriteHeader(HeaderCommand.Action, Actions.Get);
-
- //Set object id header
+ //Set action as delete
+ request.WriteHeader(HeaderCommand.Action, Actions.Delete);
+ //Set session-id header
request.WriteHeader(Constants.ObjectId, objectId);
//Make request
@@ -389,18 +431,13 @@ namespace VNLib.Data.Caching
//Get the status code
FBMMessageHeader status = response.Headers.FirstOrDefault(static a => a.Header == HeaderCommand.Status);
- //Check ok status code, then its safe to deserialize
if (status.Value.Equals(ResponseCodes.Okay, StringComparison.Ordinal))
{
- //Write the object data
- data.SetData(response.ResponseBody);
- return;
+ return true;
}
-
- //Object may not exist on the server yet
- if (status.Value.Equals(ResponseCodes.NotFound, StringComparison.Ordinal))
+ else if (status.Value.Equals(ResponseCodes.NotFound, StringComparison.OrdinalIgnoreCase))
{
- return;
+ return false;
}
throw new InvalidStatusException("Invalid status code recived for object get request", status.ToString());
@@ -415,10 +452,15 @@ namespace VNLib.Data.Caching
/// Dequeues a change event from the server event queue for the current connection, or waits until a change happens
/// </summary>
/// <param name="client"></param>
+ /// <param name="change">The instance to store change event data to</param>
/// <param name="cancellationToken">A token to cancel the deuque operation</param>
/// <returns>A <see cref="WaitForChangeResult"/> that contains information about the modified element</returns>
- public static async Task<WaitForChangeResult> WaitForChangeAsync(this FBMClient client, CancellationToken cancellationToken = default)
+ /// <exception cref="InvalidResponseException"></exception>
+ /// <exception cref="InvalidOperationException"></exception>
+ public static async Task WaitForChangeAsync(this FBMClient client, WaitForChangeResult change, CancellationToken cancellationToken = default)
{
+ _ = change ?? throw new ArgumentNullException(nameof(change));
+
//Rent a new request
FBMRequest request = client.RentRequest();
try
@@ -431,12 +473,9 @@ namespace VNLib.Data.Caching
response.ThrowIfNotSet();
- return new()
- {
- Status = response.Headers.FirstOrDefault(static a => a.Header == HeaderCommand.Status).Value.ToString(),
- CurrentId = response.Headers.SingleOrDefault(static v => v.Header == Constants.ObjectId).Value.ToString(),
- NewId = response.Headers.SingleOrDefault(static v => v.Header == Constants.NewObjectId).Value.ToString()
- };
+ change.Status = response.Headers.FirstOrDefault(static a => a.Header == HeaderCommand.Status).Value.ToString();
+ change.CurrentId = response.Headers.SingleOrDefault(static v => v.Header == Constants.ObjectId).Value.ToString();
+ change.NewId = response.Headers.SingleOrDefault(static v => v.Header == Constants.NewObjectId).Value.ToString();
}
finally
{
diff --git a/lib/VNLib.Data.Caching/src/GlobalCacheExtensions.cs b/lib/VNLib.Data.Caching/src/GlobalCacheExtensions.cs
new file mode 100644
index 0000000..8b23240
--- /dev/null
+++ b/lib/VNLib.Data.Caching/src/GlobalCacheExtensions.cs
@@ -0,0 +1,82 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Data.Caching
+* File: GlobalCacheExtensions.cs
+*
+* GlobalCacheExtensions.cs is part of VNLib.Data.Caching which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.Data.Caching 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.Data.Caching 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;
+
+#pragma warning disable CA1062 // Validate arguments of public methods
+
+namespace VNLib.Data.Caching
+{
+ /// <summary>
+ /// Exports extension methods for the <see cref="IGlobalCacheProvider"/> interface
+ /// </summary>
+ public static class GlobalCacheExtensions
+ {
+ /// <summary>
+ /// Asynchronously gets a value from the backing cache store and writes it to the
+ /// supplied data buffer
+ /// </summary>
+ /// <param name="cache"></param>
+ /// <param name="key">The key identifying the object to recover from cache</param>
+ /// <param name="rawData">The </param>
+ /// <param name="cancellation">A token to cancel the async operation</param>
+ /// <returns>A task that complets when the object data has been written to the data buffer</returns>
+ public static Task GetAsync(this IGlobalCacheProvider cache, string key, IObjectData rawData, CancellationToken cancellation)
+ {
+ return cache.GetAsync(key, static (cd, data) => cd.SetData(data), rawData, cancellation);
+ }
+
+ /// <summary>
+ /// Asynchronously sets (or updates) a cached value in the backing cache store
+ /// from the supplied raw data
+ /// </summary>
+ /// <param name="cache"></param>
+ /// <param name="key">The key identifying the object to recover from cache</param>
+ /// <param name="newKey">An optional key that will be changed for the new object</param>
+ /// <param name="cancellation">A token to cancel the async operation</param>
+ /// <param name="rawData">The raw data to store at the given key</param>
+ /// <returns>A task that completes when the update operation has compelted</returns>
+ public static Task AddOrUpdateAsync(this IGlobalCacheProvider cache, string key, string? newKey, IObjectData rawData, CancellationToken cancellation)
+ {
+ return cache.AddOrUpdateAsync(key, newKey, static cd => cd.GetData(), rawData, cancellation);
+ }
+
+ /// <summary>
+ /// Asynchronously sets (or updates) a cached value in the backing cache store
+ /// from the supplied raw data
+ /// </summary>
+ /// <param name="cache"></param>
+ /// <param name="key">The key identifying the object to recover from cache</param>
+ /// <param name="newKey">An optional key that will be changed for the new object</param>
+ /// <param name="cancellation">A token to cancel the async operation</param>
+ /// <param name="rawData">The raw data to store at the given key</param>
+ /// <returns>A task that completes when the update operation has compelted</returns>
+ public static Task AddOrUpdateAsync(this IGlobalCacheProvider cache, string key, string? newKey, ReadOnlyMemory<byte> rawData, CancellationToken cancellation)
+ {
+ return cache.AddOrUpdateAsync(key, newKey, static cd => cd.Span, rawData, cancellation);
+ }
+ }
+} \ No newline at end of file
diff --git a/lib/VNLib.Data.Caching/src/ICacheObjectDeserialzer.cs b/lib/VNLib.Data.Caching/src/ICacheObjectDeserializer.cs
index 3cdb395..560d3bf 100644
--- a/lib/VNLib.Data.Caching/src/ICacheObjectDeserialzer.cs
+++ b/lib/VNLib.Data.Caching/src/ICacheObjectDeserializer.cs
@@ -3,7 +3,7 @@
*
* Library: VNLib
* Package: VNLib.Data.Caching
-* File: ICacheObjectDeserialzer.cs
+* File: ICacheObjectDeserializer.cs
*
* ICacheObjectDeserialzer.cs is part of VNLib.Data.Caching which is part
* of the larger VNLib collection of libraries and utilities.
@@ -29,7 +29,7 @@ namespace VNLib.Data.Caching
/// <summary>
/// Provides custom binary deserialzation for a given type
/// </summary>
- public interface ICacheObjectDeserialzer
+ public interface ICacheObjectDeserializer
{
/// <summary>
/// Attempts to deserialze the supplied binary buffer to its original
@@ -38,6 +38,6 @@ namespace VNLib.Data.Caching
/// <param name="objectData">The buffer containing data to deserialze</param>
/// <typeparam name="T"></typeparam>
/// <returns>A new instance deserialzed to contain the original entity state</returns>
- T? Deserialze<T>(ReadOnlySpan<byte> objectData);
+ T? Deserialize<T>(ReadOnlySpan<byte> objectData);
}
}
diff --git a/lib/VNLib.Data.Caching/src/ICacheObjectSerialzer.cs b/lib/VNLib.Data.Caching/src/ICacheObjectSerializer.cs
index fba2df0..658f63e 100644
--- a/lib/VNLib.Data.Caching/src/ICacheObjectSerialzer.cs
+++ b/lib/VNLib.Data.Caching/src/ICacheObjectSerializer.cs
@@ -3,9 +3,9 @@
*
* Library: VNLib
* Package: VNLib.Data.Caching
-* File: ICacheObjectSerialzer.cs
+* File: ICacheObjectSerializer.cs
*
-* ICacheObjectSerialzer.cs is part of VNLib.Data.Caching which is part
+* ICacheObjectSerializer.cs is part of VNLib.Data.Caching which is part
* of the larger VNLib collection of libraries and utilities.
*
* VNLib.Data.Caching is free software: you can redistribute it and/or modify
@@ -30,7 +30,7 @@ namespace VNLib.Data.Caching
/// <summary>
/// Provides custom binary deserialziation for a given type
/// </summary>
- public interface ICacheObjectSerialzer
+ public interface ICacheObjectSerializer
{
/// <summary>
/// Serializes an instance of the given type and writes
diff --git a/lib/VNLib.Data.Caching/src/IGlobalCacheProvider.cs b/lib/VNLib.Data.Caching/src/IGlobalCacheProvider.cs
index 8a857d4..18c8a98 100644
--- a/lib/VNLib.Data.Caching/src/IGlobalCacheProvider.cs
+++ b/lib/VNLib.Data.Caching/src/IGlobalCacheProvider.cs
@@ -22,11 +22,30 @@
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
+using System;
using System.Threading;
using System.Threading.Tasks;
namespace VNLib.Data.Caching
{
+
+ /// <summary>
+ /// A delegate method that will set the raw object data on the state object
+ /// if data was found
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="state">The state passed to the original call</param>
+ /// <param name="objectData">The raw data of the cached object</param>
+ public delegate void ObjectDataSet<T>(T state, ReadOnlySpan<byte> objectData);
+
+ /// <summary>
+ /// A delegate method that will get the raw objet data from a state object
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="state">The state object passed to the caller</param>
+ /// <returns>The raw object data to store in cache</returns>
+ public delegate ReadOnlySpan<byte> ObjectDataReader<T>(T state);
+
/// <summary>
/// A global cache provider interface
/// </summary>
@@ -38,6 +57,12 @@ namespace VNLib.Data.Caching
bool IsConnected { get; }
/// <summary>
+ /// Gets the underlying cache store object
+ /// </summary>
+ /// <returns>The underlying cache store instance</returns>
+ object GetUnderlyingStore();
+
+ /// <summary>
/// Asynchronously gets a value from the backing cache store
/// </summary>
/// <typeparam name="T"></typeparam>
@@ -63,7 +88,7 @@ namespace VNLib.Data.Caching
/// <param name="key">The key identifying the item to delete</param>
/// <param name="cancellation">A token to cancel the async operation</param>
/// <returns>A task that completes when the delete operation has compelted</returns>
- Task DeleteAsync(string key, CancellationToken cancellation);
+ Task<bool> DeleteAsync(string key, CancellationToken cancellation);
/// <summary>
/// Asynchronously gets a value from the backing cache store
@@ -73,7 +98,7 @@ namespace VNLib.Data.Caching
/// <param name="deserializer">The specific deserialzer to deserialze the object</param>
/// <param name="cancellation">A token to cancel the async operation</param>
/// <returns>The value if found, or null if it does not exist in the store</returns>
- Task<T?> GetAsync<T>(string key, ICacheObjectDeserialzer deserializer, CancellationToken cancellation);
+ Task<T?> GetAsync<T>(string key, ICacheObjectDeserializer deserializer, CancellationToken cancellation);
/// <summary>
/// Asynchronously sets (or updates) a cached value in the backing cache store
@@ -83,19 +108,20 @@ namespace VNLib.Data.Caching
/// <param name="newKey">An optional key that will be changed for the new object</param>
/// <param name="cancellation">A token to cancel the async operation</param>
/// <param name="value">The value to set at the given key</param>
- /// <param name="serialzer">The <see cref="ICacheObjectSerialzer"/> used to serialze the entity</param>
+ /// <param name="serialzer">The <see cref="ICacheObjectSerializer"/> used to serialze the entity</param>
/// <returns>A task that completes when the update operation has compelted</returns>
- Task AddOrUpdateAsync<T>(string key, string? newKey, T value, ICacheObjectSerialzer serialzer, CancellationToken cancellation);
+ Task AddOrUpdateAsync<T>(string key, string? newKey, T value, ICacheObjectSerializer serialzer, CancellationToken cancellation);
/// <summary>
/// Asynchronously gets a value from the backing cache store and writes it to the
/// supplied data buffer
/// </summary>
/// <param name="key">The key identifying the object to recover from cache</param>
- /// <param name="rawData">The </param>
+ /// <param name="callback">The callback method that will get the raw object data</param>
+ /// <param name="state">The state parameter to pass to the callback when invoked</param>
/// <param name="cancellation">A token to cancel the async operation</param>
/// <returns>A task that complets when the object data has been written to the data buffer</returns>
- Task GetAsync(string key, IObjectData rawData, CancellationToken cancellation);
+ Task GetAsync<T>(string key, ObjectDataSet<T> callback, T state, CancellationToken cancellation);
/// <summary>
/// Asynchronously sets (or updates) a cached value in the backing cache store
@@ -103,9 +129,10 @@ namespace VNLib.Data.Caching
/// </summary>
/// <param name="key">The key identifying the object to recover from cache</param>
/// <param name="newKey">An optional key that will be changed for the new object</param>
+ /// <param name="callback">A callback method that will set the raw object data when received</param>
+ /// <param name="state">The callback state parameter</param>
/// <param name="cancellation">A token to cancel the async operation</param>
- /// <param name="rawData">The raw data to store at the given key</param>
/// <returns>A task that completes when the update operation has compelted</returns>
- Task AddOrUpdateAsync(string key, string? newKey, IObjectData rawData, CancellationToken cancellation);
+ Task AddOrUpdateAsync<T>(string key, string? newKey, ObjectDataReader<T> callback, T state, CancellationToken cancellation);
}
} \ No newline at end of file
diff --git a/lib/VNLib.Data.Caching/src/JsonCacheObjectSerializer.cs b/lib/VNLib.Data.Caching/src/JsonCacheObjectSerializer.cs
index dce0bdf..85d1184 100644
--- a/lib/VNLib.Data.Caching/src/JsonCacheObjectSerializer.cs
+++ b/lib/VNLib.Data.Caching/src/JsonCacheObjectSerializer.cs
@@ -32,10 +32,10 @@ using VNLib.Utils.Memory.Caching;
namespace VNLib.Data.Caching
{
/// <summary>
- /// Implements a <see cref="ICacheObjectDeserialzer"/> and a <see cref="ICacheObjectSerialzer"/>
+ /// Implements a <see cref="ICacheObjectDeserializer"/> and a <see cref="ICacheObjectSerializer"/>
/// that uses JSON serialization, with writer pooling. Members of this class are thread-safe.
/// </summary>
- public class JsonCacheObjectSerializer : ICacheObjectSerialzer, ICacheObjectDeserialzer
+ public class JsonCacheObjectSerializer : ICacheObjectSerializer, ICacheObjectDeserializer
{
//Create threadlocal writer for attempted lock-free writer reuse
private static readonly ObjectRental<ReusableJsonWriter> JsonWriterPool = ObjectRental.CreateThreadLocal<ReusableJsonWriter>();
@@ -75,7 +75,7 @@ namespace VNLib.Data.Caching
}
///<inheritdoc/>
- public virtual T? Deserialze<T>(ReadOnlySpan<byte> objectData) => JsonSerializer.Deserialize<T>(objectData, _options);
+ public virtual T? Deserialize<T>(ReadOnlySpan<byte> objectData) => JsonSerializer.Deserialize<T>(objectData, _options);
///<inheritdoc/>
public virtual void Serialize<T>(T obj, IBufferWriter<byte> finiteWriter)
diff --git a/lib/VNLib.Data.Caching/src/WaitForChangeResult.cs b/lib/VNLib.Data.Caching/src/WaitForChangeResult.cs
index fe4f22f..18428ce 100644
--- a/lib/VNLib.Data.Caching/src/WaitForChangeResult.cs
+++ b/lib/VNLib.Data.Caching/src/WaitForChangeResult.cs
@@ -27,14 +27,21 @@ namespace VNLib.Data.Caching
/// <summary>
/// The result of a cache server change event
/// </summary>
- /// <param name="Status">The operation status code</param>
- /// <param name="CurrentId">The current (or old) id of the element that changed</param>
- /// <param name="NewId">The new id of the element that changed</param>
- public readonly record struct WaitForChangeResult(
- string Status,
- string CurrentId,
- string NewId)
+ public sealed record class WaitForChangeResult
{
-
+ /// <summary>
+ /// The operation status code
+ /// </summary>
+ public string? Status { get; set; }
+
+ /// <summary>
+ /// The current (or old) id of the element that changed
+ /// </summary>
+ public string? CurrentId { get; set; }
+
+ /// <summary>
+ /// The new id of the element that changed
+ /// </summary>
+ public string? NewId { get; set; }
}
}