diff options
Diffstat (limited to 'lib/VNLib.Data.Caching.ObjectCache/src')
9 files changed, 302 insertions, 109 deletions
diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCache.cs b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCache.cs index 525227c..5a425ec 100644 --- a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCache.cs +++ b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCache.cs @@ -26,7 +26,6 @@ using System; using System.Diagnostics; using System.Collections.Generic; -using VNLib.Utils.Memory; using VNLib.Utils.Memory.Caching; namespace VNLib.Data.Caching.ObjectCache @@ -47,7 +46,7 @@ namespace VNLib.Data.Caching.ObjectCache protected override int MaxCapacity { get; } ///<inheritdoc/> - public IUnmangedHeap CacheHeap { get; } + public ICacheEntryMemoryManager MemoryManager { get; } ///<inheritdoc/> public uint BucketId { get; } @@ -57,10 +56,10 @@ namespace VNLib.Data.Caching.ObjectCache /// </summary> /// <param name="bucketId">The id of the bucket that manages this instance</param> /// <param name="maxCapacity">The maximum number of items to keep in memory</param> - /// <param name="heap">The unmanaged heap used to allocate cache entry buffers from</param> + /// <param name="manager">The cache entry memory manager instance</param> /// <param name="store">The optional backing persistant cache storage</param> /// <exception cref="ArgumentException"></exception> - public BlobCache(uint bucketId, int maxCapacity, IUnmangedHeap heap, IPersistantCacheStore? store) + public BlobCache(uint bucketId, int maxCapacity, ICacheEntryMemoryManager manager, IPersistantCacheStore? store) :base(maxCapacity, StringComparer.Ordinal) { if(maxCapacity < 1) @@ -72,7 +71,7 @@ namespace VNLib.Data.Caching.ObjectCache _persistance = store; - CacheHeap = heap; + MemoryManager = manager ?? throw new ArgumentNullException(nameof(manager)); MaxCapacity = maxCapacity; @@ -188,7 +187,7 @@ namespace VNLib.Data.Caching.ObjectCache //remove the entry and bypass the disposal bool result = base.Remove(objectId); - Debug.Assert(result == true); + Debug.Assert(result == true, "The cache entry was found in the table, but failed to remove"); return true; } @@ -223,7 +222,7 @@ namespace VNLib.Data.Caching.ObjectCache CacheEntry IMemoryCacheEntryFactory.CreateEntry(ReadOnlySpan<byte> entryData) { //Create entry from the internal heap - return CacheEntry.Create(entryData, CacheHeap); + return CacheEntry.Create(entryData, MemoryManager); } } } diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheBucket.cs b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheBucket.cs index 6af1a20..71c815d 100644 --- a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheBucket.cs +++ b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheBucket.cs @@ -25,8 +25,6 @@ using System.Threading; using System.Threading.Tasks; -using VNLib.Utils.Memory; - namespace VNLib.Data.Caching.ObjectCache { @@ -50,13 +48,13 @@ namespace VNLib.Data.Caching.ObjectCache /// before LRU overflow happens. /// </param> /// <param name="bucketId">The unique id of the new bucket</param> - /// <param name="heap">The heap to allocate object cache buffers</param> + /// <param name="memMan">The cache entry memory manager intance</param> /// <param name="persistantCache">An optional <see cref="IPersistantCacheStore"/> for cache persistance</param> - public BlobCacheBucket(uint bucketId, int bucketCapacity, IUnmangedHeap heap, IPersistantCacheStore? persistantCache) + public BlobCacheBucket(uint bucketId, int bucketCapacity, ICacheEntryMemoryManager memMan, IPersistantCacheStore? persistantCache) { Id = bucketId; _lock = new(1, 1); - _cacheTable = new BlobCache(bucketId, bucketCapacity, heap, persistantCache); + _cacheTable = new BlobCache(bucketId, bucketCapacity, memMan, persistantCache); } ///<inheritdoc/> @@ -69,16 +67,8 @@ namespace VNLib.Data.Caching.ObjectCache ///<inheritdoc/> public async ValueTask<IBlobCache> ManualWaitAsync(CancellationToken cancellation) { - //try to enter the lock synchronously - if (_lock.Wait(0, CancellationToken.None)) - { - return _cacheTable; - } - else - { - await _lock.WaitAsync(cancellation).ConfigureAwait(false); - return _cacheTable; - } + await _lock.WaitAsync(cancellation).ConfigureAwait(false); + return _cacheTable; } ///<inheritdoc/> @@ -86,20 +76,5 @@ namespace VNLib.Data.Caching.ObjectCache { _lock.Release(); } - - ///<inheritdoc/> - public async ValueTask<CacheBucketHandle> WaitAsync(CancellationToken cancellation) - { - //try to enter the lock synchronously - if (_lock.Wait(0, CancellationToken.None)) - { - return new(this, _cacheTable); - } - else - { - await _lock.WaitAsync(cancellation).ConfigureAwait(false); - return new(this, _cacheTable); - } - } } } diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheExtensions.cs b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheExtensions.cs index 4a8692d..a114236 100644 --- a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheExtensions.cs +++ b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheExtensions.cs @@ -34,9 +34,42 @@ namespace VNLib.Data.Caching.ObjectCache /// </summary> public static class BlobCacheExtensions { + + /// <summary> + /// Gets a <see cref="CacheBucketHandle"/> that holds an exclusive lock + /// for the current bucekt and holds a referrence to the stored + /// <see cref="IBlobCache"/> + /// </summary> + /// <param name="bucket"></param> + /// <param name="cancellation">A token to cancel the wait operation</param> + /// <returns>A <see cref="CacheBucketHandle"/> that holds the <see cref="IBlobCache"/> referrence</returns> + public static ValueTask<CacheBucketHandle> WaitAsync(this IBlobCacheBucket bucket, CancellationToken cancellation) + { + _ = bucket ?? throw new ArgumentNullException(nameof(bucket)); + + //Try enter the bucket lock + ValueTask<IBlobCache> cacheWait = bucket.ManualWaitAsync(cancellation); + + if (cacheWait.IsCompleted) + { + IBlobCache bucketHandle = cacheWait.GetAwaiter().GetResult(); + return new ValueTask<CacheBucketHandle>(new CacheBucketHandle(bucket, bucketHandle)); + } + else + { + return GetHandleAsync(cacheWait, bucket); + } + + static async ValueTask<CacheBucketHandle> GetHandleAsync(ValueTask<IBlobCache> waitTask, IBlobCacheBucket bucket) + { + IBlobCache cache = await waitTask.ConfigureAwait(false); + return new CacheBucketHandle(bucket, cache); + } + } + internal static CacheEntry CreateEntry(this IBlobCache cache, string objectId, ReadOnlySpan<byte> initialData, DateTime time) { - CacheEntry entry = CacheEntry.Create(initialData, cache.CacheHeap); + CacheEntry entry = CacheEntry.Create(initialData, cache.MemoryManager); try { //try to add the entry, but if exists, let it throw @@ -115,17 +148,27 @@ namespace VNLib.Data.Caching.ObjectCache DateTime time, CancellationToken cancellation = default) { + + _ = table ?? throw new ArgumentNullException(nameof(table)); + _ = bodyData ?? throw new ArgumentNullException(nameof(bodyData)); + //See if an id change is required if (string.IsNullOrWhiteSpace(alternateId)) { //safe to get the bucket for the primary id IBlobCacheBucket bucket = table.GetBucket(objectId); - //Wait for the bucket - using CacheBucketHandle handle = await bucket.WaitAsync(cancellation); + //Wait for the bucket to be available + IBlobCache cache = await bucket.ManualWaitAsync(cancellation); - //add/update for single entity - _ = handle.Cache.AddOrUpdateEntry(objectId, bodyData(state), time); + try + { + _ = cache.AddOrUpdateEntry(objectId, bodyData(state), time); + } + finally + { + bucket.Release(); + } } else { @@ -136,11 +179,17 @@ namespace VNLib.Data.Caching.ObjectCache //Same bucket if (ReferenceEquals(primary, alternate)) { - //wait for lock on only one bucket otherwise dealock - using CacheBucketHandle handle = await primary.WaitAsync(cancellation); + IBlobCache cache = await primary.ManualWaitAsync(cancellation); - //Update the entry for the single bucket - _ = handle.Cache.TryChangeKey(objectId, alternateId, bodyData(state), time); + try + { + //Update the entry for the single bucket + _ = cache.TryChangeKey(objectId, alternateId, bodyData(state), time); + } + finally + { + primary.Release(); + } } else { @@ -187,11 +236,17 @@ namespace VNLib.Data.Caching.ObjectCache //Try to get the bucket that the id should belong to IBlobCacheBucket bucket = table.GetBucket(objectId); - //Wait for lock on bucket async - using CacheBucketHandle handle = await bucket.WaitAsync(cancellation); + //Wait for the bucket + IBlobCache cache = await bucket.ManualWaitAsync(cancellation); - //Remove the object from the blob store - return handle.Cache.Remove(objectId); + try + { + return cache.Remove(objectId); + } + finally + { + bucket.Release(); + } } } } diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheTable.cs b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheTable.cs index f3f1b50..9443737 100644 --- a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheTable.cs +++ b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheTable.cs @@ -28,10 +28,10 @@ using System.Collections; using System.Collections.Generic; using VNLib.Utils; -using VNLib.Utils.Memory; namespace VNLib.Data.Caching.ObjectCache { + /// <summary> /// A concrete implementation of a <see cref="IBlobCacheTable"/> /// </summary> @@ -41,18 +41,32 @@ namespace VNLib.Data.Caching.ObjectCache private readonly IBlobCacheBucket[] _buckets; private readonly IPersistantCacheStore? _persistant; + /// <summary> /// Initializes a new <see cref="BlobCacheTable"/> /// </summary> /// <param name="bucketSize">The number of elements in each bucket</param> /// <param name="tableSize">The number of buckets within the table</param> - /// <param name="heap">The heap used to allocate cache entry buffers from</param> + /// <param name="manager">A single cache memory manger to share across all buckets</param> /// <param name="persistantCache">An optional <see cref="IPersistantCacheStore"/> for persistant cache implementations</param> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentException"></exception> - public BlobCacheTable(uint tableSize, uint bucketSize, IUnmangedHeap heap, IPersistantCacheStore? persistantCache) + public BlobCacheTable(uint tableSize, uint bucketSize, ICacheEntryMemoryManager manager, IPersistantCacheStore? persistantCache) + :this(tableSize, bucketSize, new SharedMemManager(manager), persistantCache) + { } + + /// <summary> + /// Initializes a new <see cref="BlobCacheTable"/> + /// </summary> + /// <param name="bucketSize">The number of elements in each bucket</param> + /// <param name="tableSize">The number of buckets within the table</param> + /// <param name="factory">A factory that can generate bucket-local memory managers</param> + /// <param name="persistantCache">An optional <see cref="IPersistantCacheStore"/> for persistant cache implementations</param> + /// <exception cref="ArgumentNullException"></exception> + /// <exception cref="ArgumentException"></exception> + public BlobCacheTable(uint tableSize, uint bucketSize, ICacheMemoryManagerFactory factory, IPersistantCacheStore? persistantCache) { - _ = heap ?? throw new ArgumentNullException(nameof(heap)); + _ = factory ?? throw new ArgumentNullException(nameof(factory)); if(tableSize == 0) { @@ -66,15 +80,18 @@ namespace VNLib.Data.Caching.ObjectCache _persistant = persistantCache; //Init buckets - InitBuckets(tableSize, bucketSize, _buckets, heap, persistantCache); + InitBuckets(tableSize, bucketSize, _buckets, factory, persistantCache); } - private static void InitBuckets(uint size, uint bucketSize, IBlobCacheBucket[] table, IUnmangedHeap heap, IPersistantCacheStore? persistantCache) + private static void InitBuckets(uint size, uint bucketSize, IBlobCacheBucket[] table, ICacheMemoryManagerFactory man, IPersistantCacheStore? persistantCache) { for(uint i = 0; i < size; i++) { - table[i] = new BlobCacheBucket(i, (int)bucketSize, heap, persistantCache); + //Get the memory manager for the bucket + ICacheEntryMemoryManager manager = man.CreateForBucket(i); + + table[i] = new BlobCacheBucket(i, (int)bucketSize, manager, persistantCache); } } @@ -143,5 +160,12 @@ namespace VNLib.Data.Caching.ObjectCache Check(); return _buckets.AsEnumerable().GetEnumerator(); } + + private sealed record class SharedMemManager(ICacheEntryMemoryManager Manager) : ICacheMemoryManagerFactory + { + ///<inheritdoc/> + public ICacheEntryMemoryManager CreateForBucket(uint bucketId) => Manager; + + } } } diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/CacheEntry.cs b/lib/VNLib.Data.Caching.ObjectCache/src/CacheEntry.cs index 9183d0a..917052f 100644 --- a/lib/VNLib.Data.Caching.ObjectCache/src/CacheEntry.cs +++ b/lib/VNLib.Data.Caching.ObjectCache/src/CacheEntry.cs @@ -29,10 +29,10 @@ using System.Buffers.Binary; using System.Runtime.CompilerServices; using VNLib.Utils.Memory; -using VNLib.Utils.Extensions; namespace VNLib.Data.Caching { + /// <summary> /// A structure that represents an item in cache. It contains the binary content /// of a cache entry by its internal memory handle @@ -45,28 +45,28 @@ namespace VNLib.Data.Caching private const int DATA_SEGMENT_START = TIME_SEGMENT_SIZE + LENGTH_SEGMENT_SIZE; - - //Only contain ref to backing handle to keep struct size small - private readonly MemoryHandle<byte> _handle; - + private readonly ICacheEntryMemoryManager _manager; + private readonly object _handle; /// <summary> /// Creates a new <see cref="CacheEntry"/> and copies the initial data to the internal buffer /// </summary> /// <param name="data">The initial data to store</param> - /// <param name="heap">The heap to allocate the buffer from</param> + /// <param name="dataManager">The heap to allocate the buffer from</param> /// <returns>The newly initialized and ready to use <see cref="CacheEntry"/></returns> - public static CacheEntry Create(ReadOnlySpan<byte> data, IUnmangedHeap heap) + /// <exception cref="ArgumentNullException"></exception> + public static CacheEntry Create(ReadOnlySpan<byte> data, ICacheEntryMemoryManager dataManager) { + _ = dataManager ?? throw new ArgumentNullException(nameof(dataManager)); + //Calc buffer size - int bufferSize = GetRequiredHandleSize(data.Length); + uint bufferSize = GetRequiredHandleSize(data.Length); - //Alloc buffer - MemoryHandle<byte> handle = heap.Alloc<byte>(bufferSize); + object handle = dataManager.AllocHandle(bufferSize); //Create new entry from handle - CacheEntry entry = new (handle); - entry.SetLength(data.Length); + CacheEntry entry = new(dataManager, handle); + entry.SetLength((uint)data.Length); //Get the data segment Span<byte> segment = entry.GetDataSegment(); @@ -79,24 +79,46 @@ namespace VNLib.Data.Caching return entry; } + /// <summary> + /// Creates a new <see cref="CacheEntry"/> from an existing handle + /// </summary> + /// <param name="handle">The cache data handle to create the entry around</param> + /// <param name="manager">The cache entry memory manager the handle blongs to</param> + /// <returns>The re-constructed entry</returns> + /// <exception cref="ArgumentNullException"></exception> + /// <exception cref="ArgumentException"></exception> + public static CacheEntry FromExistingHandle(object handle, ICacheEntryMemoryManager manager) + { + _ = handle ?? throw new ArgumentNullException(nameof(handle)); + _ = manager ?? throw new ArgumentNullException(nameof(manager)); + + //validate handle size it at least the minimum size + if (manager.GetHandleSize(handle) < DATA_SEGMENT_START) + { + throw new ArgumentException("Memory segment is too small to be a valid cache entry"); + } + + return new(manager, handle); + } - private static int GetRequiredHandleSize(int size) + private static uint GetRequiredHandleSize(int size) { //Caculate the minimum handle size to store all required information, rounded to nearest page - return (int)MemoryUtil.NearestPage(size + DATA_SEGMENT_START); + return (uint)MemoryUtil.NearestPage(size + DATA_SEGMENT_START); } - private CacheEntry(MemoryHandle<byte> handle) + private CacheEntry(ICacheEntryMemoryManager manager, object handle) { + _manager = manager; _handle = handle; } ///<inheritdoc/> - public readonly void Dispose() => _handle?.Dispose(); + public readonly void Dispose() => _manager?.FreeHandle(_handle); - private readonly Span<byte> GetTimeSegment() => _handle.AsSpan(0, TIME_SEGMENT_SIZE); + private readonly Span<byte> GetTimeSegment() => _manager.GetSpan(_handle, 0, TIME_SEGMENT_SIZE); - private readonly Span<byte> GetLengthSegment() => _handle.AsSpan(TIME_SEGMENT_SIZE, LENGTH_SEGMENT_SIZE); + private readonly Span<byte> GetLengthSegment() => _manager.GetSpan(_handle, TIME_SEGMENT_SIZE, LENGTH_SEGMENT_SIZE); /// <summary> /// Gets the size of the block of memory held by the underlying handle @@ -104,11 +126,7 @@ namespace VNLib.Data.Caching /// <returns>The size of the block held by the current entry</returns> /// <exception cref="ObjectDisposedException"></exception> [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly nuint GetMemoryUsage() - { - _handle.ThrowIfClosed(); - return _handle.ByteLength; - } + public readonly nuint GetMemoryUsage() => _manager.GetHandleSize(_handle); /// <summary> /// Gets the last set time @@ -148,21 +166,21 @@ namespace VNLib.Data.Caching /// <returns>The length of the data segment</returns> /// <exception cref="ObjectDisposedException"></exception> [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly int GetLength() + public readonly uint GetLength() { //Get the length segment ReadOnlySpan<byte> segment = GetLengthSegment(); //Recover the integer - return BinaryPrimitives.ReadInt32BigEndian(segment); + return BinaryPrimitives.ReadUInt32BigEndian(segment); } - private readonly void SetLength(int length) + private readonly void SetLength(uint length) { //Get the length segment Span<byte> segment = GetLengthSegment(); //Update the length value - BinaryPrimitives.WriteInt32BigEndian(segment, length); + BinaryPrimitives.WriteUInt32BigEndian(segment, length); } /// <summary> @@ -174,9 +192,9 @@ namespace VNLib.Data.Caching public readonly Span<byte> GetDataSegment() { //Get the actual length of the segment - int length = GetLength(); + uint length = GetLength(); //Get the segment from its begining offset and - return _handle.AsSpan(DATA_SEGMENT_START, length); + return _manager.GetSpan(_handle, DATA_SEGMENT_START, length); } /// <summary> @@ -188,13 +206,17 @@ namespace VNLib.Data.Caching public readonly void UpdateData(ReadOnlySpan<byte> data) { //Calc required buffer size - int bufferSize = GetRequiredHandleSize(data.Length); + uint bufferSize = GetRequiredHandleSize(data.Length); - //Resize handle if required - _handle.ResizeIfSmaller(bufferSize); + //Resize buffer if necessary + if(_manager.GetHandleSize(_handle) < bufferSize) + { + //resize handle + _manager.ResizeHandle(_handle, bufferSize); + } //Reset data length - SetLength(data.Length); + SetLength((uint)data.Length); //Get the data segment Span<byte> segment = GetDataSegment(); @@ -206,9 +228,6 @@ namespace VNLib.Data.Caching data.CopyTo(segment); } - ///<inheritdoc/> - public override int GetHashCode() => _handle.GetHashCode(); - /// <summary> /// Gets a <see cref="MemoryHandle"/> offset to the start of the /// internal data segment, and avoids calling the fixed keyword. @@ -216,14 +235,25 @@ namespace VNLib.Data.Caching /// </summary> /// <remarks> /// WARNING: You must respect the <see cref="GetLength"/> return value so - /// as no to overrun the valid data segment. + /// as not to overrun the valid data segment. /// </remarks> /// <returns>A handle that points to the begining of the data segment</returns> [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly MemoryHandle UnsafeGetDataSegmentHandle() { //Get the handle offset to the data segment start, the caller must know when the data segment ends - return _handle.Pin(DATA_SEGMENT_START); + return _manager.PinHandle(_handle, DATA_SEGMENT_START); + } + + /// <summary> + /// Gets the internal memory handle and manager its associated with + /// </summary> + /// <param name="handle">The opaque memory handle</param> + /// <param name="manager">The associated memory manager</param> + public readonly void GetInternalHandle(out object handle, out ICacheEntryMemoryManager manager) + { + handle = _handle; + manager = _manager; } } } diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/IBlobCache.cs b/lib/VNLib.Data.Caching.ObjectCache/src/IBlobCache.cs index bc3180b..7333898 100644 --- a/lib/VNLib.Data.Caching.ObjectCache/src/IBlobCache.cs +++ b/lib/VNLib.Data.Caching.ObjectCache/src/IBlobCache.cs @@ -25,8 +25,6 @@ using System; using System.Collections.Generic; -using VNLib.Utils.Memory; - namespace VNLib.Data.Caching.ObjectCache { /// <summary> @@ -40,9 +38,9 @@ namespace VNLib.Data.Caching.ObjectCache public uint BucketId { get; } /// <summary> - /// The internal heap used to allocate <see cref="CacheEntry"/> buffers + /// The memory manager used to create <see cref="CacheEntry"/> memory handles /// </summary> - IUnmangedHeap CacheHeap { get; } + ICacheEntryMemoryManager MemoryManager { get; } /// <summary> /// Attempts to retreive the entry at the given id. diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/IBlobCacheBucket.cs b/lib/VNLib.Data.Caching.ObjectCache/src/IBlobCacheBucket.cs index dbe095c..b506600 100644 --- a/lib/VNLib.Data.Caching.ObjectCache/src/IBlobCacheBucket.cs +++ b/lib/VNLib.Data.Caching.ObjectCache/src/IBlobCacheBucket.cs @@ -40,15 +40,6 @@ namespace VNLib.Data.Caching.ObjectCache uint Id { get; } /// <summary> - /// Gets a <see cref="CacheBucketHandle"/> that holds an exclusive lock - /// for the current bucekt and holds a referrence to the stored - /// <see cref="IBlobCache"/> - /// </summary> - /// <param name="cancellation">A token to cancel the wait operation</param> - /// <returns>A <see cref="CacheBucketHandle"/> that holds the <see cref="IBlobCache"/> referrence</returns> - ValueTask<CacheBucketHandle> WaitAsync(CancellationToken cancellation); - - /// <summary> /// Allows for waiting for the cache directly, IE without receiving a lock handle /// </summary> /// <param name="cancellation"></param> @@ -56,7 +47,7 @@ namespace VNLib.Data.Caching.ObjectCache ValueTask<IBlobCache> ManualWaitAsync(CancellationToken cancellation); /// <summary> - /// Releases an exlcusive lock on the current bucket, DO NOT CALL BY USER CODE + /// Releases an exlcusive lock on the current bucket that was obtained by <see cref="ManualWaitAsync(CancellationToken)"/> /// </summary> void Release(); } diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/ICacheEntryMemoryManager.cs b/lib/VNLib.Data.Caching.ObjectCache/src/ICacheEntryMemoryManager.cs new file mode 100644 index 0000000..dffbfa2 --- /dev/null +++ b/lib/VNLib.Data.Caching.ObjectCache/src/ICacheEntryMemoryManager.cs @@ -0,0 +1,80 @@ +/* +* Copyright (c) 2023 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.Data.Caching.ObjectCache +* File: ICacheEntryMemoryManager.cs +* +* ICacheEntryMemoryManager.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; +using System.Buffers; + +namespace VNLib.Data.Caching +{ + /// <summary> + /// Provides a way to allocate and manage opaque memory hanles for a cache entry data + /// </summary> + public interface ICacheEntryMemoryManager + { + /// <summary> + /// Allocates a new handle of at-least the specified size or larger. + /// </summary> + /// <param name="size">The desired minimum size of the handle</param> + /// <returns>A referrence to the newly allocated handle</returns> + object AllocHandle(uint size); + + /// <summary> + /// Resizes the handle to the new size. Usually a larger size + /// than the current size. + /// </summary> + /// <param name="handle">A referrence to the existing handle</param> + /// <param name="newSize"></param> + void ResizeHandle(object handle, uint newSize); + + /// <summary> + /// Frees the prevously allocated handle + /// </summary> + /// <param name="handle">A referrence to the previously allocated handle</param> + void FreeHandle(object handle); + + /// <summary> + /// Pins the handle to the specified offset and returns a + /// <see cref="MemoryHandle"/> to the pinned memory block. + /// </summary> + /// <param name="handle"></param> + /// <param name="offset"></param> + /// <returns></returns> + MemoryHandle PinHandle(object handle, int offset); + + /// <summary> + /// Gets the full usable size of the memory block held by the handle + /// </summary> + /// <returns>The number of bytes available for access</returns> + uint GetHandleSize(object handle); + + /// <summary> + /// Gets a segment of the memory block held by the handle for reading/writing + /// </summary> + /// <param name="handle">A referrence to the handle object</param> + /// <param name="offset">The data offset in bytes for the start of the desired memory block</param> + /// <param name="length">The desired size of the block in bytes</param> + /// <returns>A span with the desired offset of the desired length</returns> + Span<byte> GetSpan(object handle, uint offset, uint length); + } +} diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/ICacheMemoryManagerFactory.cs b/lib/VNLib.Data.Caching.ObjectCache/src/ICacheMemoryManagerFactory.cs new file mode 100644 index 0000000..99a3b66 --- /dev/null +++ b/lib/VNLib.Data.Caching.ObjectCache/src/ICacheMemoryManagerFactory.cs @@ -0,0 +1,41 @@ +/* +* Copyright (c) 2023 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.Data.Caching.ObjectCache +* File: ICacheMemoryManagerFactory.cs +* +* ICacheMemoryManagerFactory.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/. +*/ + +namespace VNLib.Data.Caching.ObjectCache +{ + /// <summary> + /// Provides bucket-local memory managers for <see cref="IBlobCacheBucket"/>s + /// to use for their internal memory management + /// </summary> + public interface ICacheMemoryManagerFactory + { + /// <summary> + /// Creates a new <see cref="ICacheEntryMemoryManager"/> for the specified bucket + /// identified by the given <paramref name="bucketId"/> + /// </summary> + /// <param name="bucketId">The unique id of a bucket within the table</param> + /// <returns></returns> + ICacheEntryMemoryManager CreateForBucket(uint bucketId); + } +} |