From dc7ad57c845cc9b1b502e5e8b12ce96af4183dc4 Mon Sep 17 00:00:00 2001 From: vman Date: Fri, 18 Nov 2022 17:15:36 -0500 Subject: Add project files. --- VNLib.Data.Caching/src/BlobItem.cs | 185 +++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 VNLib.Data.Caching/src/BlobItem.cs (limited to 'VNLib.Data.Caching/src/BlobItem.cs') diff --git a/VNLib.Data.Caching/src/BlobItem.cs b/VNLib.Data.Caching/src/BlobItem.cs new file mode 100644 index 0000000..a5630e9 --- /dev/null +++ b/VNLib.Data.Caching/src/BlobItem.cs @@ -0,0 +1,185 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +using VNLib.Utils; +using VNLib.Utils.IO; +using VNLib.Utils.Memory; +using VNLib.Utils.Logging; +using VNLib.Utils.Extensions; + +#nullable enable + +namespace VNLib.Data.Caching +{ + /// + /// A general purpose binary storage item + /// + public class BlobItem //: VnDisposeable + { + /* + private static readonly JoinableTaskContext JTX = new(); + private static readonly Semaphore CentralSwapLock = new(Environment.ProcessorCount, Environment.ProcessorCount); + + private readonly VnMemoryStream _loadedData; + private bool _loaded; + + /// + /// The time the blob was last modified + /// + public DateTimeOffset LastAccessed { get; private set; } + + + /// + /// Gets the current size of the file (in bytes) as an atomic operation + /// + public int FileSize => (int)_loadedData.Length; + /// + /// The operation synchronization lock + /// + public AsyncReaderWriterLock OpLock { get; } + /// + /// Initializes a new + /// + /// The heap to allocate buffers from + internal BlobItem(IUnmangedHeap heap) + { + _loadedData = new(heap); + OpLock = new AsyncReaderWriterLock(JTX); + _loaded = true; + LastAccessed = DateTimeOffset.UtcNow; + } + /// + protected override void Free() + { + _loadedData.Dispose(); + OpLock.Dispose(); + } + + /// + /// Reads data from the internal buffer and copies it to the specified buffer. + /// Use the property to obtain the size of the internal buffer + /// + /// The buffer to copy data to + /// When completed, the number of bytes copied to the buffer + public int Read(Span buffer) + { + //Make sure the blob has been swapped back into memory + if (!_loaded) + { + throw new InvalidOperationException("The blob was not loaded from the disk"); + } + //Read all data from the buffer and write it to the output buffer + _loadedData.AsSpan().CopyTo(buffer); + //Update last-accessed + LastAccessed = DateTimeOffset.UtcNow; + return (int)_loadedData.Length; + } + /// + /// Overwrites the internal buffer with the contents of the supplied buffer + /// + /// The buffer containing data to store within the blob + /// A that completes when write access has been granted and copied + /// + public void Write(ReadOnlySpan buffer) + { + //Make sure the blob has been swapped back into memory + if (!_loaded) + { + throw new InvalidOperationException("The blob was not loaded from the disk"); + } + //Reset the buffer + _loadedData.SetLength(buffer.Length); + _loadedData.Seek(0, SeekOrigin.Begin); + _loadedData.Write(buffer); + LastAccessed = DateTimeOffset.UtcNow; + } + + /// + /// Writes the contents of the memory buffer to its designated file on the disk + /// + /// The heap to allocate buffers from + /// The that stores the file + /// The name of the file to write data do + /// A log to write errors to + /// A task that completes when the swap to disk is complete + internal async Task SwapToDiskAsync(IUnmangedHeap heap, DirectoryInfo swapDir, string filename, ILogProvider log) + { + try + { + //Wait for write lock + await using (AsyncReaderWriterLock.Releaser releaser = await OpLock.WriteLockAsync()) + { + //Enter swap lock + await CentralSwapLock; + try + { + //Open swap file data stream + await using FileStream swapFile = swapDir.OpenFile(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite, bufferSize: 8128); + //reset swap file + swapFile.SetLength(0); + //Seek loaded-data back to 0 before writing + _loadedData.Seek(0, SeekOrigin.Begin); + //Write loaded data to disk + await _loadedData.CopyToAsync(swapFile, 8128, heap); + } + finally + { + CentralSwapLock.Release(); + } + //Release memory held by stream + _loadedData.SetLength(0); + //Clear loaded flag + _loaded = false; + LastAccessed = DateTimeOffset.UtcNow; + } + log.Debug("Blob {name} swapped to disk", filename); + } + catch(Exception ex) + { + log.Error(ex, "Blob swap to disk error"); + } + } + /// + /// Reads the contents of the blob into a memory buffer from its designated file on disk + /// + /// The heap to allocate buffers from + /// The that stores the file + /// The name of the file to write the blob data to + /// A log to write errors to + /// A task that completes when the swap from disk is complete + internal async Task SwapFromDiskAsync(IUnmangedHeap heap, DirectoryInfo swapDir, string filename, ILogProvider log) + { + try + { + //Wait for write lock + await using (AsyncReaderWriterLock.Releaser releaser = await OpLock.WriteLockAsync()) + { + //Enter swap lock + await CentralSwapLock; + try + { + //Open swap file data stream + await using FileStream swapFile = swapDir.OpenFile(filename, FileMode.OpenOrCreate, FileAccess.Read, bufferSize:8128); + //Copy from disk to memory + await swapFile.CopyToAsync(_loadedData, 8128, heap); + } + finally + { + CentralSwapLock.Release(); + } + //Set loaded flag + _loaded = true; + LastAccessed = DateTimeOffset.UtcNow; + } + log.Debug("Blob {name} swapped from disk", filename); + } + catch(Exception ex) + { + log.Error(ex, "Blob swap from disk error"); + } + } + */ + } +} -- cgit