aboutsummaryrefslogtreecommitdiff
path: root/zenstore/blockstore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zenstore/blockstore.cpp')
-rw-r--r--zenstore/blockstore.cpp242
1 files changed, 242 insertions, 0 deletions
diff --git a/zenstore/blockstore.cpp b/zenstore/blockstore.cpp
new file mode 100644
index 000000000..1eb859d5a
--- /dev/null
+++ b/zenstore/blockstore.cpp
@@ -0,0 +1,242 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "compactcas.h"
+
+#include <zenstore/blockstore.h>
+
+#if ZEN_WITH_TESTS
+# include <zencore/compactbinarybuilder.h>
+# include <zencore/testing.h>
+# include <zencore/testutils.h>
+# include <algorithm>
+# include <random>
+#endif
+
+//////////////////////////////////////////////////////////////////////////
+
+namespace zen {
+
+//////////////////////////////////////////////////////////////////////////
+
+BlockStoreFile::BlockStoreFile(const std::filesystem::path& BlockPath) : m_Path(BlockPath)
+{
+}
+
+BlockStoreFile::~BlockStoreFile()
+{
+ m_IoBuffer = IoBuffer();
+ m_File.Detach();
+}
+
+const std::filesystem::path&
+BlockStoreFile::GetPath() const
+{
+ return m_Path;
+}
+
+void
+BlockStoreFile::Open()
+{
+ m_File.Open(m_Path, BasicFile::Mode::kDelete);
+ void* FileHandle = m_File.Handle();
+ m_IoBuffer = IoBuffer(IoBuffer::File, FileHandle, 0, m_File.FileSize());
+}
+
+void
+BlockStoreFile::Create(uint64_t InitialSize)
+{
+ auto ParentPath = m_Path.parent_path();
+ if (!std::filesystem::is_directory(ParentPath))
+ {
+ CreateDirectories(ParentPath);
+ }
+
+ m_File.Open(m_Path, BasicFile::Mode::kTruncateDelete);
+ if (InitialSize > 0)
+ {
+ m_File.SetFileSize(InitialSize);
+ }
+ void* FileHandle = m_File.Handle();
+ m_IoBuffer = IoBuffer(IoBuffer::File, FileHandle, 0, InitialSize);
+}
+
+uint64_t
+BlockStoreFile::FileSize()
+{
+ return m_File.FileSize();
+}
+
+void
+BlockStoreFile::MarkAsDeleteOnClose(std::error_code& Ec)
+{
+ m_File.MarkAsDeleteOnClose(Ec);
+}
+
+IoBuffer
+BlockStoreFile::GetChunk(uint64_t Offset, uint64_t Size)
+{
+ return IoBuffer(m_IoBuffer, Offset, Size);
+}
+
+void
+BlockStoreFile::Read(void* Data, uint64_t Size, uint64_t FileOffset)
+{
+ m_File.Read(Data, Size, FileOffset);
+}
+
+void
+BlockStoreFile::Write(const void* Data, uint64_t Size, uint64_t FileOffset)
+{
+ m_File.Write(Data, Size, FileOffset);
+}
+
+void
+BlockStoreFile::Truncate(uint64_t Size)
+{
+ m_File.SetFileSize(Size);
+}
+
+void
+BlockStoreFile::Flush()
+{
+ m_File.Flush();
+}
+
+void
+BlockStoreFile::StreamByteRange(uint64_t FileOffset, uint64_t Size, std::function<void(const void* Data, uint64_t Size)>&& ChunkFun)
+{
+ m_File.StreamByteRange(FileOffset, Size, std::move(ChunkFun));
+}
+
+#if ZEN_WITH_TESTS
+
+static bool
+operator==(const BlockStoreLocation& Lhs, const BlockStoreLocation& Rhs)
+{
+ return Lhs.BlockIndex == Rhs.BlockIndex && Lhs.Offset == Rhs.Offset && Lhs.Size == Rhs.Size;
+}
+
+TEST_CASE("blockstore.blockstoredisklocation")
+{
+ BlockStoreLocation Zero = BlockStoreLocation{.BlockIndex = 0, .Offset = 0, .Size = 0};
+ CHECK(Zero == BlockStoreDiskLocation(Zero, 4).Get(4));
+
+ BlockStoreLocation MaxBlockIndex = BlockStoreLocation{.BlockIndex = BlockStoreDiskLocation::MaxBlockIndex, .Offset = 0, .Size = 0};
+ CHECK(MaxBlockIndex == BlockStoreDiskLocation(MaxBlockIndex, 4).Get(4));
+
+ BlockStoreLocation MaxOffset = BlockStoreLocation{.BlockIndex = 0, .Offset = BlockStoreDiskLocation::MaxOffset * 4, .Size = 0};
+ CHECK(MaxOffset == BlockStoreDiskLocation(MaxOffset, 4).Get(4));
+
+ BlockStoreLocation MaxSize = BlockStoreLocation{.BlockIndex = 0, .Offset = 0, .Size = std::numeric_limits<uint32_t>::max()};
+ CHECK(MaxSize == BlockStoreDiskLocation(MaxSize, 4).Get(4));
+
+ BlockStoreLocation MaxBlockIndexAndOffset =
+ BlockStoreLocation{.BlockIndex = BlockStoreDiskLocation::MaxBlockIndex, .Offset = BlockStoreDiskLocation::MaxOffset * 4, .Size = 0};
+ CHECK(MaxBlockIndexAndOffset == BlockStoreDiskLocation(MaxBlockIndexAndOffset, 4).Get(4));
+
+ BlockStoreLocation MaxAll = BlockStoreLocation{.BlockIndex = BlockStoreDiskLocation::MaxBlockIndex,
+ .Offset = BlockStoreDiskLocation::MaxOffset * 4,
+ .Size = std::numeric_limits<uint32_t>::max()};
+ CHECK(MaxAll == BlockStoreDiskLocation(MaxAll, 4).Get(4));
+
+ BlockStoreLocation MaxAll4096 = BlockStoreLocation{.BlockIndex = BlockStoreDiskLocation::MaxBlockIndex,
+ .Offset = BlockStoreDiskLocation::MaxOffset * 4096,
+ .Size = std::numeric_limits<uint32_t>::max()};
+ CHECK(MaxAll4096 == BlockStoreDiskLocation(MaxAll4096, 4096).Get(4096));
+
+ BlockStoreLocation Middle = BlockStoreLocation{.BlockIndex = (BlockStoreDiskLocation::MaxBlockIndex) / 2,
+ .Offset = ((BlockStoreDiskLocation::MaxOffset) / 2) * 4,
+ .Size = std::numeric_limits<uint32_t>::max() / 2};
+ CHECK(Middle == BlockStoreDiskLocation(Middle, 4).Get(4));
+}
+
+TEST_CASE("blockstore.blockfile")
+{
+ ScopedTemporaryDirectory TempDir;
+ auto RootDirectory = TempDir.Path() / "blocks";
+ CreateDirectories(RootDirectory);
+
+ {
+ BlockStoreFile File1(RootDirectory / "1");
+ File1.Create(16384);
+ CHECK(File1.FileSize() == 16384);
+ File1.Write("data", 5, 0);
+ IoBuffer DataChunk = File1.GetChunk(0, 5);
+ File1.Write("boop", 5, 5);
+ IoBuffer BoopChunk = File1.GetChunk(5, 5);
+ const char* Data = static_cast<const char*>(DataChunk.GetData());
+ CHECK(std::string(Data) == "data");
+ const char* Boop = static_cast<const char*>(BoopChunk.GetData());
+ CHECK(std::string(Boop) == "boop");
+ File1.Flush();
+ }
+ {
+ BlockStoreFile File1(RootDirectory / "1");
+ File1.Open();
+
+ char DataRaw[5];
+ File1.Read(DataRaw, 5, 0);
+ CHECK(std::string(DataRaw) == "data");
+ IoBuffer DataChunk = File1.GetChunk(0, 5);
+
+ char BoopRaw[5];
+ File1.Read(BoopRaw, 5, 5);
+ CHECK(std::string(BoopRaw) == "boop");
+
+ IoBuffer BoopChunk = File1.GetChunk(5, 5);
+ const char* Data = static_cast<const char*>(DataChunk.GetData());
+ CHECK(std::string(Data) == "data");
+ const char* Boop = static_cast<const char*>(BoopChunk.GetData());
+ CHECK(std::string(Boop) == "boop");
+ }
+
+ {
+ IoBuffer DataChunk;
+ IoBuffer BoopChunk;
+
+ {
+ BlockStoreFile File1(RootDirectory / "1");
+ File1.Open();
+ DataChunk = File1.GetChunk(0, 5);
+ BoopChunk = File1.GetChunk(5, 5);
+ }
+
+ CHECK(std::filesystem::exists(RootDirectory / "1"));
+
+ const char* Data = static_cast<const char*>(DataChunk.GetData());
+ CHECK(std::string(Data) == "data");
+ const char* Boop = static_cast<const char*>(BoopChunk.GetData());
+ CHECK(std::string(Boop) == "boop");
+ }
+ CHECK(std::filesystem::exists(RootDirectory / "1"));
+
+ {
+ IoBuffer DataChunk;
+ IoBuffer BoopChunk;
+
+ {
+ BlockStoreFile File1(RootDirectory / "1");
+ File1.Open();
+ std::error_code Ec;
+ File1.MarkAsDeleteOnClose(Ec);
+ CHECK(!Ec);
+ DataChunk = File1.GetChunk(0, 5);
+ BoopChunk = File1.GetChunk(5, 5);
+ }
+
+ const char* Data = static_cast<const char*>(DataChunk.GetData());
+ CHECK(std::string(Data) == "data");
+ const char* Boop = static_cast<const char*>(BoopChunk.GetData());
+ CHECK(std::string(Boop) == "boop");
+ }
+ CHECK(!std::filesystem::exists(RootDirectory / "1"));
+}
+
+#endif
+
+void
+blockstore_forcelink()
+{
+}
+
+} // namespace zen