410 lines
13 KiB
C++
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 ¶meters)
|
|
{
|
|
this->InitTransactions();
|
|
SysCheckNotNullMemory(this->pStreamReader, {});
|
|
return this->pStreamReader->ArbitraryRead(offset, parameters) == EStreamError::eErrorNone;
|
|
}
|
|
|
|
bool MemoryMappedFile::BlockingWrite(AuUInt64 offset, const Memory::MemoryViewStreamRead ¶meters)
|
|
{
|
|
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);
|
|
}
|
|
} |