diff options
| author | Stefan Boberg <[email protected]> | 2025-10-13 13:42:25 +0200 |
|---|---|---|
| committer | GitHub Enterprise <[email protected]> | 2025-10-13 13:42:25 +0200 |
| commit | e5a05c01ba5f1b9517108fe95d54b4066190d66d (patch) | |
| tree | 591d18ecf12753104ee05f868c1155b0a7941e4a /src/zenserver/main.cpp | |
| parent | refactor builds cmd (#566) (diff) | |
| download | zen-e5a05c01ba5f1b9517108fe95d54b4066190d66d.tar.xz zen-e5a05c01ba5f1b9517108fe95d54b4066190d66d.zip | |
extract storage server into separate source files (#569)
this change moves common base service code into `zenserver.(cpp|h)` and storage server code into `zenstorageserver.(cpp|h)` to more clearly separate concerns but also to make way for another service
Diffstat (limited to 'src/zenserver/main.cpp')
| -rw-r--r-- | src/zenserver/main.cpp | 347 |
1 files changed, 5 insertions, 342 deletions
diff --git a/src/zenserver/main.cpp b/src/zenserver/main.cpp index 0dc390797..f1c1a9394 100644 --- a/src/zenserver/main.cpp +++ b/src/zenserver/main.cpp @@ -1,6 +1,6 @@ // Copyright Epic Games, Inc. All Rights Reserved. -#include "zenserver.h" +#include "zenstorageserver.h" #include <zencore/compactbinarybuilder.h> #include <zencore/compactbinaryvalidation.h> @@ -59,342 +59,13 @@ SignalCallbackHandler(int SigNum) namespace zen { -static const FLLMTag& -GetZenserverTag() -{ - static FLLMTag _("zenserver"); - - return _; -} - using namespace std::literals; -//////////////////////////////////////////////////////////////////////////////// - -class ZenServerMain -{ -public: - ZenServerMain(ZenServerOptions& ServerOptions); - ~ZenServerMain(); - - 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()}); - }; -}; - -ZenServerMain::ZenServerMain(ZenServerOptions& ServerOptions) : m_ServerOptions(ServerOptions) -{ -} - -ZenServerMain::~ZenServerMain() -{ -} - -int -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 - // there. So we don't name the main thread explicitly there. - -#ifndef ZEN_PLATFORM_LINUX - zen::SetCurrentThreadName("main"); -#endif - -#if ZEN_USE_SENTRY - SentryIntegration Sentry; - - if (m_ServerOptions.SentryConfig.Disable == false) - { - std::string SentryDatabasePath = (m_ServerOptions.DataDir / ".sentry-native").string(); - std::string SentryAttachmentPath = m_ServerOptions.AbsLogFile.string(); - - Sentry.Initialize({.DatabasePath = SentryDatabasePath, - .AttachmentsPath = SentryAttachmentPath, - .Dsn = m_ServerOptions.SentryConfig.Dsn, - .Environment = m_ServerOptions.SentryConfig.Environment, - .AllowPII = m_ServerOptions.SentryConfig.AllowPII, - .Debug = m_ServerOptions.SentryConfig.Debug}, - m_ServerOptions.CommandLine); - } -#endif - - try - { - // Mutual exclusion and synchronization - ZenServerState ServerState; - ServerState.Initialize(); - ServerState.Sweep(); - - uint32_t AttachSponsorProcessRetriesLeft = 3; - ZenServerState::ZenServerEntry* Entry = ServerState.Lookup(m_ServerOptions.BasePort); - while (Entry) - { - if (m_ServerOptions.OwnerPid) - { - std::error_code Ec; - if (!IsProcessRunning(m_ServerOptions.OwnerPid, Ec)) - { - if (Ec) - { - ZEN_WARN(ZEN_APP_NAME - " exiting, sponsor owner pid {} can not be checked for running state, reason: '{}'. Will not add sponsor " - "to process " - "listening to port {} (pid: {})", - m_ServerOptions.OwnerPid, - Ec.message(), - m_ServerOptions.BasePort, - Entry->Pid.load()); - } - else - { - ZEN_WARN(ZEN_APP_NAME - " exiting, sponsor owner pid {} is no longer running, will not add sponsor to process listening to port " - "{} (pid: {})", - m_ServerOptions.OwnerPid, - m_ServerOptions.BasePort, - Entry->Pid.load()); - } - std::exit(1); - } - ZEN_INFO( - "Looks like there is already a process listening to this port {} (pid: {}), attaching owner pid {} to running instance", - m_ServerOptions.BasePort, - Entry->Pid.load(), - m_ServerOptions.OwnerPid); - - // Sponsor processes are checked every second, so 2 second wait time should be enough - if (Entry->AddSponsorProcess(m_ServerOptions.OwnerPid, 2000)) - { - NotifyReady(); - std::exit(0); - } - if (AttachSponsorProcessRetriesLeft-- > 0) - { - Entry = ServerState.Lookup(m_ServerOptions.BasePort); - } - else - { - ZEN_WARN(ZEN_APP_NAME " exiting, failed to add sponsor owner pid {} to process listening to port {} (pid: {})", - m_ServerOptions.OwnerPid, - m_ServerOptions.BasePort, - Entry->Pid.load()); - std::exit(1); - } - } - else - { - ZEN_WARN(ZEN_APP_NAME " exiting, there is already a process listening to port {} (pid: {})", - m_ServerOptions.BasePort, - Entry->Pid.load()); - std::exit(1); - } - } - - std::error_code Ec; - - std::filesystem::path LockFilePath = m_ServerOptions.DataDir / ".lock"; - - m_LockFile.Create(LockFilePath, MakeLockData(false), Ec); - - if (Ec) - { - ZEN_INFO(ZEN_APP_NAME " unable to grab lock at '{}' (reason: '{}'), retrying", LockFilePath, Ec.message()); - Sleep(100); - - m_LockFile.Create(LockFilePath, MakeLockData(false), Ec); - if (Ec) - { - ZEN_INFO(ZEN_APP_NAME " unable to grab lock at '{}' (reason: '{}'), retrying", LockFilePath, Ec.message()); - Sleep(500); - if (Ec) - { - ZEN_WARN(ZEN_APP_NAME " exiting, unable to grab lock at '{}' (reason: '{}')", LockFilePath, Ec.message()); - std::exit(99); - } - } - } - - InitializeServerLogging(m_ServerOptions); - - ZEN_INFO("Command line: {}", m_ServerOptions.CommandLine); - -#if ZEN_USE_SENTRY - Sentry.LogStartupInformation(); -#endif - - MaximizeOpenFileCount(); - - ZEN_INFO(ZEN_APP_NAME " - using lock file at '{}'", LockFilePath); - - ZEN_INFO(ZEN_APP_NAME " - starting on port {}, version '{}'", m_ServerOptions.BasePort, ZEN_CFG_VERSION_BUILD_STRING_FULL); - - Entry = ServerState.Register(m_ServerOptions.BasePort); - - if (m_ServerOptions.OwnerPid) - { - // We are adding a sponsor process to our own entry, can't wait for pick since the code is not run until later - Entry->AddSponsorProcess(m_ServerOptions.OwnerPid, 0); - } - - // Run the actual application logic - - DoRun(Entry); - } - catch (const AssertException& AssertEx) - { - ZEN_CRITICAL(ZEN_APP_NAME " caught assert exception in main for process {}: {}", - zen::GetCurrentProcessId(), - AssertEx.FullDescription()); - RequestApplicationExit(1); - } - catch (const std::system_error& e) - { - ZEN_CRITICAL(ZEN_APP_NAME " caught system error exception in main for process {}: {} ({})", - zen::GetCurrentProcessId(), - e.what(), - e.code().value()); - RequestApplicationExit(1); - } - catch (const std::exception& e) - { - ZEN_CRITICAL(ZEN_APP_NAME " caught exception in main for process {}: {}", zen::GetCurrentProcessId(), e.what()); - RequestApplicationExit(1); - } - - ShutdownServerLogging(); - - ReportServiceStatus(ServiceStatus::Stopped); - - return ApplicationExitCode(); -} - -////////////////////////////////////////////////////////////////////////// -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 +template<class T> class ZenWindowsService : public WindowsService { public: @@ -403,18 +74,12 @@ public: ZenWindowsService(const ZenWindowsService&) = delete; ZenWindowsService& operator=(const ZenWindowsService&) = delete; - virtual int Run() override; + virtual int Run() override { return m_EntryPoint.Run(); } private: - ZenStorageServerMain m_EntryPoint; + T m_EntryPoint; }; -int -ZenWindowsService::Run() -{ - return m_EntryPoint.Run(); -} - #endif // ZEN_PLATFORM_WINDOWS } // namespace zen @@ -425,8 +90,6 @@ ZenWindowsService::Run() int test_main(int argc, char** argv) { - zen::zenserver_forcelinktests(); - zen::logging::InitializeLogging(); zen::logging::SetLogLevel(zen::logging::level::Debug); @@ -537,7 +200,7 @@ main(int argc, char* argv[]) std::exit(0); } - ZenWindowsService App(ServerOptions); + ZenWindowsService<ZenStorageServerMain> App(ServerOptions); return App.ServiceMain(); #else if (ServerOptions.InstallService || ServerOptions.UninstallService) |