aboutsummaryrefslogtreecommitdiff
path: root/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheTable.cs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheTable.cs')
-rw-r--r--lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheTable.cs139
1 files changed, 139 insertions, 0 deletions
diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheTable.cs b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheTable.cs
new file mode 100644
index 0000000..270cf1e
--- /dev/null
+++ b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheTable.cs
@@ -0,0 +1,139 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Data.Caching.ObjectCache
+* File: BlobCacheTable.cs
+*
+* BlobCacheTable.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.Linq;
+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>
+ public sealed class BlobCacheTable : VnDisposeable, IBlobCacheTable
+ {
+ private readonly uint _tableSize;
+ private readonly IBlobCacheBucket[] _buckets;
+
+ /// <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>
+ /// <exception cref="ArgumentNullException"></exception>
+ /// <exception cref="ArgumentException"></exception>
+ public BlobCacheTable(uint tableSize, uint bucketSize, IUnmangedHeap heap)
+ {
+ _ = heap ?? throw new ArgumentNullException(nameof(heap));
+
+ if(tableSize == 0)
+ {
+ throw new ArgumentException("Cache table must have atleast 1 bucket");
+ }
+
+ //Init bucket table
+ _tableSize = tableSize;
+ _buckets = new IBlobCacheBucket[tableSize];
+
+ //Init buckets
+ InitBuckets(tableSize, bucketSize, _buckets, heap);
+ }
+
+
+ private static void InitBuckets(uint size, uint bucketSize, IBlobCacheBucket[] table, IUnmangedHeap heap)
+ {
+ for(int i = 0; i < size; i++)
+ {
+ table[i] = new BlobCacheBucket((int)bucketSize, heap);
+ }
+ }
+
+ /*
+ * A very simple algorithm that captures unique values
+ * from an object id and builds an unsigned 32bit integer
+ * used to determine the bucked index within the table.
+ *
+ * This method will alawys result in the same index for
+ * for a given object-id
+ */
+
+ private uint FastGetBucketIndexFromId(ReadOnlySpan<char> objectId)
+ {
+ if (objectId.Length < 4)
+ {
+ throw new ArgumentException("Object id must be larger than 3 characters");
+ }
+
+ Span<byte> buffer = stackalloc byte[4];
+
+ //cast the characters
+ buffer[0] = (byte)objectId[0];
+ buffer[1] = (byte)objectId[objectId.Length / 2];
+ buffer[2] = (byte)objectId[1];
+ buffer[3] = (byte)objectId[^1];
+
+ //Read the buffer back to a uint and mod by the table size to get the bucket index
+ return BitConverter.ToUInt32(buffer) % _tableSize;
+ }
+
+
+ ///<inheritdoc/>
+ ///<exception cref="ObjectDisposedException"></exception>
+ public IBlobCacheBucket GetBucket(ReadOnlySpan<char> objectId)
+ {
+ Check();
+
+ //If tablesize is 1, skip lookup, otherwise perform bucket index lookup
+ uint index = _tableSize == 1 ? 0 : FastGetBucketIndexFromId(objectId);
+
+ return _buckets[index];
+ }
+
+ ///<inheritdoc/>
+ protected sealed override void Free()
+ {
+ //Dispose buckets
+ Array.ForEach(_buckets, static b => b.Dispose());
+ }
+
+ ///<inheritdoc/>
+ public IEnumerator<IBlobCacheBucket> GetEnumerator()
+ {
+ Check();
+ return _buckets.AsEnumerable().GetEnumerator();
+ }
+
+ ///<inheritdoc/>
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ Check();
+ return _buckets.AsEnumerable().GetEnumerator();
+ }
+ }
+}