AuroraRuntime/Source/IO/FS/FSMemoryMappedFile.cpp
Jamie Reece Wilson 66f3250983 [*] Improved IMemoryMappedFile API
[+] AuIO::Adapters::NewAsyncTransactionFromStreamSeekingPair
2024-03-09 00:20:26 +00:00

410 lines
13 KiB
C++

/***
Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
File: FSMemoryMappedFile.cpp
Date: 2024-03-05
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "FSMemoryMappedFile.hpp"
#include <Source/IO/Adapters/AuIOAdapterAsyncDelegators.hpp>
namespace Aurora::IO::FS
{
IIOHandle * MemoryMappedFile::ToHandle()
{
return this->pHandleShared ?
this->pHandleShared.get() :
this->handle.AsPointer();
}
AuUInt MemoryMappedFile::GetBaseAddress()
{
if (this->pView)
{
return (AuUInt)this->pView->GetBasePointer();
}
else
{
return 0;
}
}
AuUInt MemoryMappedFile::GetEndAddress()
{
if (this->pView)
{
return (AuUInt)this->pView->GetBasePointer() +
this->GetLength();
}
else
{
return 0;
}
}
AuUInt MemoryMappedFile::GetLength()
{
return this->uFileMapLength;
}
AuSPtr<IStreamReader> MemoryMappedFile::NewStreamReader()
{
return AuMakeShared<IO::Buffered::ViewReader>(this->ToReadView(), this->pView);
}
AuSPtr<IStreamWriter> MemoryMappedFile::NewStreamWriter()
{
return AuMakeShared<IO::Buffered::ViewWriter>(this->ToWriteView(), this->pView);
}
void MemoryMappedFile::InitTransactions()
{
if (AuThreading::InitOnceLocker::TryLock(&this->initOnce))
{
bool bOk { true };
if (this->eMode == EFileOpenMode::eReadWrite ||
this->eMode == EFileOpenMode::eRead)
{
auto pReader = AuMakeShared<IO::Buffered::ViewSeekableReader>(this->ToReadViewAlt(), this->pView);
if (pReader)
{
auto iBaseOffset = 0 -
AuInt64(this->uFileMapOffset) +
this->iAdjustStreamOffset;
pReader->GetBaseOffset() = iBaseOffset;
}
else
{
bOk = false;
}
this->pStreamReader = pReader;
}
if (this->eMode == EFileOpenMode::eReadWrite ||
this->eMode == EFileOpenMode::eWrite)
{
auto pWriter = AuMakeShared<IO::Buffered::ViewSeekableWriter>(this->ToWriteViewAlt(), this->pView);
if (pWriter)
{
auto iBaseOffset = 0 -
AuInt64(this->uFileMapOffset) +
this->iAdjustStreamOffset;
pWriter->GetBaseOffset() = iBaseOffset;
}
else
{
bOk = false;
}
this->pStreamWriter = pWriter;
}
AuThreading::InitOnceLocker::Finish(&this->initOnce, !bOk);
}
else
{
this->initOnce.Wait();
}
}
AuSPtr<IAsyncTransaction> MemoryMappedFile::NewAsyncReadTransaction()
{
this->InitTransactions();
SysCheckNotNullMemory(this->pStreamReader, {});
auto pTransaction = Adapters::NewAsyncTransactionFromStreamSeekingReader(this->pStreamReader, {});
SysCheckNotNullMemory(pTransaction, {});
return pTransaction;
}
AuSPtr<IAsyncTransaction> MemoryMappedFile::NewAsyncWriteTransaction()
{
this->InitTransactions();
SysCheckNotNullMemory(this->pStreamWriter, {});
auto pTransaction = Adapters::NewAsyncTransactionFromStreamSeekingWriter(this->pStreamWriter, {});
SysCheckNotNullMemory(pTransaction, {});
return pTransaction;
}
AuSPtr<IAsyncTransaction> MemoryMappedFile::NewAsyncAnyTransaction()
{
this->InitTransactions();
SysCheckNotNullMemory(this->pStreamWriter, {});
SysCheckNotNullMemory(this->pStreamReader, {});
auto pTransaction = Adapters::NewAsyncTransactionFromStreamSeekingPair(this->pStreamReader, this->pStreamWriter, {});
SysCheckNotNullMemory(pTransaction, {});
return pTransaction;
}
ISeekingReader *MemoryMappedFile::ToStreamSeekingReader()
{
if (this->optSeekableReader)
{
return &this->optSeekableReader.Value();
}
else
{
return nullptr;
}
}
ISeekingWriter *MemoryMappedFile::ToStreamSeekingWriter()
{
if (this->optSeekableWriter)
{
return &this->optSeekableWriter.Value();
}
else
{
return nullptr;
}
}
AuMemoryViewRead MemoryMappedFile::ToReadView()
{
auto pBasePointer = this->pView->GetBasePointer();
auto iBaseOffset = 0 -
AuInt64(this->uFileMapOffset) +
this->iAdjustStreamOffset;
if (iBaseOffset < 0)
{
return {};
}
auto pHeadPointer = pBasePointer + iBaseOffset;
return { pHeadPointer, this->GetEndAddress() - AuUInt(pHeadPointer) };
}
AuMemoryViewWrite MemoryMappedFile::ToWriteView()
{
auto pBasePointer = this->pView->GetBasePointer();
auto iBaseOffset = 0 -
AuInt64(this->uFileMapOffset) +
this->iAdjustStreamOffset;
if (iBaseOffset < 0)
{
return {};
}
auto pHeadPointer = pBasePointer + iBaseOffset;
return { pHeadPointer, this->GetEndAddress() - AuUInt(pHeadPointer) };
}
AuMemoryViewRead MemoryMappedFile::ToReadViewAlt()
{
auto pBasePointer = this->pView->GetBasePointer();
return { pBasePointer, this->GetEndAddress() - AuUInt(pBasePointer) };
}
AuMemoryViewWrite MemoryMappedFile::ToWriteViewAlt()
{
auto pBasePointer = this->pView->GetBasePointer();
return { pBasePointer, this->GetEndAddress() - AuUInt(pBasePointer) };
}
void MemoryMappedFile::Flush(AuUInt uOffset,
AuUInt uLength)
{
auto iOffset = 0 - AuSInt(this->uFileMapOffset) + AuSInt(iAdjustStreamOffset) + AuSInt(uOffset);
if (iOffset < 0)
{
return;
}
auto uStartAddress = iOffset;
auto uEndAddress = AuMin(this->GetLength(), uStartAddress + uLength);
auto uSecondLength = uEndAddress - uStartAddress;
this->pView->Flush(iOffset, uSecondLength);
}
void MemoryMappedFile::Prefetch(AuUInt uOffset,
AuUInt uLength)
{
AU_DEBUG_MEMCRUNCH;
auto iOffset = 0 - AuSInt(this->uFileMapOffset) + AuSInt(iAdjustStreamOffset) + AuSInt(uOffset);
if (iOffset < 0)
{
return;
}
auto uStartAddress = this->GetBaseAddress() + iOffset;
auto uEndAddress = AuMin(this->GetEndAddress(), uStartAddress + uLength);
auto uSecondLength = uEndAddress - uStartAddress;
AuMemory::Cache::OptimizeAddressRangeOnCore({
{
uStartAddress,
uSecondLength
}
});
}
IAsyncFileStream *MemoryMappedFile::ToAsyncFile()
{
return this;
}
AuSPtr<IAsyncTransaction> MemoryMappedFile::NewTransaction()
{
return this->NewAsyncAnyTransaction();
}
bool MemoryMappedFile::BlockingTruncate(AuUInt64 length)
{
return false;
}
bool MemoryMappedFile::BlockingRead(AuUInt64 offset, const Memory::MemoryViewStreamWrite &parameters)
{
this->InitTransactions();
SysCheckNotNullMemory(this->pStreamReader, {});
return this->pStreamReader->ArbitraryRead(offset, parameters) == EStreamError::eErrorNone;
}
bool MemoryMappedFile::BlockingWrite(AuUInt64 offset, const Memory::MemoryViewStreamRead &parameters)
{
this->InitTransactions();
SysCheckNotNullMemory(this->pStreamWriter, {});
return this->pStreamWriter->ArbitraryWrite(offset, parameters) == EStreamError::eErrorNone;
}
bool MemoryMappedFile::Init(EFileOpenMode eMode,
AuUInt64 uFileMapOffset,
AuUInt64 uFileMapLength,
AuInt64 iAdjustStreamOffset,
EFileAdvisoryLockLevel eLockLevel)
{
auto pHandle = this->ToHandle();
if (!uFileMapLength)
{
uFileMapLength = pHandle->GetFileLength();
}
this->eMode = eMode;
this->uFileMapLength = uFileMapLength;
this->uFileMapOffset = uFileMapOffset;
this->iAdjustStreamOffset = iAdjustStreamOffset;
auto pAddressSpace = AuProcess::GetGlobalProcessSpace();
this->pView = pAddressSpace->MapFileByObject(AuUnsafeRaiiToShared(this->ToHandle()),
uFileMapOffset,
uFileMapLength,
eMode,
eLockLevel);
if (!this->pView)
{
SysPushErrorNested();
return false;
}
{
auto iBaseOffset = 0 -
AuInt64(this->uFileMapOffset) +
this->iAdjustStreamOffset;
IO::Buffered::ViewSeekableReader reader(this->ToReadViewAlt(), this->pView);
IO::Buffered::ViewSeekableWriter writer(this->ToWriteViewAlt(), this->pView);
writer.GetBaseOffset() = iBaseOffset;
reader.GetBaseOffset() = iBaseOffset;
this->optSeekableReader = AuMove(reader);
this->optSeekableWriter = AuMove(writer);
}
return true;
}
IMemoryMappedFile *OpenMapNew(const AuString &path,
AuOptional<EFileOpenMode> opteMode,
AuOptional<AuUInt64> optuFileMapOffset,
AuOptional<AuUInt64> optuFileMapLength,
AuOptional<AuInt64> optiAdjustStreamOffset,
AuOptional<EFileAdvisoryLockLevel> opteAdvisoryLevel,
AuOptional<bool> optbLockEntireFile)
{
auto eMode = opteMode.ValueOr(EFileOpenMode::eRead);
auto uFileMapOffset = optuFileMapOffset.ValueOr(0);
auto uFileLength = optuFileMapLength.ValueOr(0);
auto iAdjustStreamOffset = optiAdjustStreamOffset.ValueOr(uFileMapOffset);
auto bLockEntireFile = optbLockEntireFile.ValueOr(true);
auto eAdvisoryLevel = opteAdvisoryLevel.ValueOr(EFileAdvisoryLockLevel::eBlockReadWrite);
auto pReturn = _new MemoryMappedFile();
SysCheckNotNullMemory(pReturn, {});
auto createRequest = AuIO::IIOHandle::HandleCreate::Create(path);
createRequest.eMode = eMode;
createRequest.eAdvisoryLevel = bLockEntireFile ? eAdvisoryLevel : EFileAdvisoryLockLevel::eNoSafety;
createRequest.bDirectIOMode = false;
if (!pReturn->handle->InitFromPath(createRequest))
{
delete pReturn;
return nullptr;
}
if (!pReturn->Init(eMode, uFileMapOffset, uFileLength, iAdjustStreamOffset, !bLockEntireFile ? eAdvisoryLevel : EFileAdvisoryLockLevel::eNoSafety))
{
delete pReturn;
return nullptr;
}
return pReturn;
}
void OpenMapRelease(IMemoryMappedFile *pReturn)
{
AuSafeDelete<MemoryMappedFile *>(pReturn);
}
IMemoryMappedFile *OpenMapFromSharedHandleNew(const AuSPtr<IIOHandle> &pIOHandle,
AuOptional<AuUInt64> optuFileMapOffset,
AuOptional<AuUInt64> optuFileMapLength,
AuOptional<AuInt64> optiAdjustStreamOffset,
AuOptional<EFileAdvisoryLockLevel> opteAdvisoryLevel)
{
auto uFileMapOffset = optuFileMapOffset.ValueOr(0);
auto uFileLength = optuFileMapLength.ValueOr(0);
auto iAdjustStreamOffset = optiAdjustStreamOffset.ValueOr(uFileMapOffset);
auto eAdvisoryLevel = opteAdvisoryLevel.ValueOr(EFileAdvisoryLockLevel::eNoSafety);
SysCheckArgNotNull(pIOHandle, {});
auto pReturn = _new MemoryMappedFile();
SysCheckNotNullMemory(pReturn, {});
pReturn->pHandleShared = pIOHandle;
if (!pReturn->Init(pIOHandle->GetOSWriteHandleSafe() ? EFileOpenMode::eReadWrite : EFileOpenMode::eRead,
uFileMapOffset,
uFileLength,
iAdjustStreamOffset,
eAdvisoryLevel))
{
delete pReturn;
return nullptr;
}
return pReturn;
}
void OpenMapFromSharedHandleRelease(IMemoryMappedFile *pReturn)
{
AuSafeDelete<MemoryMappedFile *>(pReturn);
}
}