diff options
| author | Stefan Boberg <[email protected]> | 2021-10-29 19:21:33 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2021-10-29 19:21:41 +0200 |
| commit | 73a5bec027b5879a9870b156d85343c8a018fe1e (patch) | |
| tree | 2be926bb314bc95bcf950b05a699c2cc96a79243 /zenserver | |
| parent | cas: minor improvement to CasLogFile::Open error handling (diff) | |
| parent | Minor cleanup (diff) | |
| download | zen-73a5bec027b5879a9870b156d85343c8a018fe1e.tar.xz zen-73a5bec027b5879a9870b156d85343c8a018fe1e.zip | |
Merged from main
Diffstat (limited to 'zenserver')
| -rw-r--r-- | zenserver/cache/cacheagent.cpp | 5 | ||||
| -rw-r--r-- | zenserver/cache/cacheagent.h | 9 | ||||
| -rw-r--r-- | zenserver/cache/structuredcachestore.cpp | 68 | ||||
| -rw-r--r-- | zenserver/cache/structuredcachestore.h | 4 | ||||
| -rw-r--r-- | zenserver/config.cpp | 7 | ||||
| -rw-r--r-- | zenserver/config.h | 1 | ||||
| -rw-r--r-- | zenserver/zenserver.cpp | 152 | ||||
| -rw-r--r-- | zenserver/zenserver.vcxproj | 2 | ||||
| -rw-r--r-- | zenserver/zenserver.vcxproj.filters | 6 |
9 files changed, 217 insertions, 37 deletions
diff --git a/zenserver/cache/cacheagent.cpp b/zenserver/cache/cacheagent.cpp deleted file mode 100644 index f4d1cabe6..000000000 --- a/zenserver/cache/cacheagent.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include "cacheagent.h" - -#include <gsl/gsl-lite.hpp> diff --git a/zenserver/cache/cacheagent.h b/zenserver/cache/cacheagent.h deleted file mode 100644 index 145d0f79f..000000000 --- a/zenserver/cache/cacheagent.h +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#pragma once - -class CacheAgent -{ -public: -private: -}; diff --git a/zenserver/cache/structuredcachestore.cpp b/zenserver/cache/structuredcachestore.cpp index f964c3102..b120f3955 100644 --- a/zenserver/cache/structuredcachestore.cpp +++ b/zenserver/cache/structuredcachestore.cpp @@ -6,21 +6,28 @@ #include <zencore/windows.h> #include <zencore/compactbinary.h> +#include <zencore/compactbinarybuilder.h> +#include <zencore/compactbinarypackage.h> #include <zencore/compactbinaryvalidation.h> +#include <zencore/compress.h> #include <zencore/filesystem.h> #include <zencore/fmtutils.h> #include <zencore/iobuffer.h> #include <zencore/logging.h> #include <zencore/string.h> +#include <zencore/testing.h> +#include <zencore/testutils.h> #include <zencore/thread.h> #include <zenstore/basicfile.h> #include <zenstore/cas.h> #include <zenstore/caslog.h> +#include <zenstore/cidstore.h> #include <zenstore/gc.h> #include <concepts> #include <filesystem> #include <memory_resource> +#include <ranges> #include <unordered_map> ZEN_THIRD_PARTY_INCLUDES_START @@ -236,7 +243,12 @@ ZenCacheMemoryLayer::Scrub(ScrubContext& Ctx) void ZenCacheMemoryLayer::GatherReferences(GcContext& GcCtx) { - ZEN_UNUSED(GcCtx); + RwLock::SharedLockScope _(m_Lock); + + for (auto& Kv : m_Buckets) + { + Kv.second.GatherReferences(GcCtx); + } } void @@ -1079,4 +1091,58 @@ ZenCacheDiskLayer::GatherReferences(GcContext& GcCtx) } } +////////////////////////////////////////////////////////////////////////// + +#if ZEN_WITH_TESTS + +TEST_CASE("z$.store") +{ + using namespace fmt::literals; + using namespace std::literals; + + ScopedTemporaryDirectory TempDir; + + CasGc Gc; + + ZenCacheStore Zcs(Gc, TempDir.Path() / "cache"); + + const int kIterationCount = 100; + + for (int i = 0; i < kIterationCount; ++i) + { + const IoHash Key = IoHash::HashBuffer(&i, sizeof i); + + CbObjectWriter Cbo; + Cbo << "hey" << i; + CbObject Obj = Cbo.Save(); + + ZenCacheValue Value; + Value.Value = Obj.GetBuffer().AsIoBuffer(); + Value.Value.SetContentType(ZenContentType::kCbObject); + + Zcs.Put("test_bucket"sv, Key, Value); + } + + for (int i = 0; i < kIterationCount; ++i) + { + const IoHash Key = IoHash::HashBuffer(&i, sizeof i); + + ZenCacheValue Value; + Zcs.Get("test_bucket"sv, Key, /* out */ Value); + + REQUIRE(Value.Value); + CHECK(Value.Value.GetContentType() == ZenContentType::kCbObject); + CHECK_EQ(ValidateCompactBinary(Value.Value, CbValidateMode::All), CbValidateError::None); + CbObject Obj = LoadCompactBinaryObject(Value.Value); + CHECK_EQ(Obj["hey"].AsInt32(), i); + } +} + +#endif + +void +z$_forcelink() +{ +} + } // namespace zen diff --git a/zenserver/cache/structuredcachestore.h b/zenserver/cache/structuredcachestore.h index da3e74126..6beecf78b 100644 --- a/zenserver/cache/structuredcachestore.h +++ b/zenserver/cache/structuredcachestore.h @@ -105,7 +105,7 @@ private: class ZenCacheDiskLayer { public: - ZenCacheDiskLayer(const std::filesystem::path& RootDir); + explicit ZenCacheDiskLayer(const std::filesystem::path& RootDir); ~ZenCacheDiskLayer(); bool Get(std::string_view Bucket, const IoHash& HashKey, ZenCacheValue& OutValue); @@ -149,4 +149,6 @@ private: uint64_t m_LastScrubTime = 0; }; +void z$_forcelink(); + } // namespace zen diff --git a/zenserver/config.cpp b/zenserver/config.cpp index cbdbebb03..f512f8015 100644 --- a/zenserver/config.cpp +++ b/zenserver/config.cpp @@ -234,6 +234,13 @@ ParseGlobalCliOptions(int argc, char* argv[], ZenServerOptions& GlobalOptions, Z options.add_option("cache", "", + "upstream-zen-dns", + "DNS that resolves to one or more Zen server instance(s)", + cxxopts::value<std::vector<std::string>>(ServiceConfig.UpstreamCacheConfig.ZenConfig.Dns)->default_value(""), + ""); + + options.add_option("cache", + "", "upstream-thread-count", "Number of threads used for upstream procsssing", cxxopts::value<int>(ServiceConfig.UpstreamCacheConfig.UpstreamThreadCount)->default_value("4"), diff --git a/zenserver/config.h b/zenserver/config.h index 2a5a17fb9..72a4f31bb 100644 --- a/zenserver/config.h +++ b/zenserver/config.h @@ -42,6 +42,7 @@ struct ZenUpstreamJupiterConfig struct ZenUpstreamZenConfig { std::vector<std::string> Urls; + std::vector<std::string> Dns; }; enum class UpstreamCachePolicy : uint8_t 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) { diff --git a/zenserver/zenserver.vcxproj b/zenserver/zenserver.vcxproj index b670582e7..d954d3f8d 100644 --- a/zenserver/zenserver.vcxproj +++ b/zenserver/zenserver.vcxproj @@ -120,7 +120,6 @@ <ClInclude Include="testing\httptest.h" /> <ClInclude Include="upstream\jupiter.h" /> <ClInclude Include="projectstore.h" /> - <ClInclude Include="cache\cacheagent.h" /> <ClInclude Include="testing\launch.h" /> <ClInclude Include="casstore.h" /> <ClInclude Include="diag\diagsvcs.h" /> @@ -142,7 +141,6 @@ <ClCompile Include="monitoring\httpstats.cpp" /> <ClCompile Include="monitoring\httpstatus.cpp" /> <ClCompile Include="projectstore.cpp" /> - <ClCompile Include="cache\cacheagent.cpp" /> <ClCompile Include="sos\sos.cpp" /> <ClCompile Include="testing\httptest.cpp" /> <ClCompile Include="upstream\jupiter.cpp" /> diff --git a/zenserver/zenserver.vcxproj.filters b/zenserver/zenserver.vcxproj.filters index b87fa0016..04c6267ba 100644 --- a/zenserver/zenserver.vcxproj.filters +++ b/zenserver/zenserver.vcxproj.filters @@ -5,9 +5,6 @@ <ClInclude Include="projectstore.h" /> <ClInclude Include="casstore.h" /> <ClInclude Include="testing\launch.h" /> - <ClInclude Include="cache\cacheagent.h"> - <Filter>cache</Filter> - </ClInclude> <ClInclude Include="diag\diagsvcs.h"> <Filter>diag</Filter> </ClInclude> @@ -49,9 +46,6 @@ <ClCompile Include="zenserver.cpp" /> <ClCompile Include="projectstore.cpp" /> <ClCompile Include="casstore.cpp" /> - <ClCompile Include="cache\cacheagent.cpp"> - <Filter>cache</Filter> - </ClCompile> <ClCompile Include="experimental\usnjournal.cpp"> <Filter>experimental</Filter> </ClCompile> |