diff options
| author | Stefan Boberg <[email protected]> | 2026-01-19 14:46:42 +0100 |
|---|---|---|
| committer | GitHub Enterprise <[email protected]> | 2026-01-19 14:46:42 +0100 |
| commit | 155271b7e541705bab782c0b75ed09050a56fcf8 (patch) | |
| tree | daff96788a7dda7dbc9adbb68a5daae2f2fc0af4 /src/zenutil | |
| parent | remove ZENCORE_API completely (#718) (diff) | |
| download | zen-155271b7e541705bab782c0b75ed09050a56fcf8.tar.xz zen-155271b7e541705bab782c0b75ed09050a56fcf8.zip | |
ZenServerProcess API changes (#719)
This refactor aims to improve the `ZenServerProcess` classes by making them useful for managing child zenserver instances in more scenarios than just automated tests. This involves changing some functions to not talk about "test directory" and instead use "data directory" etc
As a consequence of the API changes, some tests have changed accordingly.
The code includes som reference to the "hub" mode but there is not yet any other code using this mode, it's just included in this PR to simplify future merges.
Diffstat (limited to 'src/zenutil')
| -rw-r--r-- | src/zenutil/include/zenutil/zenserverprocess.h | 35 | ||||
| -rw-r--r-- | src/zenutil/zenserverprocess.cpp | 118 |
2 files changed, 133 insertions, 20 deletions
diff --git a/src/zenutil/include/zenutil/zenserverprocess.h b/src/zenutil/include/zenutil/zenserverprocess.h index 0da63285b..d0402640b 100644 --- a/src/zenutil/include/zenutil/zenserverprocess.h +++ b/src/zenutil/include/zenutil/zenserverprocess.h @@ -34,8 +34,10 @@ public: void Initialize(std::filesystem::path ProgramBaseDir); void InitializeForTest(std::filesystem::path ProgramBaseDir, std::filesystem::path TestBaseDir, std::string_view ServerClass = ""); + void InitializeForHub(std::filesystem::path ProgramBaseDir, std::filesystem::path TestBaseDir, std::string_view ServerClass = ""); std::filesystem::path CreateNewTestDir(); + std::filesystem::path CreateChildDir(std::string_view ChildName); std::filesystem::path ProgramBaseDir() const { return m_ProgramBaseDir; } std::filesystem::path GetTestRootDir(std::string_view Path); inline bool IsInitialized() const { return m_IsInitialized; } @@ -43,11 +45,18 @@ public: inline std::string_view GetServerClass() const { return m_ServerClass; } inline uint16_t GetNewPortNumber() { return m_NextPortNumber.fetch_add(1); } + // The defaults will work for a single root process only. For hierarchical + // setups (e.g., hub managing storage servers), we need to be able to + // allocate distinct child IDs and ports to avoid overlap/conflicts. + static void SetBaseChildId(int InitialValue); + void SetNextPortNumber(uint16_t NewValue) { m_NextPortNumber = NewValue; } + private: std::filesystem::path m_ProgramBaseDir; - std::filesystem::path m_TestBaseDir; + std::filesystem::path m_ChildProcessBaseDir; bool m_IsInitialized = false; bool m_IsTestInstance = false; + bool m_IsHubInstance = false; std::string m_ServerClass; std::atomic_uint16_t m_NextPortNumber{20000}; }; @@ -60,10 +69,19 @@ private: Especially useful for automated testing but can also be used for management tools. + This is also used by zenserver in hub mode, for managing storage + server instances. + */ struct ZenServerInstance { - ZenServerInstance(ZenServerEnvironment& TestEnvironment); + enum class ServerMode + { + kStorageServer, // default + kHubServer, + }; + + ZenServerInstance(ZenServerEnvironment& TestEnvironment, ServerMode Mode = ServerMode::kStorageServer); ~ZenServerInstance(); int Shutdown(); @@ -72,6 +90,7 @@ struct ZenServerInstance [[nodiscard]] bool WaitUntilReady(int Timeout); [[nodiscard]] bool WaitUntilExited(int Timeout, std::error_code& OutEc); void EnableTermination() { m_Terminate = true; } + void EnableShutdownOnDestroy() { m_ShutdownOnDestroy = true; } void DisableShutdownOnDestroy() { m_ShutdownOnDestroy = false; } void Detach(); inline int GetPid() const { return m_Process.Pid(); } @@ -81,7 +100,11 @@ struct ZenServerInstance bool Terminate(); std::string GetLogOutput() const; - void SetTestDir(std::filesystem::path TestDir); + inline ServerMode GetServerMode() const { return m_ServerMode; } + + inline void SetServerExecutablePath(std::filesystem::path ExecutablePath) { m_ServerExecutablePath = ExecutablePath; } + + void SetDataDir(std::filesystem::path TestDir); inline void SpawnServer(std::string_view AdditionalServerArgs = std::string_view()) { @@ -117,11 +140,13 @@ private: std::unique_ptr<NamedEvent> m_ShutdownEvent; bool m_Terminate = false; bool m_ShutdownOnDestroy = true; - std::filesystem::path m_TestDir; - uint16_t m_BasePort = 0; + std::filesystem::path m_DataDir; + uint16_t m_BasePort = 0; + ServerMode m_ServerMode = ServerMode::kStorageServer; std::optional<int> m_OwnerPid; std::string m_Name; std::filesystem::path m_OutputCapturePath; + std::filesystem::path m_ServerExecutablePath; void CreateShutdownEvent(int BasePort); void SpawnServer(int BasePort, std::string_view AdditionalServerArgs, int WaitTimeoutMs); diff --git a/src/zenutil/zenserverprocess.cpp b/src/zenutil/zenserverprocess.cpp index 6a93f0c63..b56df400d 100644 --- a/src/zenutil/zenserverprocess.cpp +++ b/src/zenutil/zenserverprocess.cpp @@ -31,6 +31,19 @@ namespace zen { +// this needs to key off the current process child-id, in order to avoid conflicts +// in situations where we have a tree of zenserver child processes (such as in hub +// tests) + +std::atomic<int> ChildIdCounter{0}; + +void +ZenServerEnvironment::SetBaseChildId(int InitialValue) +{ + ZEN_ASSERT(ChildIdCounter == 0); + ChildIdCounter = InitialValue; +} + namespace zenutil { #if ZEN_PLATFORM_WINDOWS class SecurityAttributes @@ -507,8 +520,8 @@ ZenServerEnvironment::InitializeForTest(std::filesystem::path ProgramBaseDir, { using namespace std::literals; - m_ProgramBaseDir = ProgramBaseDir; - m_TestBaseDir = TestBaseDir; + m_ProgramBaseDir = ProgramBaseDir; + m_ChildProcessBaseDir = TestBaseDir; ZEN_INFO("Program base dir is '{}'", ProgramBaseDir); ZEN_INFO("Cleaning test base dir '{}'", TestBaseDir); @@ -536,6 +549,59 @@ ZenServerEnvironment::InitializeForTest(std::filesystem::path ProgramBaseDir, } } +void +ZenServerEnvironment::InitializeForHub(std::filesystem::path ProgramBaseDir, + std::filesystem::path ChildBaseDir, + std::string_view ServerClass) +{ + using namespace std::literals; + + m_ProgramBaseDir = ProgramBaseDir; + m_ChildProcessBaseDir = ChildBaseDir; + + ZEN_INFO("Program base dir is '{}'", m_ProgramBaseDir); + ZEN_INFO("Cleaning child base dir '{}'", m_ChildProcessBaseDir); + DeleteDirectories(m_ChildProcessBaseDir.c_str()); + + m_IsHubInstance = true; + m_IsInitialized = true; + + if (ServerClass.empty()) + { +#if ZEN_WITH_HTTPSYS + if (!zen::windows::IsRunningOnWine()) + { + m_ServerClass = "httpsys"sv; + + return; + } +#endif + + m_ServerClass = "asio"sv; + } + else + { + m_ServerClass = ServerClass; + } +} + +std::filesystem::path +ZenServerEnvironment::CreateChildDir(std::string_view ChildName) +{ + using namespace std::literals; + + std::filesystem::path ChildPath = m_ChildProcessBaseDir / ChildName; + + if (!IsDir(ChildPath)) + { + ZEN_INFO("Creating new test dir @ '{}'", ChildPath); + + CreateDirectories(ChildPath); + } + + return ChildPath; +} + std::filesystem::path ZenServerEnvironment::CreateNewTestDir() { @@ -544,7 +610,7 @@ ZenServerEnvironment::CreateNewTestDir() ExtendableWideStringBuilder<256> TestDir; TestDir << "test"sv << int64_t(ZenServerTestCounter.fetch_add(1)); - std::filesystem::path TestPath = m_TestBaseDir / TestDir.c_str(); + std::filesystem::path TestPath = m_ChildProcessBaseDir / TestDir.c_str(); ZEN_ASSERT(!IsDir(TestPath)); ZEN_INFO("Creating new test dir @ '{}'", TestPath); @@ -566,11 +632,11 @@ ZenServerEnvironment::GetTestRootDir(std::string_view Path) ////////////////////////////////////////////////////////////////////////// -std::atomic<int> ChildIdCounter{0}; - -ZenServerInstance::ZenServerInstance(ZenServerEnvironment& TestEnvironment) : m_Env(TestEnvironment) +ZenServerInstance::ZenServerInstance(ZenServerEnvironment& TestEnvironment, ServerMode Mode) : m_Env(TestEnvironment), m_ServerMode(Mode) { ZEN_ASSERT(TestEnvironment.IsInitialized()); + + m_ServerMode = Mode; } ZenServerInstance::~ZenServerInstance() @@ -710,6 +776,22 @@ ZenServerInstance::SpawnServer(std::string_view ServerArgs, bool OpenConsole, in SpawnServerInternal(ChildId, ServerArgs, OpenConsole, WaitTimeoutMs); } +std::string_view +ToString(ZenServerInstance::ServerMode Mode) +{ + using namespace std::literals; + + switch (Mode) + { + case ZenServerInstance::ServerMode::kStorageServer: + return "storage"sv; + case ZenServerInstance::ServerMode::kHubServer: + return "hub"sv; + default: + return "invalid"sv; + } +} + void ZenServerInstance::SpawnServerInternal(int ChildId, std::string_view ServerArgs, bool OpenConsole, int WaitTimeoutMs) { @@ -721,6 +803,12 @@ ZenServerInstance::SpawnServerInternal(int ChildId, std::string_view ServerArgs, ExtendableStringBuilder<512> CommandLine; CommandLine << "zenserver" ZEN_EXE_SUFFIX_LITERAL; // see CreateProc() call for actual binary path + + if (m_ServerMode == ServerMode::kHubServer) + { + CommandLine << " hub"; + } + CommandLine << " --child-id " << ChildEventName; if (!ServerArgs.empty()) @@ -730,7 +818,7 @@ ZenServerInstance::SpawnServerInternal(int ChildId, std::string_view ServerArgs, std::filesystem::path CurrentDirectory = std::filesystem::current_path(); - ZEN_DEBUG("Spawning server '{}'", m_Name); + ZEN_DEBUG("Spawning {} server '{}'", ToString(m_ServerMode), m_Name); uint32_t CreationFlags = 0; if (OpenConsole) @@ -738,8 +826,9 @@ ZenServerInstance::SpawnServerInternal(int ChildId, std::string_view ServerArgs, CreationFlags |= CreateProcOptions::Flag_NewConsole; } - const std::filesystem::path BaseDir = m_Env.ProgramBaseDir(); - const std::filesystem::path Executable = BaseDir / "zenserver" ZEN_EXE_SUFFIX_LITERAL; + const std::filesystem::path BaseDir = m_Env.ProgramBaseDir(); + const std::filesystem::path Executable = + m_ServerExecutablePath.empty() ? (BaseDir / "zenserver" ZEN_EXE_SUFFIX_LITERAL) : m_ServerExecutablePath; const std::filesystem::path OutputPath = OpenConsole ? std::filesystem::path{} : std::filesystem::temp_directory_path() / ("zenserver_" + m_Name + ".log"); CreateProcOptions CreateOptions = {.WorkingDirectory = &CurrentDirectory, .Flags = CreationFlags, .StdoutFile = OutputPath}; @@ -799,8 +888,7 @@ ZenServerInstance::SpawnServer(int BasePort, std::string_view AdditionalServerAr const int ChildId = AssignName(); ExtendableStringBuilder<512> CommandLine; - - const bool IsTest = m_Env.IsTestEnvironment(); + const bool IsTest = m_Env.IsTestEnvironment(); if (IsTest) { @@ -835,10 +923,10 @@ ZenServerInstance::SpawnServer(int BasePort, std::string_view AdditionalServerAr m_BasePort = gsl::narrow_cast<uint16_t>(BasePort); } - if (!m_TestDir.empty()) + if (!m_DataDir.empty()) { CommandLine << " --data-dir "; - PathToUtf8(m_TestDir.c_str(), CommandLine); + PathToUtf8(m_DataDir.c_str(), CommandLine); } if (!AdditionalServerArgs.empty()) @@ -1028,10 +1116,10 @@ ZenServerInstance::GetBaseUri() const } void -ZenServerInstance::SetTestDir(std::filesystem::path TestDir) +ZenServerInstance::SetDataDir(std::filesystem::path TestDir) { ZEN_ASSERT(!m_Process.IsValid()); - m_TestDir = TestDir; + m_DataDir = TestDir; } bool |