From eff472457f4090a4476ced920cea2ea4cbeca7bf Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Fri, 29 Oct 2021 18:17:36 +0200 Subject: z$: hooked up bucket traversal for gc added some tests added "test" mode for zenserver, to run any tests embedded in the zenserver (example: `zenserver test -tx=z$.*`) --- zenserver/cache/structuredcachestore.cpp | 128 ++++++++++++++++++++++++++++--- 1 file changed, 117 insertions(+), 11 deletions(-) (limited to 'zenserver/cache/structuredcachestore.cpp') diff --git a/zenserver/cache/structuredcachestore.cpp b/zenserver/cache/structuredcachestore.cpp index e7b840ed8..02ec43115 100644 --- a/zenserver/cache/structuredcachestore.cpp +++ b/zenserver/cache/structuredcachestore.cpp @@ -6,19 +6,27 @@ #include #include +#include +#include +#include +#include #include #include #include #include #include +#include +#include #include #include #include #include +#include #include #include #include +#include ZEN_THIRD_PARTY_INCLUDES_START #include @@ -31,7 +39,7 @@ namespace zen { using namespace fmt::literals; -ZenCacheStore::ZenCacheStore(CasStore& Cas, const std::filesystem::path& RootDir) : m_DiskLayer{Cas, RootDir} +ZenCacheStore::ZenCacheStore(const std::filesystem::path& RootDir) : m_DiskLayer{RootDir} { ZEN_INFO("initializing structured cache at '{}'", RootDir); CreateDirectories(RootDir); @@ -125,7 +133,8 @@ ZenCacheStore::Scrub(ScrubContext& Ctx) void ZenCacheStore::GarbageCollect(GcContext& GcCtx) { - ZEN_UNUSED(GcCtx); + m_DiskLayer.GarbageCollect(GcCtx); + m_MemLayer.GarbageCollect(GcCtx); } ////////////////////////////////////////////////////////////////////////// @@ -213,7 +222,12 @@ ZenCacheMemoryLayer::Scrub(ScrubContext& Ctx) void ZenCacheMemoryLayer::GarbageCollect(GcContext& GcCtx) { - ZEN_UNUSED(GcCtx); + RwLock::SharedLockScope _(m_Lock); + + for (auto& Kv : m_Buckets) + { + Kv.second.GarbageCollect(GcCtx); + } } void @@ -358,7 +372,7 @@ static_assert(sizeof(DiskIndexEntry) == 36); struct ZenCacheDiskLayer::CacheBucket { - CacheBucket(CasStore& Cas); + CacheBucket(); ~CacheBucket(); void OpenOrCreate(std::filesystem::path BucketDir, bool AllowCreate = true); @@ -374,7 +388,6 @@ struct ZenCacheDiskLayer::CacheBucket inline bool IsOk() const { return m_IsOk; } private: - CasStore& m_CasStore; std::filesystem::path m_BucketDir; Oid m_BucketId; bool m_IsOk = false; @@ -405,7 +418,7 @@ private: inline RwLock& LockForHash(const IoHash& Hash) { return m_ShardedLocks[Hash.Hash[19]]; } }; -ZenCacheDiskLayer::CacheBucket::CacheBucket(CasStore& Cas) : m_CasStore(Cas) +ZenCacheDiskLayer::CacheBucket::CacheBucket() { } @@ -839,7 +852,7 @@ ZenCacheDiskLayer::CacheBucket::PutStandaloneCacheValue(const IoHash& HashKey, c ////////////////////////////////////////////////////////////////////////// -ZenCacheDiskLayer::ZenCacheDiskLayer(CasStore& Cas, const std::filesystem::path& RootDir) : m_RootDir(RootDir), m_CasStore(Cas) +ZenCacheDiskLayer::ZenCacheDiskLayer(const std::filesystem::path& RootDir) : m_RootDir(RootDir) { } @@ -873,7 +886,7 @@ ZenCacheDiskLayer::Get(std::string_view InBucket, const IoHash& HashKey, ZenCach } else { - auto It = m_Buckets.try_emplace(std::string(InBucket), m_CasStore); + auto It = m_Buckets.try_emplace(std::string(InBucket)); Bucket = &It.first->second; std::filesystem::path BucketPath = m_RootDir; @@ -916,7 +929,7 @@ ZenCacheDiskLayer::Put(std::string_view InBucket, const IoHash& HashKey, const Z } else { - auto It = m_Buckets.try_emplace(std::string(InBucket), m_CasStore); + auto It = m_Buckets.try_emplace(std::string(InBucket)); Bucket = &It.first->second; std::filesystem::path bucketPath = m_RootDir; @@ -972,7 +985,7 @@ ZenCacheDiskLayer::DiscoverBuckets() } else { - auto InsertResult = m_Buckets.try_emplace(BucketName8, m_CasStore); + auto InsertResult = m_Buckets.try_emplace(BucketName8); std::filesystem::path BucketPath = m_RootDir; BucketPath /= BucketName8; @@ -1050,7 +1063,100 @@ ZenCacheDiskLayer::Scrub(ScrubContext& Ctx) void ZenCacheDiskLayer::GarbageCollect(GcContext& GcCtx) { - ZEN_UNUSED(GcCtx); + RwLock::SharedLockScope _(m_Lock); + + for (auto& Kv : m_Buckets) + { + Kv.second.GarbageCollect(GcCtx); + } +} + +////////////////////////////////////////////////////////////////////////// + +#if ZEN_WITH_TESTS + +TEST_CASE("z$.store") +{ + using namespace fmt::literals; + using namespace std::literals; + + ScopedTemporaryDirectory TempDir; + + ZenCacheStore Zcs(TempDir.Path() / "cache"); + + const int kIterationCount = 100; + + for (int i = 0; i < kIterationCount; ++i) + { + const IoHash Key = IoHash::HashBuffer(&i, sizeof i); + + CbObjectWriter Cbo; + Cbo << "hey" << i; + CbObject Obj = Cbo.Save(); + + ZenCacheValue Value; + Value.Value = Obj.GetBuffer().AsIoBuffer(); + Value.Value.SetContentType(ZenContentType::kCbObject); + + Zcs.Put("test_bucket"sv, Key, Value); + } + + for (int i = 0; i < kIterationCount; ++i) + { + const IoHash Key = IoHash::HashBuffer(&i, sizeof i); + + ZenCacheValue Value; + Zcs.Get("test_bucket"sv, Key, /* out */ Value); + + REQUIRE(Value.Value); + CHECK(Value.Value.GetContentType() == ZenContentType::kCbObject); + CHECK_EQ(ValidateCompactBinary(Value.Value, CbValidateMode::All), CbValidateError::None); + CbObject Obj = LoadCompactBinaryObject(Value.Value); + CHECK_EQ(Obj["hey"].AsInt32(), i); + } +} + +TEST_CASE("z$.gc") +{ + using namespace fmt::literals; + using namespace std::literals; + + ScopedTemporaryDirectory TempDir; + + CasStoreConfiguration Config{.RootDirectory = TempDir.Path()}; + std::unique_ptr Cas{CreateCasStore()}; + Cas->Initialize(Config); + + CidStore Cid(*Cas, TempDir.Path()); + + ZenCacheStore Zcs(TempDir.Path() / "cache"); + + const int kIterationCount = 100; + + for (int i = 0; i < kIterationCount; ++i) + { + const IoHash Key = IoHash::HashBuffer(&i, sizeof i); + + CompressedBuffer CompBuf = CompressedBuffer::Compress(SharedBuffer::MakeView("abcd"sv)); + Cid.AddChunk(CompBuf); + + CbObjectWriter Cbo; + Cbo << "hey" << i << "ref" << CbAttachment(CompBuf); + CbObject Obj = Cbo.Save(); + + ZenCacheValue Value; + Value.Value = Obj.GetBuffer().AsIoBuffer(); + Value.Value.SetContentType(ZenContentType::kCbObject); + + Zcs.Put("test_bucket"sv, Key, Value); + } +} + +#endif + +void +z$_forcelink() +{ } } // namespace zen -- cgit v1.2.3 From 7b2afa7e5791d2b401e32911362ac9f1e1106598 Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Fri, 29 Oct 2021 18:41:26 +0200 Subject: Minor cleanup --- zenserver/cache/structuredcachestore.cpp | 39 ++------------------------------ 1 file changed, 2 insertions(+), 37 deletions(-) (limited to 'zenserver/cache/structuredcachestore.cpp') diff --git a/zenserver/cache/structuredcachestore.cpp b/zenserver/cache/structuredcachestore.cpp index 02ec43115..e1d77a088 100644 --- a/zenserver/cache/structuredcachestore.cpp +++ b/zenserver/cache/structuredcachestore.cpp @@ -22,11 +22,12 @@ #include #include #include +#include #include #include -#include #include +#include ZEN_THIRD_PARTY_INCLUDES_START #include @@ -1116,42 +1117,6 @@ TEST_CASE("z$.store") } } -TEST_CASE("z$.gc") -{ - using namespace fmt::literals; - using namespace std::literals; - - ScopedTemporaryDirectory TempDir; - - CasStoreConfiguration Config{.RootDirectory = TempDir.Path()}; - std::unique_ptr Cas{CreateCasStore()}; - Cas->Initialize(Config); - - CidStore Cid(*Cas, TempDir.Path()); - - ZenCacheStore Zcs(TempDir.Path() / "cache"); - - const int kIterationCount = 100; - - for (int i = 0; i < kIterationCount; ++i) - { - const IoHash Key = IoHash::HashBuffer(&i, sizeof i); - - CompressedBuffer CompBuf = CompressedBuffer::Compress(SharedBuffer::MakeView("abcd"sv)); - Cid.AddChunk(CompBuf); - - CbObjectWriter Cbo; - Cbo << "hey" << i << "ref" << CbAttachment(CompBuf); - CbObject Obj = Cbo.Save(); - - ZenCacheValue Value; - Value.Value = Obj.GetBuffer().AsIoBuffer(); - Value.Value.SetContentType(ZenContentType::kCbObject); - - Zcs.Put("test_bucket"sv, Key, Value); - } -} - #endif void -- cgit v1.2.3 From 20317e28bec68fcd11e00026cd8308aefc0ce58b Mon Sep 17 00:00:00 2001 From: Martin Ridgers Date: Mon, 1 Nov 2021 10:45:26 +0100 Subject: Fixed possible undefined use error --- zenserver/cache/structuredcachestore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'zenserver/cache/structuredcachestore.cpp') diff --git a/zenserver/cache/structuredcachestore.cpp b/zenserver/cache/structuredcachestore.cpp index e1d77a088..45241eb68 100644 --- a/zenserver/cache/structuredcachestore.cpp +++ b/zenserver/cache/structuredcachestore.cpp @@ -160,7 +160,7 @@ ZenCacheMemoryLayer::Get(std::string_view InBucket, const IoHash& HashKey, ZenCa return false; } - CacheBucket* Bucket = Bucket = &it->second; + CacheBucket* Bucket = &it->second; _.ReleaseNow(); -- cgit v1.2.3 From 584855c4684204aa3cb0867ffb3fdbce61a936b3 Mon Sep 17 00:00:00 2001 From: Martin Ridgers Date: Mon, 1 Nov 2021 12:44:12 +0100 Subject: Moved declaration of ZenDiskCacheLayer::CacheBucket in the .h GCC fails to compile if CacheBucket is only forward-declared within the class, issuing an "incomplete type" error in relation to the m_Buckets unordered map. --- zenserver/cache/structuredcachestore.cpp | 122 ++++++++----------------------- 1 file changed, 31 insertions(+), 91 deletions(-) (limited to 'zenserver/cache/structuredcachestore.cpp') diff --git a/zenserver/cache/structuredcachestore.cpp b/zenserver/cache/structuredcachestore.cpp index 45241eb68..119062833 100644 --- a/zenserver/cache/structuredcachestore.cpp +++ b/zenserver/cache/structuredcachestore.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -317,107 +316,48 @@ ZenCacheMemoryLayer::CacheBucket::Put(const IoHash& HashKey, const ZenCacheValue ////////////////////////////////////////////////////////////////////////// -#pragma pack(push) -#pragma pack(1) +inline DiskLocation::DiskLocation() = default; -struct DiskLocation +inline DiskLocation::DiskLocation(uint64_t Offset, uint64_t ValueSize, uint32_t IndexSize, uint64_t Flags) +: OffsetAndFlags(CombineOffsetAndFlags(Offset, Flags)) +, LowerSize(ValueSize & 0xFFFFffff) +, IndexDataSize(IndexSize) { - inline DiskLocation() = default; - - inline DiskLocation(uint64_t Offset, uint64_t ValueSize, uint32_t IndexSize, uint64_t Flags) - : OffsetAndFlags(CombineOffsetAndFlags(Offset, Flags)) - , LowerSize(ValueSize & 0xFFFFffff) - , IndexDataSize(IndexSize) - { - } - - static const uint64_t kOffsetMask = 0x0000'ffFF'ffFF'ffFFull; - static const uint64_t kSizeMask = 0x00FF'0000'0000'0000ull; - static const uint64_t kFlagsMask = 0xff00'0000'0000'0000ull; - static const uint64_t kStandaloneFile = 0x8000'0000'0000'0000ull; - static const uint64_t kStructured = 0x4000'0000'0000'0000ull; - static const uint64_t kTombStone = 0x2000'0000'0000'0000ull; - - static uint64_t CombineOffsetAndFlags(uint64_t Offset, uint64_t Flags) { return Offset | Flags; } +} - inline uint64_t Offset() const { return OffsetAndFlags & kOffsetMask; } - inline uint64_t Size() const { return LowerSize; } - inline uint64_t IsFlagSet(uint64_t Flag) const { return OffsetAndFlags & Flag; } - inline ZenContentType GetContentType() const - { - ZenContentType ContentType = ZenContentType::kBinary; +inline uint64_t DiskLocation::CombineOffsetAndFlags(uint64_t Offset, uint64_t Flags) +{ + return Offset | Flags; +} - if (IsFlagSet(DiskLocation::kStructured)) - { - ContentType = ZenContentType::kCbObject; - } +inline uint64_t DiskLocation::Offset() const +{ + return OffsetAndFlags & kOffsetMask; +} - return ContentType; - } +inline uint64_t DiskLocation::Size() const +{ + return LowerSize; +} -private: - uint64_t OffsetAndFlags = 0; - uint32_t LowerSize = 0; - uint32_t IndexDataSize = 0; -}; +inline uint64_t DiskLocation::IsFlagSet(uint64_t Flag) const +{ + return OffsetAndFlags & Flag; +} -struct DiskIndexEntry +inline ZenContentType DiskLocation::GetContentType() const { - IoHash Key; - DiskLocation Location; -}; + ZenContentType ContentType = ZenContentType::kBinary; -#pragma pack(pop) + if (IsFlagSet(DiskLocation::kStructured)) + { + ContentType = ZenContentType::kCbObject; + } -static_assert(sizeof(DiskIndexEntry) == 36); + return ContentType; +} -struct ZenCacheDiskLayer::CacheBucket -{ - CacheBucket(); - ~CacheBucket(); - - void OpenOrCreate(std::filesystem::path BucketDir, bool AllowCreate = true); - static bool Delete(std::filesystem::path BucketDir); - - bool Get(const IoHash& HashKey, ZenCacheValue& OutValue); - void Put(const IoHash& HashKey, const ZenCacheValue& Value); - void Drop(); - void Flush(); - void Scrub(ScrubContext& Ctx); - void GarbageCollect(GcContext& GcCtx); - - inline bool IsOk() const { return m_IsOk; } - -private: - std::filesystem::path m_BucketDir; - Oid m_BucketId; - bool m_IsOk = false; - uint64_t m_LargeObjectThreshold = 64 * 1024; - - // These files are used to manage storage of small objects for this bucket - - BasicFile m_SobsFile; - TCasLogFile m_SlogFile; - - RwLock m_IndexLock; - tsl::robin_map m_Index; - uint64_t m_WriteCursor = 0; - - void BuildPath(WideStringBuilderBase& Path, const IoHash& HashKey); - void PutStandaloneCacheValue(const IoHash& HashKey, const ZenCacheValue& Value); - bool GetStandaloneCacheValue(const DiskLocation& Loc, const IoHash& HashKey, ZenCacheValue& OutValue); - bool GetInlineCacheValue(const DiskLocation& Loc, ZenCacheValue& OutValue); - - // These locks are here to avoid contention on file creation, therefore it's sufficient - // that we take the same lock for the same hash - // - // These locks are small and should really be spaced out so they don't share cache lines, - // but we don't currently access them at particularly high frequency so it should not be - // an issue in practice - - RwLock m_ShardedLocks[256]; - inline RwLock& LockForHash(const IoHash& Hash) { return m_ShardedLocks[Hash.Hash[19]]; } -}; +////////////////////////////////////////////////////////////////////////// ZenCacheDiskLayer::CacheBucket::CacheBucket() { -- cgit v1.2.3