aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2025-10-13 12:01:55 +0200
committerGitHub Enterprise <[email protected]>2025-10-13 12:01:55 +0200
commitd86ca9ac1c76e2841c44ede6b39930b6f934ef93 (patch)
treeec2c6a936229d343c843ac5f1962cb2ba96c8db0
parenthide http.sys options when unavailable (#568) (diff)
downloadzen-d86ca9ac1c76e2841c44ede6b39930b6f934ef93.tar.xz
zen-d86ca9ac1c76e2841c44ede6b39930b6f934ef93.zip
move service common code into base class (#567)
Separates storage server code and generic server code into two classes. This is a change to prepare for different services to be implemented using the same framework, into the same executable
-rw-r--r--src/zenserver/config.cpp10
-rw-r--r--src/zenserver/config.h69
-rw-r--r--src/zenserver/main.cpp241
-rw-r--r--src/zenserver/zenserver.cpp642
-rw-r--r--src/zenserver/zenserver.h163
5 files changed, 626 insertions, 499 deletions
diff --git a/src/zenserver/config.cpp b/src/zenserver/config.cpp
index a355f0ed5..ce3a70184 100644
--- a/src/zenserver/config.cpp
+++ b/src/zenserver/config.cpp
@@ -95,7 +95,7 @@ ReadAllCentralManifests(const std::filesystem::path& SystemRoot)
}
void
-ValidateOptions(ZenServerOptions& ServerOptions)
+ValidateOptions(ZenStorageServerOptions& ServerOptions)
{
if (ServerOptions.EncryptionKey.empty() == false)
{
@@ -440,7 +440,7 @@ MakeOption(std::vector<std::pair<std::string, ZenStructuredCacheBucketConfig>>&
};
void
-ParseEnvVariables(ZenServerOptions& ServerOptions, const cxxopts::ParseResult& CmdLineResult)
+ParseEnvVariables(ZenStorageServerOptions& ServerOptions, const cxxopts::ParseResult& CmdLineResult)
{
using namespace std::literals;
@@ -464,7 +464,7 @@ ParseEnvVariables(ZenServerOptions& ServerOptions, const cxxopts::ParseResult& C
void
ParseConfigFile(const std::filesystem::path& Path,
- ZenServerOptions& ServerOptions,
+ ZenStorageServerOptions& ServerOptions,
const cxxopts::ParseResult& CmdLineResult,
std::string_view OutputConfigFile)
{
@@ -679,7 +679,7 @@ ParseConfigFile(const std::filesystem::path& Path,
}
void
-ParsePluginsConfigFile(const std::filesystem::path& Path, ZenServerOptions& ServerOptions, int BasePort)
+ParsePluginsConfigFile(const std::filesystem::path& Path, ZenStorageServerOptions& ServerOptions, int BasePort)
{
using namespace std::literals;
@@ -741,7 +741,7 @@ ParsePluginsConfigFile(const std::filesystem::path& Path, ZenServerOptions& Serv
}
void
-ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions)
+ParseCliOptions(int argc, char* argv[], ZenStorageServerOptions& ServerOptions)
{
const char* DefaultHttp = "asio";
diff --git a/src/zenserver/config.h b/src/zenserver/config.h
index 3f7cb149a..d2311396e 100644
--- a/src/zenserver/config.h
+++ b/src/zenserver/config.h
@@ -170,55 +170,60 @@ struct ZenSentryConfig
struct ZenServerOptions
{
+ HttpServerConfig HttpServerConfig;
+ ZenSentryConfig SentryConfig;
+ int BasePort = 8558; // Service listen port (used for both UDP and TCP)
+ int OwnerPid = 0; // Parent process id (zero for standalone)
+ bool IsDebug = false;
+ bool IsCleanStart = false; // Indicates whether all state should be wiped on startup or not
+ bool IsPowerCycle = false; // When true, the process shuts down immediately after initialization
+ bool IsTest = false;
+ bool Detach = true; // Whether zenserver should detach from existing process group (Mac/Linux)
+ bool NoConsoleOutput = false; // Control default use of stdout for diagnostics
+ bool QuietConsole = false; // Configure console logger output to level WARN
+ int CoreLimit = 0; // If set, hardware concurrency queries are capped at this number
+ bool IsDedicated = false; // Indicates a dedicated/shared instance, with larger resource requirements
+ bool ShouldCrash = false; // Option for testing crash handling
+ bool IsFirstRun = false;
+ std::filesystem::path SystemRootDir; // System root directory (used for machine level config)
+ std::filesystem::path ContentDir; // Root directory for serving frontend content (experimental)
+ std::filesystem::path DataDir; // Root directory for state (used for testing)
+ std::filesystem::path AbsLogFile; // Absolute path to main log file
+ std::string ChildId; // Id assigned by parent process (used for lifetime management)
+ std::string LogId; // Id for tagging log output
+ std::string Loggers[zen::logging::level::LogLevelCount];
+#if ZEN_WITH_TRACE
+ bool HasTraceCommandlineOptions = false;
+ TraceOptions TraceOptions;
+#endif
+ std::string MemoryOptions; // Memory allocation options
+ std::string CommandLine;
+ std::string EncryptionKey; // 256 bit AES encryption key
+ std::string EncryptionIV; // 128 bit AES initialization vector
+
+ ZenStatsConfig StatsConfig;
+};
+
+struct ZenStorageServerOptions : public ZenServerOptions
+{
ZenUpstreamCacheConfig UpstreamCacheConfig;
ZenGcConfig GcConfig;
ZenAuthConfig AuthConfig;
ZenObjectStoreConfig ObjectStoreConfig;
- zen::HttpServerConfig HttpServerConfig;
ZenStructuredCacheConfig StructuredCacheConfig;
ZenProjectStoreConfig ProjectStoreConfig;
ZenBuildStoreConfig BuildStoreConfig;
- ZenStatsConfig StatsConfig;
ZenWorkspacesConfig WorksSpacesConfig;
- ZenSentryConfig SentryConfig;
- std::filesystem::path SystemRootDir; // System root directory (used for machine level config)
- std::filesystem::path DataDir; // Root directory for state (used for testing)
- std::filesystem::path ContentDir; // Root directory for serving frontend content (experimental)
- std::filesystem::path AbsLogFile; // Absolute path to main log file
std::filesystem::path ConfigFile; // Path to Lua config file
std::filesystem::path PluginsConfigFile; // Path to plugins config file
std::filesystem::path BaseSnapshotDir; // Path to server state snapshot (will be copied into data dir on start)
- std::string ChildId; // Id assigned by parent process (used for lifetime management)
- std::string LogId; // Id for tagging log output
- std::string EncryptionKey; // 256 bit AES encryption key
- std::string EncryptionIV; // 128 bit AES initialization vector
- int BasePort = 8558; // Service listen port (used for both UDP and TCP)
- int OwnerPid = 0; // Parent process id (zero for standalone)
bool InstallService = false; // Flag used to initiate service install (temporary)
bool UninstallService = false; // Flag used to initiate service uninstall (temporary)
- bool IsDebug = false;
- bool IsCleanStart = false; // Indicates whether all state should be wiped on startup or not
- bool IsPowerCycle = false; // When true, the process shuts down immediately after initialization
- bool IsTest = false;
- bool IsDedicated = false; // Indicates a dedicated/shared instance, with larger resource requirements
- bool ShouldCrash = false; // Option for testing crash handling
- bool IsFirstRun = false;
- bool Detach = true; // Whether zenserver should detach from existing process group (Mac/Linux)
bool ObjectStoreEnabled = false;
- bool NoConsoleOutput = false; // Control default use of stdout for diagnostics
- bool QuietConsole = false; // Configure console logger output to level WARN
- int CoreLimit = 0; // If set, hardware concurrency queries are capped at this number
- std::string Loggers[zen::logging::level::LogLevelCount];
std::string ScrubOptions;
-#if ZEN_WITH_TRACE
- bool HasTraceCommandlineOptions = false;
- TraceOptions TraceOptions;
-#endif
- std::string MemoryOptions; // Memory allocation options
- std::string CommandLine;
};
-void ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions);
+void ParseCliOptions(int argc, char* argv[], ZenStorageServerOptions& ServerOptions);
void EmitCentralManifest(const std::filesystem::path& SystemRoot, Oid Identifier, CbObject Manifest, std::filesystem::path ManifestPath);
std::vector<CbObject> ReadAllCentralManifests(const std::filesystem::path& SystemRoot);
diff --git a/src/zenserver/main.cpp b/src/zenserver/main.cpp
index b4d53ec5f..0dc390797 100644
--- a/src/zenserver/main.cpp
+++ b/src/zenserver/main.cpp
@@ -14,9 +14,7 @@
#include <zencore/session.h>
#include <zencore/string.h>
#include <zencore/thread.h>
-#include <zencore/timer.h>
#include <zencore/trace.h>
-#include <zenhttp/httpserver.h>
#include <zencore/memory/fmalloc.h>
#include <zencore/memory/llm.h>
@@ -73,25 +71,53 @@ using namespace std::literals;
////////////////////////////////////////////////////////////////////////////////
-class ZenEntryPoint
+class ZenServerMain
{
public:
- ZenEntryPoint(ZenServerOptions& ServerOptions);
- ZenEntryPoint(const ZenEntryPoint&) = delete;
- ZenEntryPoint& operator=(const ZenEntryPoint&) = delete;
- int Run();
+ ZenServerMain(ZenServerOptions& ServerOptions);
+ ~ZenServerMain();
-private:
+ int Run();
+
+ ZenServerMain(const ZenServerMain&) = delete;
+ ZenServerMain& operator=(const ZenServerMain&) = delete;
+
+protected:
ZenServerOptions& m_ServerOptions;
LockFile m_LockFile;
+
+ virtual void DoRun(ZenServerState::ZenServerEntry* Entry) = 0;
+
+ void NotifyReady()
+ {
+ if (!m_ServerOptions.ChildId.empty())
+ {
+ NamedEvent ParentEvent{m_ServerOptions.ChildId};
+ ParentEvent.Set();
+ }
+ }
+
+ CbObject MakeLockData(bool IsReady)
+ {
+ return MakeLockFilePayload({.Pid = GetCurrentProcessId(),
+ .SessionId = GetSessionId(),
+ .EffectiveListenPort = gsl::narrow<uint16_t>(m_ServerOptions.BasePort),
+ .Ready = IsReady,
+ .DataDir = m_ServerOptions.DataDir,
+ .ExecutablePath = GetRunningExecutablePath()});
+ };
};
-ZenEntryPoint::ZenEntryPoint(ZenServerOptions& ServerOptions) : m_ServerOptions(ServerOptions)
+ZenServerMain::ZenServerMain(ZenServerOptions& ServerOptions) : m_ServerOptions(ServerOptions)
+{
+}
+
+ZenServerMain::~ZenServerMain()
{
}
int
-ZenEntryPoint::Run()
+ZenServerMain::Run()
{
// On Linux this has the unfortunate side effect of making `top` and other tools display
// `main` as the program name since threads and processes have a closer relationship
@@ -118,6 +144,7 @@ ZenEntryPoint::Run()
m_ServerOptions.CommandLine);
}
#endif
+
try
{
// Mutual exclusion and synchronization
@@ -125,14 +152,6 @@ ZenEntryPoint::Run()
ServerState.Initialize();
ServerState.Sweep();
- auto NotifyReady = [&] {
- if (!m_ServerOptions.ChildId.empty())
- {
- NamedEvent ParentEvent{m_ServerOptions.ChildId};
- ParentEvent.Set();
- }
- };
-
uint32_t AttachSponsorProcessRetriesLeft = 3;
ZenServerState::ZenServerEntry* Entry = ServerState.Lookup(m_ServerOptions.BasePort);
while (Entry)
@@ -202,15 +221,6 @@ ZenEntryPoint::Run()
std::filesystem::path LockFilePath = m_ServerOptions.DataDir / ".lock";
- auto MakeLockData = [&](bool IsReady) {
- return MakeLockFilePayload({.Pid = GetCurrentProcessId(),
- .SessionId = GetSessionId(),
- .EffectiveListenPort = gsl::narrow<uint16_t>(m_ServerOptions.BasePort),
- .Ready = IsReady,
- .DataDir = m_ServerOptions.DataDir,
- .ExecutablePath = GetRunningExecutablePath()});
- };
-
m_LockFile.Create(LockFilePath, MakeLockData(false), Ec);
if (Ec)
@@ -253,78 +263,9 @@ ZenEntryPoint::Run()
Entry->AddSponsorProcess(m_ServerOptions.OwnerPid, 0);
}
- ZenServer Server;
- Server.SetDataRoot(m_ServerOptions.DataDir);
- Server.SetContentRoot(m_ServerOptions.ContentDir);
- Server.SetTestMode(m_ServerOptions.IsTest);
- Server.SetDedicatedMode(m_ServerOptions.IsDedicated);
-
- auto ServerCleanup = MakeGuard([&Server] { Server.Cleanup(); });
-
- int EffectiveBasePort = Server.Initialize(m_ServerOptions, Entry);
- if (EffectiveBasePort == -1)
- {
- // Server.Initialize has already logged what the issue is - just exit with failure code here.
- std::exit(1);
- }
-
- Entry->EffectiveListenPort = uint16_t(EffectiveBasePort);
- if (EffectiveBasePort != m_ServerOptions.BasePort)
- {
- ZEN_INFO(ZEN_APP_NAME " - relocated to base port {}", EffectiveBasePort);
- m_ServerOptions.BasePort = EffectiveBasePort;
- }
-
- std::unique_ptr<std::thread> ShutdownThread;
- std::unique_ptr<NamedEvent> ShutdownEvent;
-
- ExtendableStringBuilder<64> ShutdownEventName;
- ShutdownEventName << "Zen_" << m_ServerOptions.BasePort << "_Shutdown";
- ShutdownEvent.reset(new NamedEvent{ShutdownEventName});
-
- // Monitor shutdown signals
-
- ShutdownThread.reset(new std::thread{[&] {
- SetCurrentThreadName("shutdown_monitor");
-
- ZEN_INFO("shutdown monitor thread waiting for shutdown signal '{}' for process {}",
- ShutdownEventName,
- zen::GetCurrentProcessId());
-
- if (ShutdownEvent->Wait())
- {
- ZEN_INFO("shutdown signal for pid {} received", zen::GetCurrentProcessId());
- Server.RequestExit(0);
- }
- else
- {
- ZEN_INFO("shutdown signal wait() failed");
- }
- }});
-
- auto CleanupShutdown = MakeGuard([&ShutdownEvent, &ShutdownThread] {
- ReportServiceStatus(ServiceStatus::Stopping);
-
- if (ShutdownEvent)
- {
- ShutdownEvent->Set();
- }
- if (ShutdownThread && ShutdownThread->joinable())
- {
- ShutdownThread->join();
- }
- });
-
- // If we have a parent process, establish the mechanisms we need
- // to be able to communicate readiness with the parent
-
- Server.SetIsReadyFunc([&] {
- m_LockFile.Update(MakeLockData(true), Ec);
- ReportServiceStatus(ServiceStatus::Running);
- NotifyReady();
- });
+ // Run the actual application logic
- Server.Run();
+ DoRun(Entry);
}
catch (const AssertException& AssertEx)
{
@@ -355,13 +296,109 @@ ZenEntryPoint::Run()
}
//////////////////////////////////////////////////////////////////////////
+class ZenStorageServerMain : public ZenServerMain
+{
+public:
+ ZenStorageServerMain(ZenStorageServerOptions& ServerOptions);
+ virtual void DoRun(ZenServerState::ZenServerEntry* Entry) override;
+
+ ZenStorageServerMain(const ZenStorageServerMain&) = delete;
+ ZenStorageServerMain& operator=(const ZenStorageServerMain&) = delete;
+
+private:
+ ZenStorageServerOptions& m_ServerOptions;
+};
+
+ZenStorageServerMain::ZenStorageServerMain(ZenStorageServerOptions& ServerOptions)
+: ZenServerMain(ServerOptions)
+, m_ServerOptions(ServerOptions)
+{
+}
+
+void
+ZenStorageServerMain::DoRun(ZenServerState::ZenServerEntry* Entry)
+{
+ ZenStorageServer Server;
+ Server.SetDataRoot(m_ServerOptions.DataDir);
+ Server.SetContentRoot(m_ServerOptions.ContentDir);
+ Server.SetTestMode(m_ServerOptions.IsTest);
+ Server.SetDedicatedMode(m_ServerOptions.IsDedicated);
+
+ auto ServerCleanup = MakeGuard([&Server] { Server.Cleanup(); });
+
+ int EffectiveBasePort = Server.Initialize(m_ServerOptions, Entry);
+ if (EffectiveBasePort == -1)
+ {
+ // Server.Initialize has already logged what the issue is - just exit with failure code here.
+ std::exit(1);
+ }
+
+ Entry->EffectiveListenPort = uint16_t(EffectiveBasePort);
+ if (EffectiveBasePort != m_ServerOptions.BasePort)
+ {
+ ZEN_INFO(ZEN_APP_NAME " - relocated to base port {}", EffectiveBasePort);
+ m_ServerOptions.BasePort = EffectiveBasePort;
+ }
+
+ std::unique_ptr<std::thread> ShutdownThread;
+ std::unique_ptr<NamedEvent> ShutdownEvent;
+
+ ExtendableStringBuilder<64> ShutdownEventName;
+ ShutdownEventName << "Zen_" << m_ServerOptions.BasePort << "_Shutdown";
+ ShutdownEvent.reset(new NamedEvent{ShutdownEventName});
+
+ // Monitor shutdown signals
+
+ ShutdownThread.reset(new std::thread{[&] {
+ SetCurrentThreadName("shutdown_monitor");
+
+ ZEN_INFO("shutdown monitor thread waiting for shutdown signal '{}' for process {}", ShutdownEventName, zen::GetCurrentProcessId());
+
+ if (ShutdownEvent->Wait())
+ {
+ ZEN_INFO("shutdown signal for pid {} received", zen::GetCurrentProcessId());
+ Server.RequestExit(0);
+ }
+ else
+ {
+ ZEN_INFO("shutdown signal wait() failed");
+ }
+ }});
+
+ auto CleanupShutdown = MakeGuard([&ShutdownEvent, &ShutdownThread] {
+ ReportServiceStatus(ServiceStatus::Stopping);
+
+ if (ShutdownEvent)
+ {
+ ShutdownEvent->Set();
+ }
+ if (ShutdownThread && ShutdownThread->joinable())
+ {
+ ShutdownThread->join();
+ }
+ });
+
+ // If we have a parent process, establish the mechanisms we need
+ // to be able to communicate readiness with the parent
+
+ Server.SetIsReadyFunc([&] {
+ std::error_code Ec;
+ m_LockFile.Update(MakeLockData(true), Ec);
+ ReportServiceStatus(ServiceStatus::Running);
+ NotifyReady();
+ });
+
+ Server.Run();
+}
+
+//////////////////////////////////////////////////////////////////////////
#if ZEN_PLATFORM_WINDOWS
class ZenWindowsService : public WindowsService
{
public:
- ZenWindowsService(ZenServerOptions& ServerOptions) : m_EntryPoint(ServerOptions) {}
+ ZenWindowsService(ZenStorageServerOptions& ServerOptions) : m_EntryPoint(ServerOptions) {}
ZenWindowsService(const ZenWindowsService&) = delete;
ZenWindowsService& operator=(const ZenWindowsService&) = delete;
@@ -369,7 +406,7 @@ public:
virtual int Run() override;
private:
- ZenEntryPoint m_EntryPoint;
+ ZenStorageServerMain m_EntryPoint;
};
int
@@ -426,7 +463,7 @@ main(int argc, char* argv[])
try
{
- ZenServerOptions ServerOptions;
+ ZenStorageServerOptions ServerOptions;
{
#if ZEN_WITH_TRACE
@@ -508,7 +545,7 @@ main(int argc, char* argv[])
throw std::runtime_error("Service mode is not supported on this platform");
}
- ZenEntryPoint App(ServerOptions);
+ ZenStorageServerMain App(ServerOptions);
return App.Run();
#endif
}
diff --git a/src/zenserver/zenserver.cpp b/src/zenserver/zenserver.cpp
index 82ebc1711..0f53e657f 100644
--- a/src/zenserver/zenserver.cpp
+++ b/src/zenserver/zenserver.cpp
@@ -107,31 +107,22 @@ namespace utils {
//////////////////////////////////////////////////////////////////////////
-ZenServer::ZenServer()
+ZenServerBase::ZenServerBase()
{
}
-ZenServer::~ZenServer()
+ZenServerBase::~ZenServerBase()
{
}
-void
-ZenServer::OnReady()
-{
- m_ServerEntry->SignalReady();
-
- if (m_IsReadyFunc)
- {
- m_IsReadyFunc();
- }
-}
-
int
-ZenServer::Initialize(const ZenServerOptions& ServerOptions, ZenServerState::ZenServerEntry* ServerEntry)
+ZenServerBase::Initialize(const ZenServerOptions& ServerOptions, ZenServerState::ZenServerEntry* ServerEntry)
{
- ZEN_TRACE_CPU("ZenServer::Initialize");
-
+ ZEN_TRACE_CPU("ZenServerBase::Initialize");
ZEN_MEMSCOPE(GetZenserverTag());
+
+ m_IsPowerCycle = ServerOptions.IsPowerCycle;
+
const std::string MutexName = fmt::format("zen_{}", ServerOptions.BasePort);
if (NamedMutex::Exists(MutexName))
@@ -140,14 +131,12 @@ ZenServer::Initialize(const ZenServerOptions& ServerOptions, ZenServerState::Zen
return -1;
}
- m_UseSentry = ServerOptions.SentryConfig.Disable == false;
- m_ServerEntry = ServerEntry;
- m_DebugOptionForcedCrash = ServerOptions.ShouldCrash;
- m_IsPowerCycle = ServerOptions.IsPowerCycle;
- const int ParentPid = ServerOptions.OwnerPid;
- m_StartupScrubOptions = ServerOptions.ScrubOptions;
+ m_UseSentry = ServerOptions.SentryConfig.Disable == false;
+ m_ServerEntry = ServerEntry;
+
+ // Initialize parent (sponsor) process monitoring
- if (ParentPid)
+ if (const int ParentPid = ServerOptions.OwnerPid)
{
std::error_code Ec;
ProcessHandle OwnerProcess;
@@ -175,16 +164,7 @@ ZenServer::Initialize(const ZenServerOptions& ServerOptions, ZenServerState::Zen
ThrowLastError(fmt::format("Failed to create mutex '{}'", MutexName).c_str());
}
- InitializeState(ServerOptions);
-
- m_JobQueue = MakeJobQueue(8, "bgjobs");
-
- m_HealthService.SetHealthInfo({.DataRoot = m_DataRoot,
- .AbsLogPath = ServerOptions.AbsLogFile,
- .HttpServerClass = std::string(ServerOptions.HttpServerConfig.ServerClass),
- .BuildVersion = std::string(ZEN_CFG_VERSION_BUILD_STRING_FULL)});
-
- // Ok so now we're configured, let's kick things off
+ EnqueueSigIntTimer();
m_Http = CreateHttpServer(ServerOptions.HttpServerConfig);
int EffectiveBasePort = m_Http->Initialize(ServerOptions.BasePort, ServerOptions.DataDir);
@@ -197,56 +177,311 @@ ZenServer::Initialize(const ZenServerOptions& ServerOptions, ZenServerState::Zen
return -1;
}
- // Setup authentication manager
+ ZEN_INFO("Effective concurrency: {} (hw: {})", GetHardwareConcurrency(), std::thread::hardware_concurrency());
+
+ m_StatusService.RegisterHandler("status", *this);
+ m_Http->RegisterService(m_StatusService);
+
+ m_StatsReporter.Initialize(ServerOptions.StatsConfig);
+ if (ServerOptions.StatsConfig.Enabled)
{
- ZEN_TRACE_CPU("Zenserver::InitAuth");
- std::string EncryptionKey = ServerOptions.EncryptionKey;
+ EnqueueStatsReportingTimer();
+ }
- if (EncryptionKey.empty())
+ return EffectiveBasePort;
+}
+
+void
+ZenServerBase::Finalize()
+{
+ // Register health service last so if we return "OK" for health it means all services have been properly initialized
+
+ m_Http->RegisterService(m_HealthService);
+}
+
+void
+ZenServerBase::EnsureIoRunner()
+{
+ ZEN_MEMSCOPE(GetZenserverTag());
+ if (!m_IoRunner.joinable())
+ {
+ m_IoRunner = std::thread{[this] {
+ SetCurrentThreadName("timer_io");
+ m_IoContext.run();
+ }};
+ }
+}
+
+void
+ZenServerBase::OnReady()
+{
+ if (m_ServerEntry)
+ {
+ m_ServerEntry->SignalReady();
+ }
+
+ if (m_IsReadyFunc)
+ {
+ m_IsReadyFunc();
+ }
+}
+
+void
+ZenServerBase::RequestExit(int ExitCode)
+{
+ if (RequestApplicationExit(ExitCode))
+ {
+ if (m_Http)
{
- EncryptionKey = "abcdefghijklmnopqrstuvxyz0123456";
+ m_Http->RequestExit();
+ }
+ }
+}
- if (ServerOptions.IsDedicated)
- {
- ZEN_WARN("Using default encryption key for authentication state");
- }
+std::string_view
+ZenServerBase::ToString(ServerState Value)
+{
+ switch (Value)
+ {
+ case kInitializing:
+ return "initializing"sv;
+ case kRunning:
+ return "running"sv;
+ case kShuttingDown:
+ return "shutdown"sv;
+ default:
+ return "unknown"sv;
+ }
+}
+
+void
+ZenServerBase::EnqueueStatsReportingTimer()
+{
+ ZEN_MEMSCOPE(GetZenserverTag());
+ m_StatsReportingTimer.expires_after(std::chrono::milliseconds(500));
+ m_StatsReportingTimer.async_wait([this](const asio::error_code& Ec) {
+ if (!Ec)
+ {
+ m_StatsReporter.ReportStats();
+ EnqueueStatsReportingTimer();
}
+ });
+ EnsureIoRunner();
+}
- std::string EncryptionIV = ServerOptions.EncryptionIV;
+void
+ZenServerBase::EnqueueProcessMonitorTimer()
+{
+ ZEN_MEMSCOPE(GetZenserverTag());
+ m_PidCheckTimer.expires_after(std::chrono::seconds(1));
+ m_PidCheckTimer.async_wait([this](const asio::error_code&) { CheckOwnerPid(); });
- if (EncryptionIV.empty())
+ EnsureIoRunner();
+}
+
+void
+ZenServerBase::CheckOwnerPid()
+{
+ bool IsRunning = UpdateProcessMonitor();
+
+ if (IsRunning)
+ {
+ m_FoundNoActiveSponsors = false;
+ EnqueueProcessMonitorTimer();
+ }
+ else
+ {
+ // Delay exit one iteration to avoid race conditions where one process detaches
+ // and another attaches
+ if (m_FoundNoActiveSponsors)
{
- EncryptionIV = "0123456789abcdef";
+ ZEN_INFO(ZEN_APP_NAME " exiting since sponsor processes are all gone");
+ RequestExit(0);
+ }
+ else
+ {
+ m_FoundNoActiveSponsors = true;
+ EnqueueProcessMonitorTimer();
+ }
+ }
+}
- if (ServerOptions.IsDedicated)
+bool
+ZenServerBase::UpdateProcessMonitor()
+{
+ if (m_ServerEntry)
+ {
+ // Pick up any new "owner" processes
+ std::set<uint32_t> AddedPids;
+
+ for (auto& PidEntry : m_ServerEntry->SponsorPids)
+ {
+ if (uint32_t ThisPid = PidEntry.load(std::memory_order_relaxed))
{
- ZEN_WARN("Using default encryption initialization vector for authentication state");
+ if (PidEntry.compare_exchange_strong(ThisPid, 0))
+ {
+ if (AddedPids.insert(ThisPid).second)
+ {
+ m_ProcessMonitor.AddPid(ThisPid);
+
+ ZEN_INFO("added process with pid {} as a sponsor process", ThisPid);
+ }
+ }
}
}
+ }
+ return m_ProcessMonitor.IsRunning();
+}
- m_AuthMgr = AuthMgr::Create({.RootDirectory = m_DataRoot / "auth",
- .EncryptionKey = AesKey256Bit::FromString(EncryptionKey),
- .EncryptionIV = AesIV128Bit::FromString(EncryptionIV)});
+void
+ZenServerBase::EnqueueStateExitFlagTimer()
+{
+ ZEN_MEMSCOPE(GetZenserverTag());
+ m_StateExitFlagTimer.expires_after(std::chrono::milliseconds(500));
+ m_StateExitFlagTimer.async_wait([this](const asio::error_code&) { CheckStateExitFlag(); });
+ EnsureIoRunner();
+}
- for (const ZenOpenIdProviderConfig& OpenIdProvider : ServerOptions.AuthConfig.OpenIdProviders)
- {
- m_AuthMgr->AddOpenIdProvider({.Name = OpenIdProvider.Name, .Url = OpenIdProvider.Url, .ClientId = OpenIdProvider.ClientId});
- }
+void
+ZenServerBase::CheckStateExitFlag()
+{
+ if (m_ServerEntry && m_ServerEntry->IsShutdownRequested())
+ {
+ RequestExit(0);
+ return;
}
+ EnqueueStateExitFlagTimer();
+}
- m_AuthService = std::make_unique<HttpAuthService>(*m_AuthMgr);
+void
+ZenServerBase::EnqueueSigIntTimer()
+{
+ ZEN_MEMSCOPE(GetZenserverTag());
+ m_SigIntTimer.expires_after(std::chrono::milliseconds(500));
+ m_SigIntTimer.async_wait([this](const asio::error_code&) { CheckSigInt(); });
+ EnsureIoRunner();
+}
- m_StatsReporter.Initialize(ServerOptions.StatsConfig);
- if (ServerOptions.StatsConfig.Enabled)
+void
+ZenServerBase::CheckSigInt()
+{
+ if (utils::SignalCounter[SIGINT] > 0)
{
- EnqueueStatsReportingTimer();
+ ZEN_INFO("SIGINT triggered (Ctrl+C) for process {}, exiting", zen::GetCurrentProcessId());
+ RequestExit(128 + SIGINT);
+ return;
+ }
+ if (utils::SignalCounter[SIGTERM] > 0)
+ {
+ ZEN_INFO("SIGTERM triggered for process {}, exiting", zen::GetCurrentProcessId());
+ RequestExit(128 + SIGTERM);
+ return;
}
+ EnqueueSigIntTimer();
+}
- m_StatusService.RegisterHandler("status", *this);
+void
+ZenServerBase::HandleStatusRequest(HttpServerRequest& Request)
+{
+ CbObjectWriter Cbo;
+ Cbo << "ok" << true;
+ Cbo << "state" << ToString(m_CurrentState);
+ Request.WriteResponse(HttpResponseCode::OK, Cbo.Save());
+}
- ZEN_INFO("Effective concurrency: {} (hw: {})", GetHardwareConcurrency(), std::thread::hardware_concurrency());
+//////////////////////////////////////////////////////////////////////////
+
+ZenStorageServer::ZenStorageServer()
+{
+}
+
+ZenStorageServer::~ZenStorageServer()
+{
+}
+
+int
+ZenStorageServer::Initialize(const ZenStorageServerOptions& ServerOptions, ZenServerState::ZenServerEntry* ServerEntry)
+{
+ ZEN_TRACE_CPU("ZenStorageServer::Initialize");
+ ZEN_MEMSCOPE(GetZenserverTag());
+
+ const int EffectiveBasePort = ZenServerBase::Initialize(ServerOptions, ServerEntry);
+ if (EffectiveBasePort < 0)
+ {
+ return EffectiveBasePort;
+ }
+
+ m_DebugOptionForcedCrash = ServerOptions.ShouldCrash;
+ m_StartupScrubOptions = ServerOptions.ScrubOptions;
+
+ InitializeState(ServerOptions);
+ InitializeServices(ServerOptions);
+ RegisterServices();
+
+ ZenServerBase::Finalize();
+
+ return EffectiveBasePort;
+}
+
+void
+ZenStorageServer::RegisterServices()
+{
+ m_Http->RegisterService(*m_AuthService);
+ m_Http->RegisterService(m_StatsService);
+ m_Http->RegisterService(m_TestService); // NOTE: this is intentionally not limited to test mode as it's useful for diagnostics
+
+#if ZEN_WITH_TESTS
+ m_Http->RegisterService(m_TestingService);
+#endif
+
+ if (m_StructuredCacheService)
+ {
+ m_Http->RegisterService(*m_StructuredCacheService);
+ }
+
+ if (m_UpstreamService)
+ {
+ m_Http->RegisterService(*m_UpstreamService);
+ }
+
+ if (m_HttpProjectService)
+ {
+ m_Http->RegisterService(*m_HttpProjectService);
+ }
+
+ if (m_HttpWorkspacesService)
+ {
+ m_Http->RegisterService(*m_HttpWorkspacesService);
+ }
- // Initialize storage and services
+ m_FrontendService = std::make_unique<HttpFrontendService>(m_ContentRoot, m_StatusService);
+
+ if (m_FrontendService)
+ {
+ m_Http->RegisterService(*m_FrontendService);
+ }
+
+ if (m_ObjStoreService)
+ {
+ m_Http->RegisterService(*m_ObjStoreService);
+ }
+
+ if (m_BuildStoreService)
+ {
+ m_Http->RegisterService(*m_BuildStoreService);
+ }
+
+#if ZEN_WITH_VFS
+ m_Http->RegisterService(*m_VfsService);
+#endif // ZEN_WITH_VFS
+
+ m_Http->RegisterService(*m_AdminService);
+}
+
+void
+ZenStorageServer::InitializeServices(const ZenStorageServerOptions& ServerOptions)
+{
+ InitializeAuthentication(ServerOptions);
ZEN_INFO("initializing storage");
@@ -258,6 +493,8 @@ ZenServer::Initialize(const ZenServerOptions& ServerOptions, ZenServerState::Zen
ZEN_INFO("instantiating project service");
+ m_JobQueue = MakeJobQueue(8, "bgjobs");
+
m_ProjectStore = new ProjectStore(*m_CidStore, m_DataRoot / "projects", m_GcManager, ProjectStore::Configuration{});
m_HttpProjectService.reset(
new HttpProjectService{*m_CidStore, m_ProjectStore, m_StatusService, m_StatsService, *m_AuthMgr, *m_OpenProcessCache, *m_JobQueue});
@@ -357,74 +594,55 @@ ZenServer::Initialize(const ZenServerOptions& ServerOptions, ZenServerState::Zen
.HttpLogPath = ServerOptions.DataDir / "logs" / "http.log",
.CacheLogPath = ServerOptions.DataDir / "logs" / "z$.log"},
ServerOptions);
+}
- // Register all services when all initialization for all services are done
-
- m_Http->RegisterService(*m_AuthService);
-
- m_Http->RegisterService(m_StatsService);
- m_Http->RegisterService(m_StatusService);
- m_Http->RegisterService(m_TestService); // NOTE: this is intentionally not limited to test mode as it's useful for diagnostics
-
-#if ZEN_WITH_TESTS
- m_Http->RegisterService(m_TestingService);
-#endif
-
- if (m_StructuredCacheService)
+void
+ZenStorageServer::InitializeAuthentication(const ZenStorageServerOptions& ServerOptions)
+{
+ // Setup authentication manager
{
- m_Http->RegisterService(*m_StructuredCacheService);
- }
+ ZEN_TRACE_CPU("ZenStorageServer::InitAuth");
+ std::string EncryptionKey = ServerOptions.EncryptionKey;
- if (m_UpstreamService)
- {
- m_Http->RegisterService(*m_UpstreamService);
- }
+ if (EncryptionKey.empty())
+ {
+ EncryptionKey = "abcdefghijklmnopqrstuvxyz0123456";
- if (m_HttpProjectService)
- {
- m_Http->RegisterService(*m_HttpProjectService);
- }
+ if (ServerOptions.IsDedicated)
+ {
+ ZEN_WARN("Using default encryption key for authentication state");
+ }
+ }
- if (m_HttpWorkspacesService)
- {
- m_Http->RegisterService(*m_HttpWorkspacesService);
- }
+ std::string EncryptionIV = ServerOptions.EncryptionIV;
- m_FrontendService = std::make_unique<HttpFrontendService>(m_ContentRoot, m_StatusService);
+ if (EncryptionIV.empty())
+ {
+ EncryptionIV = "0123456789abcdef";
- if (m_FrontendService)
- {
- m_Http->RegisterService(*m_FrontendService);
- }
+ if (ServerOptions.IsDedicated)
+ {
+ ZEN_WARN("Using default encryption initialization vector for authentication state");
+ }
+ }
- if (m_ObjStoreService)
- {
- m_Http->RegisterService(*m_ObjStoreService);
- }
+ m_AuthMgr = AuthMgr::Create({.RootDirectory = m_DataRoot / "auth",
+ .EncryptionKey = AesKey256Bit::FromString(EncryptionKey),
+ .EncryptionIV = AesIV128Bit::FromString(EncryptionIV)});
- if (m_BuildStoreService)
- {
- m_Http->RegisterService(*m_BuildStoreService);
+ for (const ZenOpenIdProviderConfig& OpenIdProvider : ServerOptions.AuthConfig.OpenIdProviders)
+ {
+ m_AuthMgr->AddOpenIdProvider({.Name = OpenIdProvider.Name, .Url = OpenIdProvider.Url, .ClientId = OpenIdProvider.ClientId});
+ }
}
-#if ZEN_WITH_VFS
- m_Http->RegisterService(*m_VfsService);
-#endif // ZEN_WITH_VFS
-
- m_Http->RegisterService(*m_AdminService);
-
- // Register health service last so if we return "OK" for health it means all services have been properly initialized
- m_Http->RegisterService(m_HealthService);
-
- return EffectiveBasePort;
+ m_AuthService = std::make_unique<HttpAuthService>(*m_AuthMgr);
}
void
-ZenServer::InitializeState(const ZenServerOptions& ServerOptions)
+ZenStorageServer::InitializeState(const ZenStorageServerOptions& ServerOptions)
{
- ZEN_TRACE_CPU("ZenServer::InitializeState");
-
- EnqueueSigIntTimer();
+ ZEN_TRACE_CPU("ZenStorageServer::InitializeState");
// Check root manifest to deal with schema versioning
@@ -586,9 +804,9 @@ ZenServer::InitializeState(const ZenServerOptions& ServerOptions)
}
void
-ZenServer::InitializeStructuredCache(const ZenServerOptions& ServerOptions)
+ZenStorageServer::InitializeStructuredCache(const ZenStorageServerOptions& ServerOptions)
{
- ZEN_TRACE_CPU("ZenServer::InitializeStructuredCache");
+ ZEN_TRACE_CPU("ZenStorageServer::InitializeStructuredCache");
using namespace std::literals;
@@ -718,7 +936,7 @@ ZenServer::InitializeStructuredCache(const ZenServerOptions& ServerOptions)
}
void
-ZenServer::Run()
+ZenStorageServer::Run()
{
if (m_ProcessMonitor.IsActive())
{
@@ -841,21 +1059,9 @@ ZenServer::Run()
}
void
-ZenServer::RequestExit(int ExitCode)
+ZenStorageServer::Cleanup()
{
- if (RequestApplicationExit(ExitCode))
- {
- if (m_Http)
- {
- m_Http->RequestExit();
- }
- }
-}
-
-void
-ZenServer::Cleanup()
-{
- ZEN_TRACE_CPU("ZenServer::Cleanup");
+ ZEN_TRACE_CPU("ZenStorageServer::Cleanup");
ZEN_INFO(ZEN_APP_NAME " cleaning up");
try
{
@@ -869,6 +1075,7 @@ ZenServer::Cleanup()
{
m_Http->Close();
}
+
if (m_JobQueue)
{
m_JobQueue->Stop();
@@ -915,72 +1122,16 @@ ZenServer::Cleanup()
}
void
-ZenServer::EnsureIoRunner()
-{
- ZEN_MEMSCOPE(GetZenserverTag());
- if (!m_IoRunner.joinable())
- {
- m_IoRunner = std::thread{[this] {
- SetCurrentThreadName("timer_io");
- m_IoContext.run();
- }};
- }
-}
-
-void
-ZenServer::EnqueueProcessMonitorTimer()
-{
- ZEN_MEMSCOPE(GetZenserverTag());
- m_PidCheckTimer.expires_after(std::chrono::seconds(1));
- m_PidCheckTimer.async_wait([this](const asio::error_code&) { CheckOwnerPid(); });
-
- EnsureIoRunner();
-}
-
-void
-ZenServer::EnqueueStateMarkerTimer()
-{
- ZEN_MEMSCOPE(GetZenserverTag());
- m_StateMakerTimer.expires_after(std::chrono::seconds(5));
- m_StateMakerTimer.async_wait([this](const asio::error_code&) { CheckStateMarker(); });
- EnsureIoRunner();
-}
-
-void
-ZenServer::EnqueueSigIntTimer()
-{
- ZEN_MEMSCOPE(GetZenserverTag());
- m_SigIntTimer.expires_after(std::chrono::milliseconds(500));
- m_SigIntTimer.async_wait([this](const asio::error_code&) { CheckSigInt(); });
- EnsureIoRunner();
-}
-
-void
-ZenServer::EnqueueStateExitFlagTimer()
-{
- ZEN_MEMSCOPE(GetZenserverTag());
- m_StateExitFlagTimer.expires_after(std::chrono::milliseconds(500));
- m_StateExitFlagTimer.async_wait([this](const asio::error_code&) { CheckStateExitFlag(); });
- EnsureIoRunner();
-}
-
-void
-ZenServer::EnqueueStatsReportingTimer()
+ZenStorageServer::EnqueueStateMarkerTimer()
{
ZEN_MEMSCOPE(GetZenserverTag());
- m_StatsReportingTimer.expires_after(std::chrono::milliseconds(500));
- m_StatsReportingTimer.async_wait([this](const asio::error_code& Ec) {
- if (!Ec)
- {
- m_StatsReporter.ReportStats();
- EnqueueStatsReportingTimer();
- }
- });
+ m_StateMarkerTimer.expires_after(std::chrono::seconds(5));
+ m_StateMarkerTimer.async_wait([this](const asio::error_code&) { CheckStateMarker(); });
EnsureIoRunner();
}
void
-ZenServer::CheckStateMarker()
+ZenStorageServer::CheckStateMarker()
{
ZEN_MEMSCOPE(GetZenserverTag());
std::filesystem::path StateMarkerPath = m_DataRoot / "state_marker";
@@ -1003,89 +1154,9 @@ ZenServer::CheckStateMarker()
}
void
-ZenServer::CheckSigInt()
-{
- if (utils::SignalCounter[SIGINT] > 0)
- {
- ZEN_INFO("SIGINT triggered (Ctrl+C) for process {}, exiting", zen::GetCurrentProcessId());
- RequestExit(128 + SIGINT);
- return;
- }
- if (utils::SignalCounter[SIGTERM] > 0)
- {
- ZEN_INFO("SIGTERM triggered for process {}, exiting", zen::GetCurrentProcessId());
- RequestExit(128 + SIGTERM);
- return;
- }
- EnqueueSigIntTimer();
-}
-
-void
-ZenServer::CheckStateExitFlag()
-{
- if (m_ServerEntry && m_ServerEntry->IsShutdownRequested())
- {
- RequestExit(0);
- return;
- }
- EnqueueStateExitFlagTimer();
-}
-
-bool
-ZenServer::UpdateProcessMonitor()
-{
- // Pick up any new "owner" processes
- std::set<uint32_t> AddedPids;
-
- for (auto& PidEntry : m_ServerEntry->SponsorPids)
- {
- if (uint32_t ThisPid = PidEntry.load(std::memory_order_relaxed))
- {
- if (PidEntry.compare_exchange_strong(ThisPid, 0))
- {
- if (AddedPids.insert(ThisPid).second)
- {
- m_ProcessMonitor.AddPid(ThisPid);
-
- ZEN_INFO("added process with pid {} as a sponsor process", ThisPid);
- }
- }
- }
- }
- return m_ProcessMonitor.IsRunning();
-}
-
-void
-ZenServer::CheckOwnerPid()
-{
- bool IsRunning = UpdateProcessMonitor();
-
- if (IsRunning)
- {
- m_FoundNoActiveSponsors = false;
- EnqueueProcessMonitorTimer();
- }
- else
- {
- // Delay exit one iteration to avoid race conditions where one process detaches
- // and another attaches
- if (m_FoundNoActiveSponsors)
- {
- ZEN_INFO(ZEN_APP_NAME " exiting since sponsor processes are all gone");
- RequestExit(0);
- }
- else
- {
- m_FoundNoActiveSponsors = true;
- EnqueueProcessMonitorTimer();
- }
- }
-}
-
-void
-ZenServer::Flush()
+ZenStorageServer::Flush()
{
- ZEN_TRACE_CPU("ZenServer::Flush");
+ ZEN_TRACE_CPU("ZenStorageServer::Flush");
if (m_CidStore)
m_CidStore->Flush();
@@ -1100,31 +1171,6 @@ ZenServer::Flush()
m_BuildCidStore->Flush();
}
-void
-ZenServer::HandleStatusRequest(HttpServerRequest& Request)
-{
- CbObjectWriter Cbo;
- Cbo << "ok" << true;
- Cbo << "state" << ToString(m_CurrentState);
- Request.WriteResponse(HttpResponseCode::OK, Cbo.Save());
-}
-
-std::string_view
-ZenServer::ToString(ServerState Value)
-{
- switch (Value)
- {
- case kInitializing:
- return "initializing"sv;
- case kRunning:
- return "running"sv;
- case kShuttingDown:
- return "shutdown"sv;
- default:
- return "unknown"sv;
- }
-}
-
#if ZEN_WITH_TESTS
void
diff --git a/src/zenserver/zenserver.h b/src/zenserver/zenserver.h
index ba76c5fff..5447158ab 100644
--- a/src/zenserver/zenserver.h
+++ b/src/zenserver/zenserver.h
@@ -43,84 +43,129 @@ ZEN_THIRD_PARTY_INCLUDES_END
namespace zen {
-struct ZenServerOptions;
+struct ZenStorageServerOptions;
-class ZenServer : public IHttpStatusProvider
+class ZenServerBase : public IHttpStatusProvider
{
- ZenServer& operator=(ZenServer&&) = delete;
- ZenServer(ZenServer&&) = delete;
+ ZenServerBase& operator=(ZenServerBase&&) = delete;
+ ZenServerBase(ZenServerBase&&) = delete;
public:
- ZenServer();
- ~ZenServer();
+ ZenServerBase();
+ ~ZenServerBase();
+ void RequestExit(int ExitCode);
+
+ void SetIsReadyFunc(std::function<void()>&& IsReadyFunc) { m_IsReadyFunc = std::move(IsReadyFunc); }
+
+protected:
int Initialize(const ZenServerOptions& ServerOptions, ZenServerState::ZenServerEntry* ServerEntry);
- void InitializeState(const ZenServerOptions& ServerOptions);
- void InitializeStructuredCache(const ZenServerOptions& ServerOptions);
+ void Finalize();
- void Run();
- void RequestExit(int ExitCode);
- void Cleanup();
+protected:
+ NamedMutex m_ServerMutex;
+ ZenServerState::ZenServerEntry* m_ServerEntry = nullptr;
+ bool m_UseSentry = false;
+ bool m_IsPowerCycle = false;
- void SetDedicatedMode(bool State) { m_IsDedicatedMode = State; }
- void SetTestMode(bool State) { m_TestMode = State; }
- void SetDataRoot(std::filesystem::path Root) { m_DataRoot = Root; }
- void SetContentRoot(std::filesystem::path Root) { m_ContentRoot = Root; }
+ std::thread m_IoRunner;
+ asio::io_context m_IoContext;
+ void EnsureIoRunner();
+
+ enum ServerState
+ {
+ kInitializing,
+ kRunning,
+ kShuttingDown
+ } m_CurrentState = kInitializing;
+
+ inline void SetNewState(ServerState NewState) { m_CurrentState = NewState; }
+ static std::string_view ToString(ServerState Value);
std::function<void()> m_IsReadyFunc;
- void SetIsReadyFunc(std::function<void()>&& IsReadyFunc) { m_IsReadyFunc = std::move(IsReadyFunc); }
void OnReady();
- void EnsureIoRunner();
+ Ref<HttpServer> m_Http;
+ HttpHealthService m_HealthService;
+ HttpStatusService m_StatusService;
+
+ // Stats reporting
+
+ StatsReporter m_StatsReporter;
+ asio::steady_timer m_StatsReportingTimer{m_IoContext};
+ void EnqueueStatsReportingTimer();
+
+ // Process Monitoring
+
+ void CheckOwnerPid();
+ bool UpdateProcessMonitor();
void EnqueueProcessMonitorTimer();
- void EnqueueStateMarkerTimer();
- void EnqueueSigIntTimer();
+
+ ProcessMonitor m_ProcessMonitor;
+ asio::steady_timer m_PidCheckTimer{m_IoContext};
+ bool m_FoundNoActiveSponsors = false;
+
+ // Server state exit signaling
+
+ asio::steady_timer m_StateExitFlagTimer{m_IoContext};
+
void EnqueueStateExitFlagTimer();
- void EnqueueStatsReportingTimer();
- void CheckStateMarker();
- void CheckSigInt();
void CheckStateExitFlag();
- void CheckOwnerPid();
- bool UpdateProcessMonitor();
- void Flush();
+ // SIGINT handling
+
+ void EnqueueSigIntTimer();
+ void CheckSigInt();
+ asio::steady_timer m_SigIntTimer{m_IoContext};
+
+ // IHttpStatusProvider
virtual void HandleStatusRequest(HttpServerRequest& Request) override;
+};
+
+class ZenStorageServer : public ZenServerBase
+{
+ ZenStorageServer& operator=(ZenStorageServer&&) = delete;
+ ZenStorageServer(ZenStorageServer&&) = delete;
+
+public:
+ ZenStorageServer();
+ ~ZenStorageServer();
+
+ void SetDedicatedMode(bool State) { m_IsDedicatedMode = State; }
+ void SetTestMode(bool State) { m_TestMode = State; }
+ void SetDataRoot(std::filesystem::path Root) { m_DataRoot = Root; }
+ void SetContentRoot(std::filesystem::path Root) { m_ContentRoot = Root; }
+
+ int Initialize(const ZenStorageServerOptions& ServerOptions, ZenServerState::ZenServerEntry* ServerEntry);
+ void Run();
+ void Cleanup();
private:
- ZenServerState::ZenServerEntry* m_ServerEntry = nullptr;
- bool m_IsDedicatedMode = false;
- bool m_TestMode = false;
- bool m_IsPowerCycle = false;
- CbObject m_RootManifest;
- std::filesystem::path m_DataRoot;
- std::filesystem::path m_ContentRoot;
- std::thread m_IoRunner;
- asio::io_context m_IoContext;
- asio::steady_timer m_PidCheckTimer{m_IoContext};
- asio::steady_timer m_StateMakerTimer{m_IoContext};
- asio::steady_timer m_StateExitFlagTimer{m_IoContext};
- asio::steady_timer m_SigIntTimer{m_IoContext};
- asio::steady_timer m_StatsReportingTimer{m_IoContext};
- ProcessMonitor m_ProcessMonitor;
- NamedMutex m_ServerMutex;
- bool m_FoundNoActiveSponsors = false;
+ void InitializeState(const ZenStorageServerOptions& ServerOptions);
+ void InitializeStructuredCache(const ZenStorageServerOptions& ServerOptions);
+ void Flush();
- enum ServerState
- {
- kInitializing,
- kRunning,
- kShuttingDown
- } m_CurrentState = kInitializing;
+ bool m_IsDedicatedMode = false;
+ bool m_TestMode = false;
+ bool m_DebugOptionForcedCrash = false;
+ std::string m_StartupScrubOptions;
+ CbObject m_RootManifest;
+ std::filesystem::path m_DataRoot;
+ std::filesystem::path m_ContentRoot;
+ asio::steady_timer m_StateMarkerTimer{m_IoContext};
- inline void SetNewState(ServerState NewState) { m_CurrentState = NewState; }
- static std::string_view ToString(ServerState Value);
+ void EnqueueStateMarkerTimer();
+ void CheckStateMarker();
+
+ std::unique_ptr<AuthMgr> m_AuthMgr;
+ std::unique_ptr<HttpAuthService> m_AuthService;
+ void InitializeAuthentication(const ZenStorageServerOptions& ServerOptions);
+
+ void InitializeServices(const ZenStorageServerOptions& ServerOptions);
+ void RegisterServices();
- StatsReporter m_StatsReporter;
- Ref<HttpServer> m_Http;
- std::unique_ptr<AuthMgr> m_AuthMgr;
- std::unique_ptr<HttpAuthService> m_AuthService;
- HttpStatusService m_StatusService;
HttpStatsService m_StatsService;
+ std::unique_ptr<JobQueue> m_JobQueue;
GcManager m_GcManager;
GcScheduler m_GcScheduler{m_GcManager};
std::unique_ptr<CidStore> m_CidStore;
@@ -133,6 +178,7 @@ private:
#if ZEN_WITH_TESTS
HttpTestingService m_TestingService;
#endif
+
RefPtr<ProjectStore> m_ProjectStore;
std::unique_ptr<VfsServiceImpl> m_VfsServiceImpl;
std::unique_ptr<HttpProjectService> m_HttpProjectService;
@@ -141,18 +187,11 @@ private:
std::unique_ptr<UpstreamCache> m_UpstreamCache;
std::unique_ptr<HttpUpstreamService> m_UpstreamService;
std::unique_ptr<HttpStructuredCacheService> m_StructuredCacheService;
- HttpHealthService m_HealthService;
std::unique_ptr<HttpFrontendService> m_FrontendService;
std::unique_ptr<HttpObjectStoreService> m_ObjStoreService;
std::unique_ptr<HttpBuildStoreService> m_BuildStoreService;
std::unique_ptr<VfsService> m_VfsService;
- std::unique_ptr<JobQueue> m_JobQueue;
std::unique_ptr<HttpAdminService> m_AdminService;
-
- bool m_DebugOptionForcedCrash = false;
- bool m_UseSentry = false;
-
- std::string m_StartupScrubOptions;
};
void zenserver_forcelinktests();