diff options
Diffstat (limited to 'lib/VNLib.Data.Caching.ObjectCache')
5 files changed, 79 insertions, 119 deletions
diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCache.cs b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCache.cs index 5a425ec..7b2b3b1 100644 --- a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCache.cs +++ b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCache.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Vaughn Nugent +* Copyright (c) 2024 Vaughn Nugent * * Library: VNLib * Package: VNLib.Data.Caching.ObjectCache @@ -34,10 +34,10 @@ namespace VNLib.Data.Caching.ObjectCache /// <summary> /// A general purpose binary data storage /// </summary> - public sealed class BlobCache : LRUCache<string, CacheEntry>, IBlobCache, IMemoryCacheEntryFactory + public sealed class BlobCache : LRUCache<string, CacheEntry>, IBlobCache { private bool disposedValue; - private IPersistantCacheStore? _persistance; + private readonly IPersistantCacheStore? _persistance; ///<inheritdoc/> public override bool IsReadOnly { get; } @@ -62,17 +62,12 @@ namespace VNLib.Data.Caching.ObjectCache public BlobCache(uint bucketId, int maxCapacity, ICacheEntryMemoryManager manager, IPersistantCacheStore? store) :base(maxCapacity, StringComparer.Ordinal) { - if(maxCapacity < 1) - { - throw new ArgumentException("The maxium capacity of the store must be a positive integer larger than 0", nameof(maxCapacity)); - } + ArgumentOutOfRangeException.ThrowIfLessThan(maxCapacity, 1); + ArgumentNullException.ThrowIfNull(manager); BucketId = bucketId; - _persistance = store; - - MemoryManager = manager ?? throw new ArgumentNullException(nameof(manager)); - + MemoryManager = manager; MaxCapacity = maxCapacity; //Update the lookup table size @@ -88,11 +83,11 @@ namespace VNLib.Data.Caching.ObjectCache return false; } //Use the persistant cache - return _persistance.OnCacheMiss(BucketId, key, this, out value); + return _persistance.OnCacheMiss(BucketId, key, MemoryManager, out value); } ///<inheritdoc/> - protected override void Evicted(ref KeyValuePair<string, CacheEntry> evicted) + protected override void Evicted(ref readonly KeyValuePair<string, CacheEntry> evicted) { try { @@ -109,6 +104,8 @@ namespace VNLib.Data.Caching.ObjectCache ///<inheritdoc/> public bool TryChangeKey(string objectId, string newId, out CacheEntry entry) { + ObjectDisposedException.ThrowIf(disposedValue, this); + //Try to get the node at the current key if (LookupTable.Remove(objectId, out LinkedListNode<KeyValuePair<string, CacheEntry>> ? node)) { @@ -137,6 +134,8 @@ namespace VNLib.Data.Caching.ObjectCache ///<inheritdoc/> public override bool Remove(string key) { + ObjectDisposedException.ThrowIf(disposedValue, this); + //Remove from persistant store also _persistance?.OnEntryDeleted(BucketId, key); @@ -161,33 +160,23 @@ namespace VNLib.Data.Caching.ObjectCache /// </summary> public override void Clear() { - //Start from first node - LinkedListNode<KeyValuePair<string, CacheEntry>>? node = List.First; + ObjectDisposedException.ThrowIf(disposedValue, this); - //Classic ll node itteration - while(node != null) - { - //Dispose the cache entry - node.ValueRef.Value.Dispose(); - - //Move to next node - node = node.Next; - } - - //empty all cache entires in the store - base.Clear(); + ClearInternal(); } ///<inheritdoc/> public bool Remove(string objectId, out CacheEntry entry) { + ObjectDisposedException.ThrowIf(disposedValue, this); + //Try to get the stored object - if(TryGetValue(objectId, out entry)) + if (TryGetValue(objectId, out entry)) { //remove the entry and bypass the disposal bool result = base.Remove(objectId); - Debug.Assert(result == true, "The cache entry was found in the table, but failed to remove"); + Debug.Assert(result, "The cache entry was found in the table, but failed to remove"); return true; } @@ -196,6 +185,25 @@ namespace VNLib.Data.Caching.ObjectCache return false; } + private void ClearInternal() + { + //Start from first node + LinkedListNode<KeyValuePair<string, CacheEntry>>? node = List.First; + + //Classic ll node itteration + while (node != null) + { + //Dispose the cache entry + node.ValueRef.Value.Dispose(); + + //Move to next node + node = node.Next; + } + + //empty all cache entires in the store + base.Clear(); + } + ///<inheritdoc/> void Dispose(bool disposing) { @@ -203,7 +211,7 @@ namespace VNLib.Data.Caching.ObjectCache { if (disposing) { - Clear(); + ClearInternal(); } disposedValue = true; } @@ -216,13 +224,5 @@ namespace VNLib.Data.Caching.ObjectCache Dispose(disposing: true); GC.SuppressFinalize(this); } - - - ///<inheritdoc/> - CacheEntry IMemoryCacheEntryFactory.CreateEntry(ReadOnlySpan<byte> entryData) - { - //Create entry from the internal heap - return CacheEntry.Create(entryData, MemoryManager); - } } } diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheExtensions.cs b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheExtensions.cs index ded89d2..1681256 100644 --- a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheExtensions.cs +++ b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheExtensions.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Vaughn Nugent +* Copyright (c) 2024 Vaughn Nugent * * Library: VNLib * Package: VNLib.Data.Caching.ObjectCache @@ -144,14 +144,14 @@ namespace VNLib.Data.Caching.ObjectCache this IBlobCacheTable table, string objectId, string? alternateId, - ObjectDataReader<T> bodyData, + ObjectDataGet<T> bodyData, T state, DateTime time, CancellationToken cancellation = default) { - - _ = table ?? throw new ArgumentNullException(nameof(table)); - _ = bodyData ?? throw new ArgumentNullException(nameof(bodyData)); + ArgumentNullException.ThrowIfNull(table); + ArgumentNullException.ThrowIfNull(bodyData); + ArgumentException.ThrowIfNullOrWhiteSpace(objectId); //See if an id change is required if (string.IsNullOrWhiteSpace(alternateId)) @@ -252,11 +252,27 @@ namespace VNLib.Data.Caching.ObjectCache /// <param name="objectId">The id of the object to delete</param> /// <param name="cancellation">A token to cancel the async lock await</param> /// <returns>A task that completes when the item has been deleted</returns> - public static async ValueTask<bool> DeleteObjectAsync(this IBlobCacheTable table, string objectId, CancellationToken cancellation = default) + public static ValueTask<bool> DeleteObjectAsync(this IBlobCacheTable table, string objectId, CancellationToken cancellation = default) { + ArgumentNullException.ThrowIfNull(table); + //Try to get the bucket that the id should belong to IBlobCacheBucket bucket = table.GetBucket(objectId); + return DeleteObjectAsync(bucket, objectId, cancellation); + } + + /// <summary> + /// Asynchronously deletes a previously stored item + /// </summary> + /// <param name="bucket"></param> + /// <param name="objectId">The id of the object to delete</param> + /// <param name="cancellation">A token to cancel the async lock await</param> + /// <returns>A task that completes when the item has been deleted</returns> + public static async ValueTask<bool> DeleteObjectAsync(this IBlobCacheBucket bucket, string objectId, CancellationToken cancellation = default) + { + ArgumentNullException.ThrowIfNull(bucket); + //Wait for the bucket IBlobCache cache = await bucket.ManualWaitAsync(cancellation); diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheLIstener.cs b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheLIstener.cs index 5139746..972bf5e 100644 --- a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheLIstener.cs +++ b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheLIstener.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Vaughn Nugent +* Copyright (c) 2024 Vaughn Nugent * * Library: VNLib * Package: VNLib.Data.Caching.ObjectCache @@ -49,44 +49,36 @@ using static VNLib.Data.Caching.Constants; namespace VNLib.Data.Caching.ObjectCache { - /// <summary> /// An <see cref="FBMListener"/> for key-value object data caching servers. /// </summary> - public class BlobCacheListener<T> : FBMListenerBase<T>, IDisposable + /// <remarks> + /// Initialzies a new <see cref="BlobCacheListener{T}"/> + /// </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> + /// <exception cref="ArgumentNullException"></exception> + public class BlobCacheListener<T>(IBlobCacheTable cache, ICacheListenerEventQueue<T> queue, ILogProvider log, IFBMMemoryManager memoryManager) + : FBMListenerBase<T>, IDisposable { private bool disposedValue; ///<inheritdoc/> - protected override ILogProvider Log { get; } + protected override ILogProvider Log { get; } = log; ///<inheritdoc/> - protected override FBMListener Listener { get; } + protected override FBMListener Listener { get; } = new(memoryManager); /// <summary> /// A queue that stores update and delete events /// </summary> - public ICacheListenerEventQueue<T> EventQueue { get; } + public ICacheListenerEventQueue<T> EventQueue { get; } = queue ?? throw new ArgumentNullException(nameof(queue)); /// <summary> /// The Cache store to access data blobs /// </summary> - public IBlobCacheTable Cache { get; } - - /// <summary> - /// Initialzies a new <see cref="BlobCacheListener{T}"/> - /// </summary> - /// <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> - /// <exception cref="ArgumentNullException"></exception> - public BlobCacheListener(IBlobCacheTable cache, ICacheListenerEventQueue<T> queue, ILogProvider log, IFBMMemoryManager memoryManager) - { - Log = log; - Cache = cache ?? throw new ArgumentNullException(nameof(cache)); - EventQueue = queue ?? throw new ArgumentNullException(nameof(queue)); - Listener = new(memoryManager); - } + public IBlobCacheTable Cache { get; } = cache ?? throw new ArgumentNullException(nameof(cache)); ///<inheritdoc/> protected override async Task ProcessAsync(FBMContext context, T? userState, CancellationToken exitToken) @@ -254,8 +246,7 @@ namespace VNLib.Data.Caching.ObjectCache { if (!disposedValue) { - Cache.Dispose(); - + Cache.Dispose(); disposedValue = true; } } diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/IMemoryCacheEntryFactory.cs b/lib/VNLib.Data.Caching.ObjectCache/src/IMemoryCacheEntryFactory.cs deleted file mode 100644 index 1454fc0..0000000 --- a/lib/VNLib.Data.Caching.ObjectCache/src/IMemoryCacheEntryFactory.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* -* Copyright (c) 2023 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Data.Caching.ObjectCache -* File: IMemoryCacheEntryFactory.cs -* -* IMemoryCacheEntryFactory.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 System; - -namespace VNLib.Data.Caching.ObjectCache -{ - /// <summary> - /// A factory abstraction that builds <see cref="CacheEntry"/> structures - /// linked to internally configured memory implementations, for cache - /// promotions. - /// </summary> - public interface IMemoryCacheEntryFactory - { - /// <summary> - /// Creates and initalizes a new <see cref="CacheEntry"/> from the desired object data - /// </summary> - /// <param name="entryData">The non-owned memory to copy into the the new <see cref="CacheEntry"/></param> - /// <returns>The newly initalized <see cref="CacheEntry"/></returns> - CacheEntry CreateEntry(ReadOnlySpan<byte> entryData); - } -} diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/IPersistantCacheStore.cs b/lib/VNLib.Data.Caching.ObjectCache/src/IPersistantCacheStore.cs index 40f39f2..3824735 100644 --- a/lib/VNLib.Data.Caching.ObjectCache/src/IPersistantCacheStore.cs +++ b/lib/VNLib.Data.Caching.ObjectCache/src/IPersistantCacheStore.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2023 Vaughn Nugent +* Copyright (c) 2024 Vaughn Nugent * * Library: VNLib * Package: VNLib.Data.Caching.ObjectCache @@ -54,20 +54,16 @@ namespace VNLib.Data.Caching.ObjectCache /// This method is called while the bucket lock is held. This call is maded /// during an <see cref="IBlobCache.Add(string, CacheEntry)"/> method call. /// </para> - /// <para> - /// The <see cref="IMemoryCacheEntryFactory"/> should be used to create the - /// cache entry for the return value. Once this method returns, the caller owns the new <see cref="CacheEntry"/> - /// </para> /// </summary> /// <param name="key">The key identifying the entry to promot</param> - /// <param name="factory">The cache entry factory</param> + /// <param name="memManager">The cache table memory manager</param> /// <param name="bucketId">The id of the bucket requesting the operation</param> /// <param name="entry">The newly created entry when data is found</param> /// <returns> /// A value inidcating if the entry was successfully recovered from the persistant storage and /// was successfully promoted. /// </returns> - bool OnCacheMiss(uint bucketId, string key, IMemoryCacheEntryFactory factory, out CacheEntry entry); + bool OnCacheMiss(uint bucketId, string key, ICacheEntryMemoryManager memManager, out CacheEntry entry); /// <summary> /// Removes an entry from the backing store |