aboutsummaryrefslogtreecommitdiff
path: root/lib/VNLib.Data.Caching.ObjectCache/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/VNLib.Data.Caching.ObjectCache/src')
-rw-r--r--lib/VNLib.Data.Caching.ObjectCache/src/BlobCache.cs57
-rw-r--r--lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheBucket.cs14
-rw-r--r--lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheLIstener.cs23
-rw-r--r--lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheTable.cs22
-rw-r--r--lib/VNLib.Data.Caching.ObjectCache/src/CacheEntry.cs39
-rw-r--r--lib/VNLib.Data.Caching.ObjectCache/src/IBlobCache.cs5
-rw-r--r--lib/VNLib.Data.Caching.ObjectCache/src/IBlobCacheBucket.cs11
-rw-r--r--lib/VNLib.Data.Caching.ObjectCache/src/IMemoryCacheEntryFactory.cs43
-rw-r--r--lib/VNLib.Data.Caching.ObjectCache/src/IPersistantCacheStore.cs79
9 files changed, 242 insertions, 51 deletions
diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCache.cs b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCache.cs
index 440981a..f77587b 100644
--- a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCache.cs
+++ b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCache.cs
@@ -23,8 +23,8 @@
*/
using System;
-using System.Collections.Generic;
using System.Diagnostics;
+using System.Collections.Generic;
using VNLib.Utils.Memory;
using VNLib.Utils.Memory.Caching;
@@ -35,9 +35,10 @@ namespace VNLib.Data.Caching.ObjectCache
/// <summary>
/// A general purpose binary data storage
/// </summary>
- public sealed class BlobCache : LRUCache<string, CacheEntry>, IBlobCache
+ public sealed class BlobCache : LRUCache<string, CacheEntry>, IBlobCache, IMemoryCacheEntryFactory
{
private bool disposedValue;
+ private IPersistantCacheStore? _persistance;
///<inheritdoc/>
public override bool IsReadOnly { get; }
@@ -48,21 +49,29 @@ namespace VNLib.Data.Caching.ObjectCache
///<inheritdoc/>
public IUnmangedHeap CacheHeap { get; }
+ ///<inheritdoc/>
+ public uint BucketId { get; }
/// <summary>
/// Initializes a new <see cref="BlobCache"/> store
/// </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="store">The optional backing persistant cache storage</param>
/// <exception cref="ArgumentException"></exception>
- public BlobCache(int maxCapacity, IUnmangedHeap heap)
- :base(StringComparer.Ordinal)
+ public BlobCache(uint bucketId, int maxCapacity, IUnmangedHeap heap, 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));
}
+ BucketId = bucketId;
+
+ _persistance = store;
+
CacheHeap = heap;
MaxCapacity = maxCapacity;
@@ -74,19 +83,32 @@ namespace VNLib.Data.Caching.ObjectCache
///<inheritdoc/>
protected override bool CacheMiss(string key, out CacheEntry value)
{
- value = default;
- return false;
+ if(_persistance == null)
+ {
+ value = default;
+ return false;
+ }
+ //Use the persistant cache
+ return _persistance.OnCacheMiss(BucketId, key, this, out value);
}
///<inheritdoc/>
protected override void Evicted(ref KeyValuePair<string, CacheEntry> evicted)
{
- //Dispose the cache item
- evicted.Value.Dispose();
+ try
+ {
+ //Call persistance store record eviction
+ _persistance?.OnEntryEvicted(BucketId, evicted.Key, evicted.Value);
+ }
+ finally
+ {
+ //Dispose the cache item
+ evicted.Value.Dispose();
+ }
}
///<inheritdoc/>
- public bool TryChangeKey(string objectId, string newId, out CacheEntry blob)
+ public bool TryChangeKey(string objectId, string newId, out CacheEntry entry)
{
//Try to get the node at the current key
if (LookupTable.Remove(objectId, out LinkedListNode<KeyValuePair<string, CacheEntry>> ? node))
@@ -95,10 +117,10 @@ namespace VNLib.Data.Caching.ObjectCache
List.Remove(node);
//Get the stored blob
- blob = node.ValueRef.Value;
+ entry = node.ValueRef.Value;
//Update the
- node.Value = new KeyValuePair<string, CacheEntry>(newId, blob);
+ node.Value = new KeyValuePair<string, CacheEntry>(newId, entry);
//Add to end of list
List.AddLast(node);
@@ -109,13 +131,16 @@ namespace VNLib.Data.Caching.ObjectCache
return true;
}
- blob = default;
+ entry = default;
return false;
}
///<inheritdoc/>
public override bool Remove(string key)
{
+ //Remove from persistant store also
+ _persistance?.OnEntryDeleted(BucketId, key);
+
//Remove the item from the lookup table and if it exists, remove the node from the list
if (!LookupTable.Remove(key, out LinkedListNode<KeyValuePair<string, CacheEntry>>? node))
{
@@ -192,5 +217,13 @@ 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, CacheHeap);
+ }
}
}
diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheBucket.cs b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheBucket.cs
index f79db3f..6af1a20 100644
--- a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheBucket.cs
+++ b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheBucket.cs
@@ -29,11 +29,18 @@ using VNLib.Utils.Memory;
namespace VNLib.Data.Caching.ObjectCache
{
+
+ /// <summary>
+ /// A concrete implementation of an <see cref="IBlobCacheBucket"/>
+ /// </summary>
public sealed class BlobCacheBucket : IBlobCacheBucket
{
private readonly IBlobCache _cacheTable;
private readonly SemaphoreSlim _lock;
+ ///<inheritdoc/>
+ public uint Id { get; }
+
/// <summary>
/// Initialzies a new <see cref="BlobCacheBucket"/> and its underlying
/// <see cref="IBlobCache"/>
@@ -42,11 +49,14 @@ namespace VNLib.Data.Caching.ObjectCache
/// The maxium number of entries allowed in the LRU cache
/// 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>
- public BlobCacheBucket(int bucketCapacity, IUnmangedHeap heap)
+ /// <param name="persistantCache">An optional <see cref="IPersistantCacheStore"/> for cache persistance</param>
+ public BlobCacheBucket(uint bucketId, int bucketCapacity, IUnmangedHeap heap, IPersistantCacheStore? persistantCache)
{
+ Id = bucketId;
_lock = new(1, 1);
- _cacheTable = new BlobCache(bucketCapacity, heap);
+ _cacheTable = new BlobCache(bucketId, bucketCapacity, heap, persistantCache);
}
///<inheritdoc/>
diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheLIstener.cs b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheLIstener.cs
index 818dfcf..f69c2a4 100644
--- a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheLIstener.cs
+++ b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheLIstener.cs
@@ -3,9 +3,9 @@
*
* Library: VNLib
* Package: VNLib.Data.Caching.ObjectCache
-* File: BlobCacheLIstener.cs
+* File: BlobCacheListener.cs
*
-* BlobCacheLIstener.cs is part of VNLib.Data.Caching.ObjectCache which is part of the larger
+* BlobCacheListener.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
@@ -53,9 +53,9 @@ namespace VNLib.Data.Caching.ObjectCache
public delegate ReadOnlySpan<byte> GetBodyDataCallback<T>(T state);
/// <summary>
- /// A <see cref="FBMListener"/> implementation of a <see cref="CacheListener"/>
+ /// An <see cref="FBMListener"/> for key-value object data caching servers.
/// </summary>
- public class BlobCacheLIstener : FBMListenerBase, IDisposable
+ public class BlobCacheListener : FBMListenerBase, IDisposable
{
private bool disposedValue;
@@ -74,21 +74,22 @@ namespace VNLib.Data.Caching.ObjectCache
/// <summary>
- /// Initialzies a new <see cref="BlobCacheLIstener"/>
+ /// Initialzies a new <see cref="BlobCacheListener"/>
/// </summary>
- /// <param name="cacheMax">The maxium number of items per bucket</param>
- /// <param name="buckets">The number of cache store buckets</param>
- /// <param name="log"></param>
+ /// <param name="cache">The cache table to work from</param>
+ /// <param name="log">Writes error and debug logging information</param>
/// <param name="heap">The heap to alloc FBM buffers and <see cref="CacheEntry"/> cache buffers from</param>
/// <param name="singleReader">A value that indicates if a single thread is processing events</param>
- public BlobCacheLIstener(uint buckets, uint cacheMax, ILogProvider log, IUnmangedHeap heap, bool singleReader)
+ /// <exception cref="ArgumentNullException"></exception>
+ public BlobCacheListener(IBlobCacheTable cache, ILogProvider log, IUnmangedHeap heap, bool singleReader)
{
Log = log;
+ Cache = cache ?? throw new ArgumentNullException(nameof(cache));
+
//Writes may happen from multple threads with bucket design and no lock
EventQueue = new(false, singleReader);
-
- Cache = new BlobCacheTable(buckets, cacheMax, heap);
+
InitListener(heap);
}
diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheTable.cs b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheTable.cs
index 270cf1e..f3f1b50 100644
--- a/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheTable.cs
+++ b/lib/VNLib.Data.Caching.ObjectCache/src/BlobCacheTable.cs
@@ -39,6 +39,7 @@ namespace VNLib.Data.Caching.ObjectCache
{
private readonly uint _tableSize;
private readonly IBlobCacheBucket[] _buckets;
+ private readonly IPersistantCacheStore? _persistant;
/// <summary>
/// Initializes a new <see cref="BlobCacheTable"/>
@@ -46,9 +47,10 @@ namespace VNLib.Data.Caching.ObjectCache
/// <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="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)
+ public BlobCacheTable(uint tableSize, uint bucketSize, IUnmangedHeap heap, IPersistantCacheStore? persistantCache)
{
_ = heap ?? throw new ArgumentNullException(nameof(heap));
@@ -61,16 +63,18 @@ namespace VNLib.Data.Caching.ObjectCache
_tableSize = tableSize;
_buckets = new IBlobCacheBucket[tableSize];
+ _persistant = persistantCache;
+
//Init buckets
- InitBuckets(tableSize, bucketSize, _buckets, heap);
+ InitBuckets(tableSize, bucketSize, _buckets, heap, persistantCache);
}
- private static void InitBuckets(uint size, uint bucketSize, IBlobCacheBucket[] table, IUnmangedHeap heap)
+ private static void InitBuckets(uint size, uint bucketSize, IBlobCacheBucket[] table, IUnmangedHeap heap, IPersistantCacheStore? persistantCache)
{
- for(int i = 0; i < size; i++)
+ for(uint i = 0; i < size; i++)
{
- table[i] = new BlobCacheBucket((int)bucketSize, heap);
+ table[i] = new BlobCacheBucket(i, (int)bucketSize, heap, persistantCache);
}
}
@@ -118,8 +122,12 @@ namespace VNLib.Data.Caching.ObjectCache
///<inheritdoc/>
protected sealed override void Free()
{
- //Dispose buckets
- Array.ForEach(_buckets, static b => b.Dispose());
+ //Dispose persistance store
+ using (_persistant)
+ {
+ //Dispose buckets
+ Array.ForEach(_buckets, static b => b.Dispose());
+ }
}
///<inheritdoc/>
diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/CacheEntry.cs b/lib/VNLib.Data.Caching.ObjectCache/src/CacheEntry.cs
index 3d61790..e778b30 100644
--- a/lib/VNLib.Data.Caching.ObjectCache/src/CacheEntry.cs
+++ b/lib/VNLib.Data.Caching.ObjectCache/src/CacheEntry.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Data.Caching.ObjectCache
@@ -23,19 +23,21 @@
*/
using System;
+using System.Buffers;
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
/// </summary>
- public readonly struct CacheEntry : IDisposable, IEquatable<CacheEntry>
+ public readonly record struct CacheEntry : IDisposable
{
private const int TIME_SEGMENT_SIZE = sizeof(long);
@@ -53,7 +55,7 @@ namespace VNLib.Data.Caching
/// </summary>
/// <param name="data">The initial data to store</param>
/// <param name="heap">The heap to allocate the buffer from</param>
- /// <returns>The new <see cref="CacheEntry"/></returns>
+ /// <returns>The newly initialized and ready to use <see cref="CacheEntry"/></returns>
public static CacheEntry Create(ReadOnlySpan<byte> data, IUnmangedHeap heap)
{
//Calc buffer size
@@ -74,6 +76,7 @@ namespace VNLib.Data.Caching
return entry;
}
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int GetRequiredHandleSize(int size)
{
@@ -202,27 +205,31 @@ namespace VNLib.Data.Caching
Span<byte> segment = GetDataSegment();
#if DEBUG
- //Test segment length is equvalent to the requested data length
+ //Test segment length is equivalent to the requested data length
System.Diagnostics.Debug.Assert(segment.Length == data.Length);
#endif
//Copy data segment
data.CopyTo(segment);
}
-
- ///<inheritdoc/>
- public override bool Equals(object? obj) => obj is CacheEntry entry && Equals(entry);
-
///<inheritdoc/>
public override int GetHashCode() => _handle.GetHashCode();
- ///<inheritdoc/>
- public static bool operator ==(CacheEntry left, CacheEntry right) => left.Equals(right);
-
- ///<inheritdoc/>
- public static bool operator !=(CacheEntry left, CacheEntry right) => !(left == right);
-
- ///<inheritdoc/>
- public bool Equals(CacheEntry other) => other.GetHashCode() == GetHashCode();
+ /// <summary>
+ /// Gets a <see cref="MemoryHandle"/> offset to the start of the
+ /// internal data segment, and avoids calling the fixed keyword.
+ /// The handle must be disposed/released to avoid memeory leaks.
+ /// </summary>
+ /// <remarks>
+ /// WARNING: You must respect the <see cref="GetLength"/> return value so
+ /// as no 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);
+ }
}
}
diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/IBlobCache.cs b/lib/VNLib.Data.Caching.ObjectCache/src/IBlobCache.cs
index 52d53ff..bc3180b 100644
--- a/lib/VNLib.Data.Caching.ObjectCache/src/IBlobCache.cs
+++ b/lib/VNLib.Data.Caching.ObjectCache/src/IBlobCache.cs
@@ -35,6 +35,11 @@ namespace VNLib.Data.Caching.ObjectCache
public interface IBlobCache : IEnumerable<KeyValuePair<string, CacheEntry>>, IDisposable
{
/// <summary>
+ /// The id of the bucket this memory cache belongs to
+ /// </summary>
+ public uint BucketId { get; }
+
+ /// <summary>
/// The internal heap used to allocate <see cref="CacheEntry"/> buffers
/// </summary>
IUnmangedHeap CacheHeap { get; }
diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/IBlobCacheBucket.cs b/lib/VNLib.Data.Caching.ObjectCache/src/IBlobCacheBucket.cs
index 4876c5f..dbe095c 100644
--- a/lib/VNLib.Data.Caching.ObjectCache/src/IBlobCacheBucket.cs
+++ b/lib/VNLib.Data.Caching.ObjectCache/src/IBlobCacheBucket.cs
@@ -3,10 +3,10 @@
*
* Library: VNLib
* Package: VNLib.Data.Caching.ObjectCache
-* File: ObjectCacheStore.cs
+* File: IBlobCacheBucket.cs
*
-* ObjectCacheStore.cs is part of VNLib.Data.Caching.ObjectCache which is part of the larger
-* VNLib collection of libraries and utilities.
+* IBlobCacheBucket.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
@@ -35,6 +35,11 @@ namespace VNLib.Data.Caching.ObjectCache
public interface IBlobCacheBucket : IDisposable
{
/// <summary>
+ /// The unique integer id of a bucket within an <see cref="IBlobCacheTable"/>
+ /// </summary>
+ 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"/>
diff --git a/lib/VNLib.Data.Caching.ObjectCache/src/IMemoryCacheEntryFactory.cs b/lib/VNLib.Data.Caching.ObjectCache/src/IMemoryCacheEntryFactory.cs
new file mode 100644
index 0000000..1454fc0
--- /dev/null
+++ b/lib/VNLib.Data.Caching.ObjectCache/src/IMemoryCacheEntryFactory.cs
@@ -0,0 +1,43 @@
+/*
+* 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
new file mode 100644
index 0000000..40f39f2
--- /dev/null
+++ b/lib/VNLib.Data.Caching.ObjectCache/src/IPersistantCacheStore.cs
@@ -0,0 +1,79 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Data.Caching.ObjectCache
+* File: IPersistantCacheStore.cs
+*
+* IPersistantCacheStore.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>
+ /// Provides a persitance layer to memory caching.
+ /// </summary>
+ public interface IPersistantCacheStore : IDisposable
+ {
+ /// <summary>
+ /// Invoked when an entry has been evicted from main-memory cache
+ /// and is expected to be stored in a "persistant" storage solution.
+ /// <para>
+ /// When this method returns, the <paramref name="entry"/> is no longer valid.
+ /// </para>
+ /// <para>
+ /// 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>
+ /// </summary>
+ /// <param name="bucketId">The id of the bucket requesting the operation</param>
+ /// <param name="key">The key identifying the the entry</param>
+ /// <param name="entry">The entry containing the object data to store</param>
+ void OnEntryEvicted(uint bucketId, string key, in CacheEntry entry);
+
+ /// <summary>
+ /// Called when a cache item does not exist in main memory cache and should
+ /// be promoted from persistant cache to main memory cache.
+ /// <para>
+ /// 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="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);
+
+ /// <summary>
+ /// Removes an entry from the backing store
+ /// </summary>
+ /// <param name="key">The key identifying the entry to remove</param>
+ /// <param name="bucketId">The id of the bucket requesting the operation</param>
+ void OnEntryDeleted(uint bucketId, string key);
+ }
+}