aboutsummaryrefslogtreecommitdiff
path: root/zenserver/cache
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2021-05-22 11:41:08 +0200
committerStefan Boberg <[email protected]>2021-05-22 11:41:08 +0200
commit02c19b524e54bc8f2fc36fecd43310a5ed665fcd (patch)
tree4eea19c7fd9ec8293a3d2d771a3ad40ddec17574 /zenserver/cache
parentclang-format (diff)
downloadzen-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')
-rw-r--r--zenserver/cache/cachestore.cpp232
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;
}