aboutsummaryrefslogtreecommitdiff
path: root/zenserver/zenserver.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2021-10-29 19:21:33 +0200
committerStefan Boberg <[email protected]>2021-10-29 19:21:41 +0200
commit73a5bec027b5879a9870b156d85343c8a018fe1e (patch)
tree2be926bb314bc95bcf950b05a699c2cc96a79243 /zenserver/zenserver.cpp
parentcas: minor improvement to CasLogFile::Open error handling (diff)
parentMinor cleanup (diff)
downloadzen-73a5bec027b5879a9870b156d85343c8a018fe1e.tar.xz
zen-73a5bec027b5879a9870b156d85343c8a018fe1e.zip
Merged from main
Diffstat (limited to 'zenserver/zenserver.cpp')
-rw-r--r--zenserver/zenserver.cpp152
1 files changed, 139 insertions, 13 deletions
diff --git a/zenserver/zenserver.cpp b/zenserver/zenserver.cpp
index 542ad6dd2..33cec7db1 100644
--- a/zenserver/zenserver.cpp
+++ b/zenserver/zenserver.cpp
@@ -8,11 +8,13 @@
#include <zencore/logging.h>
#include <zencore/refcount.h>
#include <zencore/scopeguard.h>
+#include <zencore/session.h>
#include <zencore/string.h>
#include <zencore/thread.h>
#include <zencore/timer.h>
#include <zencore/windows.h>
#include <zenhttp/httpserver.h>
+#include <zenstore/basicfile.h>
#include <zenstore/cas.h>
#include <zenstore/cidstore.h>
#include <zenutil/zenserverprocess.h>
@@ -118,6 +120,37 @@ namespace zen {
using namespace std::literals;
using namespace fmt::literals;
+namespace utils {
+ asio::error_code ResolveHostname(asio::io_context& Ctx,
+ std::string_view Host,
+ std::string_view DefaultPort,
+ std::vector<std::string>& OutEndpoints)
+ {
+ std::string_view Port = DefaultPort;
+
+ if (const size_t Idx = Host.find(":"); Idx != std::string_view::npos)
+ {
+ Port = Host.substr(Idx + 1);
+ Host = Host.substr(0, Idx);
+ }
+
+ asio::ip::tcp::resolver Resolver(Ctx);
+
+ asio::error_code ErrorCode;
+ asio::ip::tcp::resolver::results_type Endpoints = Resolver.resolve(Host, Port, ErrorCode);
+
+ if (!ErrorCode)
+ {
+ for (const asio::ip::tcp::endpoint& Ep : Endpoints)
+ {
+ OutEndpoints.push_back("http://{}:{}"_format(Ep.address().to_string(), Ep.port()));
+ }
+ }
+
+ return ErrorCode;
+ }
+} // namespace utils
+
class ZenServer : public IHttpStatusProvider
{
public:
@@ -305,11 +338,13 @@ public:
const bool IsInteractiveMode = zen::IsInteractiveSession() && !m_TestMode;
- m_CurrentState = kRunning;
+ SetNewState(kRunning);
+
+ OnReady();
m_Http->Run(IsInteractiveMode);
- m_CurrentState = kShuttingDown;
+ SetNewState(kShuttingDown);
ZEN_INFO(ZEN_APP_NAME " exiting");
@@ -331,6 +366,10 @@ public:
void SetDataRoot(std::filesystem::path Root) { m_DataRoot = Root; }
void SetContentRoot(std::filesystem::path Root) { m_ContentRoot = Root; }
+ std::function<void()> m_IsReadyFunc;
+ void SetIsReadyFunc(std::function<void()>&& IsReadyFunc) { m_IsReadyFunc = std::move(IsReadyFunc); }
+ void OnReady();
+
void EnsureIoRunner()
{
if (!m_IoRunner.joinable())
@@ -454,6 +493,8 @@ private:
kShuttingDown
} m_CurrentState = kInitializing;
+ inline void SetNewState(ServerState NewState) { m_CurrentState = NewState; }
+
std::string_view ToString(ServerState Value)
{
switch (Value)
@@ -501,6 +542,17 @@ private:
};
void
+ZenServer::OnReady()
+{
+ m_ServerEntry->SignalReady();
+
+ if (m_IsReadyFunc)
+ {
+ m_IsReadyFunc();
+ }
+}
+
+void
ZenServer::InitializeState(ZenServiceConfig& ServiceConfig)
{
// Check root manifest to deal with schema versioning
@@ -621,12 +673,29 @@ ZenServer::InitializeStructuredCache(ZenServiceConfig& ServiceConfig)
UpstreamCache = zen::MakeUpstreamCache(UpstreamOptions, *m_CacheStore, *m_CidStore);
- if (!UpstreamConfig.ZenConfig.Urls.empty())
+ // Zen upstream
{
- std::unique_ptr<zen::UpstreamEndpoint> ZenEndpoint = zen::MakeZenUpstreamEndpoint(UpstreamConfig.ZenConfig.Urls);
- UpstreamCache->RegisterEndpoint(std::move(ZenEndpoint));
+ std::vector<std::string> ZenUrls = UpstreamConfig.ZenConfig.Urls;
+ if (!UpstreamConfig.ZenConfig.Dns.empty())
+ {
+ for (const std::string& Dns : UpstreamConfig.ZenConfig.Dns)
+ {
+ const asio::error_code Err = zen::utils::ResolveHostname(m_IoContext, Dns, "1337"sv, ZenUrls);
+ if (Err)
+ {
+ ZEN_ERROR("resolve '{}' FAILED, reason '{}'", Err.message());
+ }
+ }
+ }
+
+ if (!ZenUrls.empty())
+ {
+ std::unique_ptr<zen::UpstreamEndpoint> ZenEndpoint = zen::MakeZenUpstreamEndpoint(ZenUrls);
+ UpstreamCache->RegisterEndpoint(std::move(ZenEndpoint));
+ }
}
+ // Jupiter upstream
{
zen::CloudCacheClientOptions Options;
if (UpstreamConfig.JupiterConfig.UseProductionSettings)
@@ -703,6 +772,7 @@ public:
private:
ZenServerOptions& m_GlobalOptions;
ZenServiceConfig& m_ServiceConfig;
+ zen::LockFile m_LockFile;
};
int
@@ -725,6 +795,32 @@ ZenWindowsService::Run()
try
{
+ // Mutual exclusion and synchronization
+
+ std::error_code Ec;
+
+ std::filesystem::path LockFilePath = GlobalOptions.DataDir / ".lock";
+
+ bool IsReady = false;
+
+ auto MakeLockData = [&] {
+ CbObjectWriter Cbo;
+ Cbo << "pid" << _getpid() << "data" << ToUtf8(GlobalOptions.DataDir) << "port" << GlobalOptions.BasePort << "session_id"
+ << GetSessionId() << "ready" << IsReady;
+ return Cbo.Save();
+ };
+
+ m_LockFile.Create(LockFilePath, MakeLockData(), Ec);
+
+ if (Ec)
+ {
+ ConsoleLog().error("ERROR: Unable to grab lock at '{}' (error: '{}')", LockFilePath, Ec.message());
+
+ std::exit(99);
+ }
+
+ InitializeLogging(GlobalOptions);
+
// Prototype config system, we'll see how this pans out
//
// TODO: we need to report any parse errors here
@@ -786,13 +882,19 @@ ZenWindowsService::Run()
}});
// If we have a parent process, establish the mechanisms we need
- // to be able to communicate with the parent
+ // to be able to communicate readiness with the parent
- if (!GlobalOptions.ChildId.empty())
- {
- zen::NamedEvent ParentEvent{GlobalOptions.ChildId};
- ParentEvent.Set();
- }
+ Server.SetIsReadyFunc([&] {
+ IsReady = true;
+
+ m_LockFile.Update(MakeLockData(), Ec);
+
+ if (!GlobalOptions.ChildId.empty())
+ {
+ zen::NamedEvent ParentEvent{GlobalOptions.ChildId};
+ ParentEvent.Set();
+ }
+ });
Server.Run();
Server.Cleanup();
@@ -810,6 +912,22 @@ ZenWindowsService::Run()
return 0;
}
+#if ZEN_WITH_TESTS
+int
+test_main(int argc, char** argv)
+{
+ zen::zencore_forcelinktests();
+ zen::zenhttp_forcelinktests();
+ zen::zenstore_forcelinktests();
+
+ zen::logging::InitializeLogging();
+
+ spdlog::set_level(spdlog::level::debug);
+
+ return doctest::Context(argc, argv).run();
+}
+#endif
+
int
main(int argc, char* argv[])
{
@@ -819,6 +937,16 @@ main(int argc, char* argv[])
mi_version();
#endif
+#if ZEN_WITH_TESTS
+ if (argc >= 2)
+ {
+ if (argv[1] == "test"sv)
+ {
+ return test_main(argc, argv);
+ }
+ }
+#endif
+
try
{
ZenServerOptions GlobalOptions;
@@ -831,8 +959,6 @@ main(int argc, char* argv[])
std::filesystem::create_directories(GlobalOptions.DataDir);
}
- InitializeLogging(GlobalOptions);
-
#if ZEN_PLATFORM_WINDOWS
if (GlobalOptions.InstallService)
{