diff options
| author | Stefan Boberg <[email protected]> | 2021-09-26 21:06:06 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2021-09-26 21:06:06 +0200 |
| commit | 4f1b3600b85461e7817d23f46eedcae40b99c160 (patch) | |
| tree | 374266267c486243b23ac3d76ad0b972e172940c /zenstore/basicfile.cpp | |
| parent | Use /MP on all projects (diff) | |
| download | zen-4f1b3600b85461e7817d23f46eedcae40b99c160.tar.xz zen-4f1b3600b85461e7817d23f46eedcae40b99c160.zip | |
Various BasicFile improvements
* BasicFile::Open clears error_code on entry, and exits early on failure to avoid initialization of m_FileHandle
* Made BasicFile::Read handle large reads
* Made BasicFile::Write handle large writes
* Added BasicFile::WriteAll which may be optimized in the future to handle what is essentially a file copy more efficiently
Diffstat (limited to 'zenstore/basicfile.cpp')
| -rw-r--r-- | zenstore/basicfile.cpp | 110 |
1 files changed, 88 insertions, 22 deletions
diff --git a/zenstore/basicfile.cpp b/zenstore/basicfile.cpp index 233efa11c..f41f04101 100644 --- a/zenstore/basicfile.cpp +++ b/zenstore/basicfile.cpp @@ -35,6 +35,8 @@ BasicFile::Open(std::filesystem::path FileName, bool IsCreate) void BasicFile::Open(std::filesystem::path FileName, bool IsCreate, std::error_code& Ec) { + Ec.clear(); + const DWORD dwCreationDisposition = IsCreate ? CREATE_ALWAYS : OPEN_EXISTING; DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; const DWORD dwShareMode = FILE_SHARE_READ; @@ -57,6 +59,8 @@ BasicFile::Open(std::filesystem::path FileName, bool IsCreate, std::error_code& if (FileHandle == INVALID_HANDLE_VALUE) { Ec = zen::MakeErrorCodeFromLastError(); + + return; } m_FileHandle = FileHandle; @@ -73,21 +77,32 @@ BasicFile::Close() } void -BasicFile::Read(void* Data, uint64_t Size, uint64_t Offset) +BasicFile::Read(void* Data, uint64_t BytesToRead, uint64_t FileOffset) { - OVERLAPPED Ovl{}; + const uint64_t MaxChunkSize = 2u * 1024 * 1024 * 1024; - Ovl.Offset = DWORD(Offset & 0xffff'ffffu); - Ovl.OffsetHigh = DWORD(Offset >> 32); + while (BytesToRead) + { + const uint64_t NumberOfBytesToRead = Min(BytesToRead, MaxChunkSize); - DWORD dwNumberOfBytesToRead = gsl::narrow<DWORD>(Size); - DWORD dwNumberOfBytesRead = 0; + OVERLAPPED Ovl{}; - BOOL Success = ::ReadFile(m_FileHandle, Data, dwNumberOfBytesToRead, &dwNumberOfBytesRead, &Ovl); + Ovl.Offset = DWORD(FileOffset & 0xffff'ffffu); + Ovl.OffsetHigh = DWORD(FileOffset >> 32); - if (!Success) - { - ThrowLastError("Failed to read from file '{}'"_format(zen::PathFromHandle(m_FileHandle))); + DWORD dwNumberOfBytesRead = 0; + BOOL Success = ::ReadFile(m_FileHandle, Data, DWORD(NumberOfBytesToRead), &dwNumberOfBytesRead, &Ovl); + + ZEN_ASSERT(dwNumberOfBytesRead == NumberOfBytesToRead); + + if (!Success) + { + ThrowLastError("Failed to read from file '{}'"_format(zen::PathFromHandle(m_FileHandle))); + } + + BytesToRead -= NumberOfBytesToRead; + FileOffset += NumberOfBytesToRead; + Data = reinterpret_cast<uint8_t*>(Data) + NumberOfBytesToRead; } } @@ -95,9 +110,7 @@ IoBuffer BasicFile::ReadAll() { IoBuffer Buffer(FileSize()); - - Read((void*)Buffer.Data(), Buffer.Size(), 0); - + Read(Buffer.MutableData(), Buffer.Size(), 0); return Buffer; } @@ -131,25 +144,57 @@ BasicFile::StreamByteRange(uint64_t FileOffset, uint64_t Size, std::function<voi } void -BasicFile::Write(const void* Data, uint64_t Size, uint64_t Offset) +BasicFile::Write(const void* Data, uint64_t Size, uint64_t FileOffset, std::error_code& Ec) { - OVERLAPPED Ovl{}; + Ec.clear(); + + const uint64_t MaxChunkSize = 2u * 1024 * 1024 * 1024; + + while (Size) + { + const uint64_t NumberOfBytesToWrite = Min(Size, MaxChunkSize); + + OVERLAPPED Ovl{}; + + Ovl.Offset = DWORD(FileOffset & 0xffff'ffffu); + Ovl.OffsetHigh = DWORD(FileOffset >> 32); + + DWORD dwNumberOfBytesWritten = 0; + + BOOL Success = ::WriteFile(m_FileHandle, Data, DWORD(NumberOfBytesToWrite), &dwNumberOfBytesWritten, &Ovl); - Ovl.Offset = DWORD(Offset & 0xffff'ffffu); - Ovl.OffsetHigh = DWORD(Offset >> 32); + if (!Success) + { + Ec = MakeErrorCodeFromLastError(); - DWORD dwNumberOfBytesToWrite = gsl::narrow<DWORD>(Size); - DWORD dwNumberOfBytesWritten = 0; + return; + } - BOOL Success = ::WriteFile(m_FileHandle, Data, dwNumberOfBytesToWrite, &dwNumberOfBytesWritten, &Ovl); + Size -= NumberOfBytesToWrite; + FileOffset += NumberOfBytesToWrite; + Data = reinterpret_cast<const uint8_t*>(Data) + NumberOfBytesToWrite; + } +} - if (!Success) +void +BasicFile::Write(const void* Data, uint64_t Size, uint64_t Offset) +{ + std::error_code Ec; + Write(Data, Size, Offset, Ec); + + if (Ec) { - ThrowLastError("Failed to write to file '{}'"_format(zen::PathFromHandle(m_FileHandle))); + throw std::system_error(Ec, "Failed to write to file '{}'"_format(zen::PathFromHandle(m_FileHandle))); } } void +BasicFile::WriteAll(IoBuffer Data, std::error_code& Ec) +{ + Write(Data.Data(), Data.Size(), 0, Ec); +} + +void BasicFile::Flush() { FlushFileBuffers(m_FileHandle); @@ -209,6 +254,15 @@ TemporaryFile::MoveTemporaryIntoPlace(std::filesystem::path FinalFileName, std:: std::filesystem::rename(m_TempPath, FinalFileName, Ec); } +/* + ___________ __ + \__ ___/___ _______/ |_ ______ + | |_/ __ \ / ___/\ __\/ ___/ + | |\ ___/ \___ \ | | \___ \ + |____| \___ >____ > |__| /____ > + \/ \/ \/ +*/ + #if ZEN_WITH_TESTS TEST_CASE("BasicFile") @@ -220,6 +274,18 @@ TEST_CASE("BasicFile") CHECK_NOTHROW(File1.Open("zonk", true)); CHECK_NOTHROW(File1.Write("abcd", 4, 0)); CHECK(File1.FileSize() == 4); + { + IoBuffer Data = File1.ReadAll(); + CHECK(Data.Size() == 4); + CHECK_EQ(memcmp(Data.Data(), "abcd", 4), 0); + } + CHECK_NOTHROW(File1.Write("efgh", 4, 2)); + CHECK(File1.FileSize() == 6); + { + IoBuffer Data = File1.ReadAll(); + CHECK(Data.Size() == 6); + CHECK_EQ(memcmp(Data.Data(), "abefgh", 6), 0); + } } TEST_CASE("TemporaryFile") |