/*
* Copyright (c) 2022 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Data.Caching.ObjectCache
* File: BlobCache.cs
*
* BlobCache.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.IO;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using VNLib.Utils.IO;
using VNLib.Utils.Logging;
using VNLib.Utils.Memory;
using VNLib.Utils.Memory.Caching;
namespace VNLib.Data.Caching
{
///
/// A general purpose binary data storage
///
public class BlobCache : LRUCache>
{
readonly IUnmangedHeap Heap;
readonly DirectoryInfo SwapDir;
readonly ILogProvider Log;
///
public override bool IsReadOnly { get; }
///
protected override int MaxCapacity { get; }
///
/// Initializes a new store
///
/// The to swap blob data to when cache
/// The maximum number of items to keep in memory
/// A to write log data to
/// A to allocate buffers and store data in memory
public BlobCache(DirectoryInfo swapDir, int maxCapacity, ILogProvider log, IUnmangedHeap heap)
:base(StringComparer.Ordinal)
{
IsReadOnly = false;
MaxCapacity = maxCapacity;
SwapDir = swapDir;
//Update the lookup table size
LookupTable.EnsureCapacity(maxCapacity);
//Set default heap if not specified
Heap = heap;
Log = log;
}
///
protected override bool CacheMiss(string key, [NotNullWhen(true)] out MemoryHandle? value)
{
value = null;
return false;
}
///
protected override void Evicted(KeyValuePair> evicted)
{
//Dispose the blob
evicted.Value.Dispose();
}
///
/// If the is found in the store, changes the key
/// that referrences the blob.
///
/// The key that currently referrences the blob in the store
/// The new key that will referrence the blob
/// The if its found in the store
/// True if the record was found and the key was changes
public bool TryChangeKey(string currentKey, string newKey, [NotNullWhen(true)] out MemoryHandle? blob)
{
if (LookupTable.Remove(currentKey, out LinkedListNode>>? node))
{
//Remove the node from the ll
List.Remove(node);
//Update the node kvp
blob = node.Value.Value;
node.Value = new KeyValuePair>(newKey, blob);
//Add to end of list
List.AddLast(node);
//Re-add to lookup table with new key
LookupTable.Add(newKey, node);
return true;
}
blob = null;
return false;
}
///
/// Removes the from the store without disposing the blobl
///
/// The key that referrences the in the store
/// A value indicating if the blob was removed
public override bool Remove(string key)
{
//Remove the item from the lookup table and if it exists, remove the node from the list
if (LookupTable.Remove(key, out LinkedListNode>>? node))
{
//Remove the new from the list
List.Remove(node);
//dispose the buffer
node.Value.Value.Dispose();
return true;
}
return false;
}
///
/// Removes and disposes all blobl elements in cache (or in the backing store)
///
public override void Clear()
{
foreach (MemoryHandle blob in List.Select(kp => kp.Value))
{
blob.Dispose();
}
base.Clear();
}
}
}