Skeleton BlockCacheBufferedStorage

This commit is contained in:
Alex Barney 2022-03-10 18:39:59 -07:00
parent c765ab999e
commit eaff8059ba
6 changed files with 286 additions and 3 deletions

View file

@ -287,4 +287,11 @@ public enum SdmmcPort
Mmc = 0,
SdCard = 1,
GcAsic = 2
}
public enum StorageType
{
SaveData = 0,
RomFs = 1,
Authoring = 2
}

View file

@ -0,0 +1,14 @@
using LibHac.Diag;
namespace LibHac.FsSystem;
public static class BitmapUtils
{
public static uint ILog2(uint value)
{
Assert.SdkRequiresGreater(value, 0u);
const uint intBitCount = 32;
return intBitCount - 1 - (uint)Util.BitUtil.CountLeadingZeros(value);
}
}

View file

@ -0,0 +1,249 @@
using System;
using LibHac.Diag;
using LibHac.Fs;
using LibHac.FsSystem.Impl;
using LibHac.Os;
using Buffer = LibHac.Mem.Buffer;
// Todo: Remove warning suppressions after implementing
// ReSharper disable All
#pragma warning disable CS0414
namespace LibHac.FsSystem;
public class BlockCacheBufferedStorage : IStorage
{
public struct CacheEntry : IBlockCacheManagerEntry<AccessRange>
{
public AccessRange Range { get; }
public bool IsValid { get; set; }
public bool IsWriteBack { get; set; }
public bool IsCached { get; set; }
public bool IsFlushing { get; set; }
public short Age { get; set; }
public ulong Handle { get; set; }
public Buffer Buffer { get; set; }
public void Invalidate()
{
throw new NotImplementedException();
}
public readonly bool IsAllocated()
{
throw new NotImplementedException();
}
}
public struct AccessRange : IBlockCacheManagerRange
{
public long Offset { get; set; }
public long Size { get; set; }
public readonly long GetEndOffset()
{
throw new NotImplementedException();
}
public readonly long IsIncluded(long offset)
{
throw new NotImplementedException();
}
}
private SdkRecursiveMutex _mutex;
private IStorage _storageData;
private Result _lastResult;
private long _sizeBytesData;
private int _sizeBytesVerificationBlock;
private int _shiftBytesVerificationBlock;
private int _flags;
private int _bufferLevel;
private StorageType _storageType;
private BlockCacheManager<CacheEntry, AccessRange> _cacheManager;
public BlockCacheBufferedStorage()
{
_bufferLevel = -1;
_cacheManager = new BlockCacheManager<CacheEntry, AccessRange>();
}
public override void Dispose()
{
FinalizeObject();
_cacheManager.Dispose();
base.Dispose();
}
public bool IsEnabledKeepBurstMode()
{
throw new NotImplementedException();
}
public void SetKeepBurstMode(bool isEnabled)
{
throw new NotImplementedException();
}
public void SetRealDataCache(bool isEnabled)
{
throw new NotImplementedException();
}
public Result Initialize(IBufferManager bufferManager, SdkRecursiveMutex mutex, IStorage data, long dataSize,
int sizeBytesVerificationBlock, int maxCacheEntries, bool useRealDataCache, sbyte bufferLevel,
bool useKeepBurstMode, StorageType storageType)
{
Assert.SdkNotNull(data);
Assert.SdkNotNull(mutex);
Assert.SdkNull(_mutex);
Assert.SdkNull(_storageData);
Assert.SdkGreater(maxCacheEntries, 0);
Result rc = _cacheManager.Initialize(bufferManager, maxCacheEntries);
if (rc.IsFailure()) return rc.Miss();
_mutex = mutex;
_storageData = data;
_sizeBytesData = dataSize;
_sizeBytesVerificationBlock = sizeBytesVerificationBlock;
_lastResult = Result.Success;
_flags = 0;
_bufferLevel = bufferLevel;
_storageType = storageType;
_shiftBytesVerificationBlock = (int)BitmapUtils.ILog2((uint)sizeBytesVerificationBlock);
Assert.SdkEqual(1 << _shiftBytesVerificationBlock, _sizeBytesVerificationBlock);
SetKeepBurstMode(useKeepBurstMode);
SetRealDataCache(useRealDataCache);
return Result.Success;
}
public void FinalizeObject()
{
throw new NotImplementedException();
}
public override Result GetSize(out long size)
{
throw new NotImplementedException();
}
public override Result SetSize(long size)
{
throw new NotImplementedException();
}
public override Result Read(long offset, Span<byte> destination)
{
throw new NotImplementedException();
}
public override Result Write(long offset, ReadOnlySpan<byte> source)
{
throw new NotImplementedException();
}
public override Result Flush()
{
throw new NotImplementedException();
}
public override Result OperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
ReadOnlySpan<byte> inBuffer)
{
throw new NotImplementedException();
}
public Result Commit()
{
throw new NotImplementedException();
}
public Result OnRollback()
{
throw new NotImplementedException();
}
private Result FillZeroImpl(long offset, long size)
{
throw new NotImplementedException();
}
private Result DestroySignatureImpl(long offset, long size)
{
throw new NotImplementedException();
}
private Result InvalidateImpl()
{
throw new NotImplementedException();
}
private Result QueryRangeImpl(Span<byte> outBuffer, long offset, long size)
{
throw new NotImplementedException();
}
private Result GetAssociateBuffer(out Buffer outRange, out CacheEntry outEntry, long offset, int idealSize,
bool isAllocateForWrite)
{
throw new NotImplementedException();
}
private Result StoreOrDestroyBuffer(in Buffer memoryRange, ref CacheEntry entry)
{
throw new NotImplementedException();
}
private Result StoreOrDestroyBuffer(out int outCacheIndex, in Buffer memoryRange, ref CacheEntry entry)
{
throw new NotImplementedException();
}
private Result FlushCacheEntry(int index, bool isWithInvalidate)
{
throw new NotImplementedException();
}
private Result FlushRangeCacheEntries(long offset, long size, bool isWithInvalidate)
{
throw new NotImplementedException();
}
private Result FlushAllCacheEntries()
{
throw new NotImplementedException();
}
private Result ControlDirtiness()
{
throw new NotImplementedException();
}
private Result UpdateLastResult(Result result)
{
throw new NotImplementedException();
}
private Result ReadHeadCache(out Buffer outMemoryRange, out CacheEntry outEntry, out bool outIsCacheNeeded,
ref long offset, ref long offsetAligned, long offsetAlignedEnd, ref Span<byte> buffer)
{
throw new NotImplementedException();
}
private Result ReadTailCache(out Buffer outMemoryRange, out CacheEntry outEntry, out bool outIsCacheNeeded,
long offset, long offsetAligned, long offsetAlignedEnd, Span<byte> buffer, ref long size)
{
throw new NotImplementedException();
}
private Result BulkRead(long offset, Span<byte> buffer, ref Buffer memoryRangeHead, ref Buffer memoryRangeTail,
ref CacheEntry entryHead, ref CacheEntry entryTail, bool isHeadCacheNeeded, bool isTailCacheNeeded)
{
throw new NotImplementedException();
}
}

View file

@ -162,8 +162,8 @@ public class CompressedStorage : IStorage, IAsynchronousAccessSplitter
public long Offset { get; set; }
public uint Size { get; set; }
public long GetEndOffset() => Offset + Size;
public bool IsIncluded(long offset) => Offset <= offset && offset < GetEndOffset();
public readonly long GetEndOffset() => Offset + Size;
public readonly bool IsIncluded(long offset) => Offset <= offset && offset < GetEndOffset();
}
public struct AccessRange

View file

@ -28,6 +28,13 @@ public interface IBlockCacheManagerRange
long GetEndOffset();
}
/// <summary>
/// Handles caching buffers with the given <see cref="IBufferManager"/>.
/// </summary>
/// <typeparam name="TEntry">The type of the entries to be stores in the cache manager.</typeparam>
/// <typeparam name="TRange">The type that <typeparamref name="TEntry"/> uses
/// to represent the range cached by an entry.</typeparam>
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
public class BlockCacheManager<TEntry, TRange> : IDisposable
where TEntry : struct, IBlockCacheManagerEntry<TRange>
where TRange : struct, IBlockCacheManagerRange

View file

@ -1,4 +1,5 @@
using System.Runtime.CompilerServices;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace LibHac.Util;
@ -36,6 +37,11 @@ public static class BitUtil
return value & (value - 1);
}
public static int CountLeadingZeros(uint value)
{
return BitOperations.LeadingZeroCount(value);
}
// DivideUp comes from a C++ template that always casts to unsigned types
public static uint DivideUp(uint value, uint divisor) => (value + divisor - 1) / divisor;
public static ulong DivideUp(ulong value, ulong divisor) => (value + divisor - 1) / divisor;