aboutsummaryrefslogtreecommitdiff
path: root/zenstore/basicfile.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2021-09-26 21:06:06 +0200
committerStefan Boberg <[email protected]>2021-09-26 21:06:06 +0200
commit4f1b3600b85461e7817d23f46eedcae40b99c160 (patch)
tree374266267c486243b23ac3d76ad0b972e172940c /zenstore/basicfile.cpp
parentUse /MP on all projects (diff)
downloadzen-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.cpp110
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")