diff options
Diffstat (limited to 'zenstore/blockstore.cpp')
| -rw-r--r-- | zenstore/blockstore.cpp | 242 |
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 |