diff options
| author | Per Larsson <[email protected]> | 2021-11-29 12:55:08 +0100 |
|---|---|---|
| committer | Per Larsson <[email protected]> | 2021-11-29 12:55:08 +0100 |
| commit | 9a8e2c8d905bc1e5b62c6f5e246d2574a645b73e (patch) | |
| tree | fb6cd0492812dd8ea99ba3dde27cc2b49dd978dc | |
| parent | Merged main. (diff) | |
| download | zen-9a8e2c8d905bc1e5b62c6f5e246d2574a645b73e.tar.xz zen-9a8e2c8d905bc1e5b62c6f5e246d2574a645b73e.zip | |
Moved GC to background thread and added endpoint to trigger/status GC.
| -rw-r--r-- | xmake.lua | 3 | ||||
| -rw-r--r-- | zenserver/admin/admin.cpp | 43 | ||||
| -rw-r--r-- | zenserver/admin/admin.h | 10 | ||||
| -rw-r--r-- | zenserver/xmake.lua | 3 | ||||
| -rw-r--r-- | zenserver/zenserver.cpp | 35 | ||||
| -rw-r--r-- | zenstore/gc.cpp | 28 | ||||
| -rw-r--r-- | zenstore/include/zenstore/gc.h | 22 |
7 files changed, 124 insertions, 20 deletions
@@ -17,7 +17,8 @@ add_requires( "vcpkg::curl", "vcpkg::zlib", "vcpkg::zstd", - "vcpkg::http-parser") + "vcpkg::http-parser", + "vcpkg::rocksdb") add_rules("mode.debug", "mode.release") diff --git a/zenserver/admin/admin.cpp b/zenserver/admin/admin.cpp index 2dd9b110f..0d7a57e36 100644 --- a/zenserver/admin/admin.cpp +++ b/zenserver/admin/admin.cpp @@ -5,11 +5,14 @@ #include "admin.h" #include <zencore/compactbinarybuilder.h> +#include <zencore/string.h> namespace zen { HttpAdminService::HttpAdminService() { + using namespace std::literals; + m_Router.RegisterRoute( "health", [this](HttpRouterRequest& Req) { @@ -19,12 +22,50 @@ HttpAdminService::HttpAdminService() }, HttpVerb::kGet); + m_Router.RegisterRoute( + "gc", + [this](HttpRouterRequest& Req) { + CbObject Response; + if (m_GcHandler.Status) + { + Response = m_GcHandler.Status(); + } + else + { + CbObjectWriter Writer; + Writer << "Status"sv + << "Ok"sv; + Response = Writer.Save(); + } + Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Response); + }, + HttpVerb::kGet); + + m_Router.RegisterRoute( + "gc", + [this](HttpRouterRequest& Req) { + CbObject Response; + if (m_GcHandler.Trigger) + { + Response = m_GcHandler.Trigger(); + } + else + { + CbObjectWriter Writer; + Writer << "Status"sv + << "Ok"sv; + Response = Writer.Save(); + } + Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Response); + }, + HttpVerb::kPost); + // RPC endpoint m_Router.RegisterRoute( "", [this](HttpRouterRequest& Req) { CbObject Payload = Req.ServerRequest().ReadPayloadObject(); - + CbObjectWriter Obj; Obj.AddBool("ok", true); Req.ServerRequest().WriteResponse(HttpResponseCode::OK, Obj.Save()); diff --git a/zenserver/admin/admin.h b/zenserver/admin/admin.h index 6257f0998..f8fcab7de 100644 --- a/zenserver/admin/admin.h +++ b/zenserver/admin/admin.h @@ -2,6 +2,7 @@ #pragma once +#include <zencore/compactbinary.h> #include <zenhttp/httpserver.h> namespace zen { @@ -15,8 +16,17 @@ public: virtual const char* BaseUri() const override; virtual void HandleRequest(zen::HttpServerRequest& Request) override; + struct GcHandler + { + std::function<CbObject()> Trigger; + std::function<CbObject()> Status; + }; + + void RegisterGcHandler(GcHandler&& Handler) { m_GcHandler = std::forward<GcHandler>(Handler); } + private: HttpRequestRouter m_Router; + GcHandler m_GcHandler; }; } // namespace zen diff --git a/zenserver/xmake.lua b/zenserver/xmake.lua index bba9b6ba5..600c8d053 100644 --- a/zenserver/xmake.lua +++ b/zenserver/xmake.lua @@ -26,7 +26,8 @@ target("zenserver") "vcpkg::lua", "vcpkg::asio", "vcpkg::json11", - "vcpkg::http-parser" + "vcpkg::http-parser", + "vcpkg::rocksdb" ) add_packages( diff --git a/zenserver/zenserver.cpp b/zenserver/zenserver.cpp index e9c41d070..b1bcb545f 100644 --- a/zenserver/zenserver.cpp +++ b/zenserver/zenserver.cpp @@ -195,6 +195,21 @@ public: .HttpServerClass = std::string(ServerOptions.HttpServerClass), .BuildVersion = std::string(BUILD_VERSION)}); + m_AdminService.RegisterGcHandler({.Trigger = + [this]() { + CbObjectWriter Writer; + const bool Started = m_Gc.Trigger(); + Writer << "Status"sv << (Started ? "Started"sv : "Running"sv); + return Writer.Save(); + }, + .Status = + [this]() { + CbObjectWriter Writer; + const GcStatus Status = m_Gc.Status(); + Writer << "Status"sv << (GcStatus::kIdle == Status ? "Idle"sv : "Running"sv); + return Writer.Save(); + }}); + // Ok so now we're configured, let's kick things off m_Http = zen::CreateHttpServer(ServerOptions.HttpServerClass); @@ -214,11 +229,11 @@ public: m_CasStore->Initialize(Config); m_CidStore = std::make_unique<zen::CidStore>(*m_CasStore, m_DataRoot / "cid"); - m_Gc.SetCidStore(m_CidStore.get()); + m_Gc.Cas().SetCidStore(m_CidStore.get()); ZEN_INFO("instantiating project service"); - m_ProjectStore = new zen::ProjectStore(*m_CidStore, m_DataRoot / "projects", m_Gc); + m_ProjectStore = new zen::ProjectStore(*m_CidStore, m_DataRoot / "projects", m_Gc.Cas()); m_HttpProjectService.reset(new zen::HttpProjectService{*m_CidStore, m_ProjectStore}); #if ZEN_USE_NAMED_PIPES @@ -440,16 +455,6 @@ public: NiceByteRate(Ctx.ScrubbedBytes(), ElapsedTimeMs)); } - void CollectGarbage() - { - Stopwatch Timer; - ZEN_INFO("Garbage collection STARTING"); - - m_Gc.CollectGarbage(); - - ZEN_INFO("Garbage collection DONE after {}", NiceTimeSpanMs(Timer.GetElapsedTimeMs())); - } - void Flush() { if (m_CasStore) @@ -513,8 +518,8 @@ private: zen::Ref<zen::HttpServer> m_Http; zen::HttpStatusService m_StatusService; zen::HttpStatsService m_StatsService; - zen::CasGc m_Gc; - std::unique_ptr<zen::CasStore> m_CasStore{zen::CreateCasStore(m_Gc)}; + zen::Gc m_Gc; + std::unique_ptr<zen::CasStore> m_CasStore{zen::CreateCasStore(m_Gc.Cas())}; std::unique_ptr<zen::CidStore> m_CidStore; std::unique_ptr<zen::ZenCacheStore> m_CacheStore; zen::CasScrubber m_Scrubber{*m_CasStore}; @@ -656,7 +661,7 @@ ZenServer::InitializeStructuredCache(const ZenServerOptions& ServerOptions) auto ValueOrDefault = [](std::string_view Value, std::string_view Default) { return Value.empty() ? Default : Value; }; ZEN_INFO("instantiating structured cache service"); - m_CacheStore = std::make_unique<ZenCacheStore>(m_Gc, m_DataRoot / "cache"); + m_CacheStore = std::make_unique<ZenCacheStore>(m_Gc.Cas(), m_DataRoot / "cache"); std::unique_ptr<zen::UpstreamCache> UpstreamCache; if (ServerOptions.UpstreamCacheConfig.CachePolicy != UpstreamCachePolicy::Disabled) diff --git a/zenstore/gc.cpp b/zenstore/gc.cpp index 278f09b0b..52bb33955 100644 --- a/zenstore/gc.cpp +++ b/zenstore/gc.cpp @@ -2,9 +2,11 @@ #include <zenstore/gc.h> +#include <zencore/logging.h> +#include <zencore/string.h> +#include <zencore/timer.h> #include <zenstore/CAS.h> #include <zenstore/cidstore.h> -#include <zencore/logging.h> namespace zen { @@ -202,4 +204,28 @@ CasGc::OnDroppedCidReferences(std::span<IoHash> Hashes) ZEN_UNUSED(Hashes); } +bool +Gc::Trigger() +{ + uint32_t Expected = uint32_t(GcStatus::kIdle); + if (!m_Status.compare_exchange_strong(Expected, static_cast<uint32_t>(GcStatus::kRunning))) + { + return false; + } + + ZEN_ASSERT(GcStatus::kRunning == Status()); + + m_GcThread = std::jthread([this]() { + Stopwatch Timer; + ZEN_INFO("garbage collection STARTING"); + + m_CasGc.CollectGarbage(); + m_Status = static_cast<uint32_t>(GcStatus::kIdle); + + ZEN_INFO("garbage collection DONE after {}", NiceTimeSpanMs(Timer.GetElapsedTimeMs())); + }); + + return true; +} + } // namespace zen diff --git a/zenstore/include/zenstore/gc.h b/zenstore/include/zenstore/gc.h index 560642803..8efe933a0 100644 --- a/zenstore/include/zenstore/gc.h +++ b/zenstore/include/zenstore/gc.h @@ -5,8 +5,9 @@ #include <zencore/iohash.h> #include <zencore/thread.h> -#include <span> +#include <atomic> #include <functional> +#include <span> #define ZEN_USE_REF_TRACKING 0 // This is not currently functional @@ -107,4 +108,23 @@ private: CidStore* m_CidStore; }; +enum class GcStatus : uint32_t +{ + kIdle, + kRunning +}; + +class Gc +{ +public: + bool Trigger(); + CasGc& Cas() { return m_CasGc; } + GcStatus Status() const { return static_cast<GcStatus>(m_Status.load()); } + +private: + CasGc m_CasGc; + std::jthread m_GcThread; + std::atomic_uint32_t m_Status; +}; + } // namespace zen |