diff options
| author | Stefan Boberg <[email protected]> | 2021-05-22 11:41:08 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2021-05-22 11:41:08 +0200 |
| commit | 02c19b524e54bc8f2fc36fecd43310a5ed665fcd (patch) | |
| tree | 4eea19c7fd9ec8293a3d2d771a3ad40ddec17574 /zenserver/cache/cachestore.cpp | |
| parent | clang-format (diff) | |
| download | zen-02c19b524e54bc8f2fc36fecd43310a5ed665fcd.tar.xz zen-02c19b524e54bc8f2fc36fecd43310a5ed665fcd.zip | |
Structured cache changes
- Changed cachestore to use BasicFile and TCasLog instead of local variants
- Added structured cache persistence tests
Diffstat (limited to 'zenserver/cache/cachestore.cpp')
| -rw-r--r-- | zenserver/cache/cachestore.cpp | 232 |
1 files changed, 32 insertions, 200 deletions
diff --git a/zenserver/cache/cachestore.cpp b/zenserver/cache/cachestore.cpp index 1db58c1e6..f99caa24f 100644 --- a/zenserver/cache/cachestore.cpp +++ b/zenserver/cache/cachestore.cpp @@ -5,14 +5,18 @@ #include <zencore/except.h> #include <zencore/windows.h> -#include <fmt/core.h> -#include <spdlog/spdlog.h> #include <zencore/filesystem.h> #include <zencore/fmtutils.h> #include <zencore/iobuffer.h> #include <zencore/string.h> #include <zencore/thread.h> +#include <zenstore/basicfile.h> #include <zenstore/cas.h> +#include <zenstore/caslog.h> + +#include <fmt/core.h> +#include <spdlog/spdlog.h> +#include <concepts> #include <filesystem> #include <gsl/gsl-lite.hpp> #include <unordered_map> @@ -685,178 +689,6 @@ ZenCacheMemoryLayer::CacheBucket::Put(const zen::IoHash& HashKey, const ZenCache ////////////////////////////////////////////////////////////////////////// -class ZenFile -{ -public: - void Open(std::filesystem::path FileName, bool IsCreate); - void Read(void* Data, uint64_t Size, uint64_t Offset); - void Write(const void* Data, uint64_t Size, uint64_t Offset); - void Flush(); - void* Handle() { return m_File; } - -private: - CAtlFile m_File; -}; - -void -ZenFile::Open(std::filesystem::path FileName, bool isCreate) -{ - const DWORD dwCreationDisposition = isCreate ? CREATE_ALWAYS : OPEN_EXISTING; - - HRESULT hRes = m_File.Create(FileName.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, dwCreationDisposition); - - if (FAILED(hRes)) - { - throw std::system_error(GetLastError(), std::system_category(), "Failed to open bucket sobs file"); - } -} - -void -ZenFile::Read(void* Data, uint64_t Size, uint64_t Offset) -{ - OVERLAPPED Ovl{}; - - Ovl.Offset = DWORD(Offset & 0xffff'ffffu); - Ovl.OffsetHigh = DWORD(Offset >> 32); - - HRESULT hRes = m_File.Read(Data, gsl::narrow<DWORD>(Size), &Ovl); - - if (FAILED(hRes)) - { - throw std::system_error(GetLastError(), - std::system_category(), - "Failed to read from file '{}'"_format(zen::PathFromHandle(m_File))); - } -} - -void -ZenFile::Write(const void* Data, uint64_t Size, uint64_t Offset) -{ - OVERLAPPED Ovl{}; - - Ovl.Offset = DWORD(Offset & 0xffff'ffffu); - Ovl.OffsetHigh = DWORD(Offset >> 32); - - HRESULT hRes = m_File.Write(Data, gsl::narrow<DWORD>(Size), &Ovl); - - if (FAILED(hRes)) - { - throw std::system_error(GetLastError(), std::system_category(), "Failed to write to file '{}'"_format(zen::PathFromHandle(m_File))); - } -} - -void -ZenFile::Flush() -{ - m_File.Flush(); -} - -////////////////////////////////////////////////////////////////////////// - -class ZenLogFile -{ -public: - ZenLogFile(); - ~ZenLogFile(); - - void Open(std::filesystem::path FileName, size_t RecordSize, bool isCreate); - void Append(const void* DataPointer, uint64_t DataSize); - void Replay(std::function<void(const void*)>&& Handler); - void Flush(); - -private: - CAtlFile m_File; - size_t m_RecordSize = 1; - uint64_t m_AppendOffset = 0; -}; - -ZenLogFile::ZenLogFile() -{ -} - -ZenLogFile::~ZenLogFile() -{ -} - -void -ZenLogFile::Open(std::filesystem::path FileName, size_t RecordSize, bool IsCreate) -{ - m_RecordSize = RecordSize; - - const DWORD dwCreationDisposition = IsCreate ? CREATE_ALWAYS : OPEN_EXISTING; - - HRESULT hRes = m_File.Create(FileName.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, dwCreationDisposition); - - if (FAILED(hRes)) - { - throw std::system_error(GetLastError(), std::system_category(), "Failed to open log file" /* TODO: add path */); - } - - // TODO: write/validate header and log contents and prepare for appending/replay -} - -void -ZenLogFile::Replay(std::function<void(const void*)>&& Handler) -{ - std::vector<uint8_t> ReadBuffer; - - ULONGLONG LogFileSize; - m_File.GetSize(LogFileSize); - - // Ensure we end up on a clean boundary - LogFileSize -= LogFileSize % m_RecordSize; - - ReadBuffer.resize(LogFileSize); - - HRESULT hRes = m_File.Read(ReadBuffer.data(), gsl::narrow<DWORD>(ReadBuffer.size())); - - if (FAILED(hRes)) - { - throw std::system_error(GetLastError(), std::system_category(), "Failed to read log file" /* TODO: add context */); - } - - const size_t EntryCount = LogFileSize / m_RecordSize; - - for (int i = 0; i < EntryCount; ++i) - { - Handler(ReadBuffer.data() + (i * m_RecordSize)); - } -} - -void -ZenLogFile::Append(const void* DataPointer, uint64_t DataSize) -{ - HRESULT hRes = m_File.Write(DataPointer, gsl::narrow<DWORD>(DataSize)); - - if (FAILED(hRes)) - { - throw std::system_error(GetLastError(), std::system_category(), "Failed to write to log file" /* TODO: add context */); - } -} - -void -ZenLogFile::Flush() -{ -} - -template<typename T> -class TZenLogFile : public ZenLogFile -{ -public: - void Replay(std::function<void(const T&)>&& Handler) - { - ZenLogFile::Replay([&](const void* VoidPtr) { - const T& Record = *reinterpret_cast<const T*>(VoidPtr); - - Handler(Record); - }); - } - - void Append(const T& Record) { ZenLogFile::Append(&Record, sizeof Record); } -}; - -////////////////////////////////////////////////////////////////////////// - #pragma pack(push) #pragma pack(1) @@ -887,21 +719,21 @@ struct ZenCacheDiskLayer::CacheBucket void Put(const zen::IoHash& HashKey, const ZenCacheValue& Value); void Flush(); - void PutLargeObject(const zen::IoHash& HashKey, const ZenCacheValue& Value); - inline bool IsOk() const { return m_Ok; } +private: CasStore& m_CasStore; std::filesystem::path m_BucketDir; Oid m_BucketId; bool m_Ok = false; uint64_t m_LargeObjectThreshold = 1024; - ZenFile m_SobsFile; - TZenLogFile<DiskIndexEntry> m_SlogFile; - ZenFile m_SidxFile; + BasicFile m_SobsFile; + TCasLogFile<DiskIndexEntry> m_SlogFile; + BasicFile m_SidxFile; void BuildPath(zen::WideStringBuilderBase& Path, const zen::IoHash& HashKey); + void PutLargeObject(const zen::IoHash& HashKey, const ZenCacheValue& Value); RwLock m_IndexLock; std::unordered_map<zen::IoHash, DiskLocation, zen::IoHash::Hasher> m_Index; @@ -923,10 +755,10 @@ ZenCacheDiskLayer::CacheBucket::OpenOrCreate(std::filesystem::path BucketDir) m_BucketDir = BucketDir; - std::wstring ManifestPath{(m_BucketDir / "zen_manifest").c_str()}; - std::wstring SobsPath{(m_BucketDir / "zen.sobs").c_str()}; - std::wstring SlogPath{(m_BucketDir / "zen.slog").c_str()}; - std::wstring SidxPath{(m_BucketDir / "zen.sidx").c_str()}; + std::filesystem::path ManifestPath{m_BucketDir / "zen_manifest"}; + std::filesystem::path SobsPath{m_BucketDir / "zen.sobs"}; + std::filesystem::path SlogPath{m_BucketDir / "zen.slog"}; + std::filesystem::path SidxPath{m_BucketDir / "zen.sidx"}; CAtlFile ManifestFile; @@ -963,7 +795,7 @@ ZenCacheDiskLayer::CacheBucket::OpenOrCreate(std::filesystem::path BucketDir) if (FAILED(hRes)) { - throw std::system_error(GetLastError(), std::system_category(), "Failed to create bucket manifest"); + ThrowLastError("Failed to create bucket manifest '{}'"_format(ManifestPath)); } m_BucketId.Generate(); @@ -980,9 +812,9 @@ ZenCacheDiskLayer::CacheBucket::OpenOrCreate(std::filesystem::path BucketDir) // Open and replay log - m_SlogFile.Open(SlogPath, sizeof(DiskIndexEntry), IsNew); + m_SlogFile.Open(SlogPath, IsNew); - uint64_t maxFileOffset = 0; + uint64_t MaxFileOffset = 0; { // This is not technically necessary but may help future static analysis @@ -991,11 +823,11 @@ ZenCacheDiskLayer::CacheBucket::OpenOrCreate(std::filesystem::path BucketDir) m_SlogFile.Replay([&](const DiskIndexEntry& Record) { m_Index[Record.Key] = Record.Location; - maxFileOffset = std::max<uint64_t>(maxFileOffset, Record.Location.Offset + Record.Location.Size); + MaxFileOffset = std::max<uint64_t>(MaxFileOffset, Record.Location.Offset + Record.Location.Size); }); } - m_WriteCursor = (maxFileOffset + 15) & ~15; + m_WriteCursor = (MaxFileOffset + 15) & ~15; m_Ok = true; } @@ -1028,17 +860,17 @@ ZenCacheDiskLayer::CacheBucket::Get(const zen::IoHash& HashKey, ZenCacheValue& O } } - WideStringBuilder<128> dataFilePath; - BuildPath(dataFilePath, HashKey); + WideStringBuilder<128> DataFilePath; + BuildPath(DataFilePath, HashKey); - zen::IoBuffer data = IoBufferBuilder::MakeFromFile(dataFilePath.c_str()); + zen::IoBuffer Data = IoBufferBuilder::MakeFromFile(DataFilePath.c_str()); - if (!data) + if (!Data) { return false; } - OutValue.Value = data; + OutValue.Value = Data; // TODO: should populate index? @@ -1064,26 +896,26 @@ ZenCacheDiskLayer::CacheBucket::Put(const zen::IoHash& HashKey, const ZenCacheVa auto it = m_Index.find(HashKey); - DiskLocation loc{.Offset = m_WriteCursor, .Size = gsl::narrow<uint32_t>(Value.Value.Size())}; + DiskLocation Loc{.Offset = m_WriteCursor, .Size = gsl::narrow<uint32_t>(Value.Value.Size())}; - m_WriteCursor = (m_WriteCursor + loc.Size + 15) & ~15; + m_WriteCursor = (m_WriteCursor + Loc.Size + 15) & ~15; if (it == m_Index.end()) { - m_Index.insert({HashKey, loc}); + m_Index.insert({HashKey, Loc}); } else { // TODO: should check if write is idempotent and bail out if it is? - it->second = loc; + it->second = Loc; } - DiskIndexEntry indexEntry{.Key = HashKey, .Location = loc}; + DiskIndexEntry IndexEntry{.Key = HashKey, .Location = Loc}; - m_SlogFile.Append(indexEntry); + m_SlogFile.Append(IndexEntry); - m_SobsFile.Write(Value.Value.Data(), loc.Size, loc.Offset); + m_SobsFile.Write(Value.Value.Data(), Loc.Size, Loc.Offset); return; } |