diff options
Diffstat (limited to 'lib/VNLib.Data.Caching.ObjectCache')
3 files changed, 123 insertions, 9 deletions
diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheLIstener.cs b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheLIstener.cs index 972bf5e..7908313 100644 --- a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheLIstener.cs +++ b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheLIstener.cs @@ -43,7 +43,6 @@ using System.Threading; using System.Threading.Tasks; using VNLib.Utils.Logging; -using VNLib.Net.Messaging.FBM; using VNLib.Net.Messaging.FBM.Server; using static VNLib.Data.Caching.Constants; @@ -57,18 +56,22 @@ namespace VNLib.Data.Caching.ObjectCache /// </remarks> /// <param name="cache">The cache table to work from</param> /// <param name="queue">The event queue to publish changes to</param> - /// <param name="log">Writes error and debug logging information</param> - /// <param name="memoryManager">The heap to alloc FBM buffers and <see cref="CacheEntry"/> cache buffers from</param> + /// <param name="config">The listener configuration object</param> /// <exception cref="ArgumentNullException"></exception> - public class BlobCacheListener<T>(IBlobCacheTable cache, ICacheListenerEventQueue<T> queue, ILogProvider log, IFBMMemoryManager memoryManager) + public class BlobCacheListener<T>(IBlobCacheTable cache, BlobCacheListenerConfig config, ICacheListenerEventQueue<T> queue) : FBMListenerBase<T>, IDisposable { private bool disposedValue; ///<inheritdoc/> - protected override ILogProvider Log { get; } = log; + protected override ILogProvider Log { get; } = config.Log; ///<inheritdoc/> - protected override FBMListener Listener { get; } = new(memoryManager); + protected override FBMListener Listener { get; } = new(config.MemoryManager); + + /// <summary> + /// The configuration instance for the listener + /// </summary> + public BlobCacheListenerConfig Config { get; } = config ?? throw new ArgumentNullException(nameof(config)); /// <summary> /// A queue that stores update and delete events @@ -80,6 +83,9 @@ namespace VNLib.Data.Caching.ObjectCache /// </summary> public IBlobCacheTable Cache { get; } = cache ?? throw new ArgumentNullException(nameof(cache)); + + private readonly ILogProvider _tLog = config.LogTransactions ? config.Log : new NullLogger(); + ///<inheritdoc/> protected override async Task ProcessAsync(FBMContext context, T? userState, CancellationToken exitToken) { @@ -110,6 +116,25 @@ namespace VNLib.Data.Caching.ObjectCache //Create change event for the object ChangeEvent change = new(objectId, alternateId, false); + if (config.EnableMessageChecksums) + { + switch (context.Request.IsClientChecksumValid()) + { + //0 is checksum sent, supported, but invalid + case 0: + context.CloseResponse(ResponseCodes.InvalidChecksum); + return; + + case -2: //Method not supported, set an error header but allow the request + context.Response.WriteHeader(ChecksumWarning, "Checksum method not supported"); + break; + + case 1: //1 is checksum sent and valid + case -1: //No checksum sent + break; + } + } + await AddOrUpdateAsync(context, change, exitToken); return; } @@ -199,6 +224,12 @@ namespace VNLib.Data.Caching.ObjectCache if (handle.Cache.TryGetValue(objectId, out CacheEntry data)) { + //Compute an fnv message checksum and send it to the client + if (config.EnableMessageChecksums) + { + FbmMessageChecksum.WriteFnv1aChecksum(context.Response, data.GetDataSegment()); + } + //Set the status code and write the buffered data to the response buffer context.CloseResponse(ResponseCodes.Okay); @@ -222,6 +253,8 @@ namespace VNLib.Data.Caching.ObjectCache if (found) { EnqueEvent(change); + + _tLog.Debug("Deleted cache entry {id}", change.CurrentId); } } @@ -232,6 +265,8 @@ namespace VNLib.Data.Caching.ObjectCache EnqueEvent(change); + _tLog.Debug("Cache entry {id} added or updated. New ID {nid}", change.CurrentId, change.AlternateId); + context.CloseResponse(ResponseCodes.Okay); } @@ -239,7 +274,7 @@ namespace VNLib.Data.Caching.ObjectCache { EventQueue.PublishEvent(change); } - + ///<inheritdoc/> protected virtual void Dispose(bool disposing) @@ -258,5 +293,28 @@ namespace VNLib.Data.Caching.ObjectCache Dispose(disposing: true); GC.SuppressFinalize(this); } + + sealed class NullLogger : ILogProvider + { + public void Flush() + { } + + public object GetLogProvider() => null!; + + + public bool IsEnabled(LogLevel level) => false; + + public void Write(LogLevel level, string value) + { } + + public void Write(LogLevel level, Exception exception, string value = "") + { } + + public void Write(LogLevel level, string value, params object?[] args) + { } + + public void Write(LogLevel level, string value, params ValueType[] args) + { } + } } } diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheListenerConfig.cs b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheListenerConfig.cs new file mode 100644 index 0000000..492dfb8 --- /dev/null +++ b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheListenerConfig.cs @@ -0,0 +1,56 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.Data.Caching.ObjectCache +* File: BlobCacheListenerConfig.cs +* +* BlobCacheListenerConfig.cs is part of VNLib.Data.Caching.ObjectCache which is part of the larger +* VNLib collection of libraries and utilities. +* +* VNLib.Data.Caching.ObjectCache 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.ObjectCache 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.Utils.Logging; +using VNLib.Net.Messaging.FBM; + +namespace VNLib.Data.Caching.ObjectCache +{ + /// <summary> + /// A configuration object for <see cref="BlobCacheListener{T}"/> + /// </summary> + public sealed record class BlobCacheListenerConfig + { + /// <summary> + /// Writes error and debug logging information + /// </summary> + public ILogProvider Log { get; init; } = null!; + + /// <summary> + /// The memory manager used for the internal FBM server listener + /// </summary> + public IFBMMemoryManager MemoryManager { get; init; } = null!; + + /// <summary> + /// A flag that enables verifying and sending checksums with message + /// data in FBM header fields + /// </summary> + public bool EnableMessageChecksums { get; init; } = true; + + /// <summary> + /// A flag that enables logging of transactions (events) to the log + /// </summary> + public bool LogTransactions { get; init; } + } +} diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/CacheEntry.cs b/lib/VNLib.Data.Caching.ObjectCache/src/CacheEntry.cs index 9370901..eddfc42 100644 --- a/lib/VNLib.Data.Caching.ObjectCache/src/CacheEntry.cs +++ b/lib/VNLib.Data.Caching.ObjectCache/src/CacheEntry.cs @@ -89,8 +89,8 @@ namespace VNLib.Data.Caching /// <exception cref="ArgumentException"></exception> public static CacheEntry FromExistingHandle(object handle, ICacheEntryMemoryManager manager) { - _ = handle ?? throw new ArgumentNullException(nameof(handle)); - _ = manager ?? throw new ArgumentNullException(nameof(manager)); + ArgumentNullException.ThrowIfNull(handle); + ArgumentNullException.ThrowIfNull(manager); //validate handle size it at least the minimum size if (manager.GetHandleSize(handle) < DATA_SEGMENT_START) |