aboutsummaryrefslogtreecommitdiff
path: root/src/zenserver/config.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2023-12-11 13:09:03 +0100
committerStefan Boberg <[email protected]>2023-12-11 13:09:03 +0100
commit93afeddbc7a5b5df390a29407f5515acd5a70fc1 (patch)
tree6f85ee551aabe20dece64a750c0b2d5d2c5d2d5d /src/zenserver/config.cpp
parentremoved unnecessary SHA1 references (diff)
parentMake sure that PathFromHandle don't hide true error when throwing exceptions ... (diff)
downloadzen-93afeddbc7a5b5df390a29407f5515acd5a70fc1.tar.xz
zen-93afeddbc7a5b5df390a29407f5515acd5a70fc1.zip
Merge branch 'main' of https://github.com/EpicGames/zen
Diffstat (limited to 'src/zenserver/config.cpp')
-rw-r--r--src/zenserver/config.cpp729
1 files changed, 178 insertions, 551 deletions
diff --git a/src/zenserver/config.cpp b/src/zenserver/config.cpp
index 08ba6dc95..5f2c3351e 100644
--- a/src/zenserver/config.cpp
+++ b/src/zenserver/config.cpp
@@ -2,12 +2,14 @@
#include "config.h"
+#include "config/luaconfig.h"
#include "diag/logging.h"
#include <zencore/crypto.h>
#include <zencore/except.h>
#include <zencore/fmtutils.h>
#include <zencore/iobuffer.h>
+#include <zencore/logging.h>
#include <zencore/string.h>
#include <zenhttp/zenhttp.h>
#include <zenutil/basicfile.h>
@@ -175,592 +177,156 @@ MakeSafePath(const std::string_view Path)
#endif
};
-namespace LuaConfig {
-
- void EscapeBackslash(std::string& InOutString)
+class CachePolicyOption : public LuaConfig::OptionValue
+{
+public:
+ CachePolicyOption(UpstreamCachePolicy& Value) : Value(Value) {}
+ virtual void Print(std::string_view, zen::StringBuilderBase& StringBuilder) override
{
- std::size_t BackslashPos = InOutString.find('\\');
- if (BackslashPos != std::string::npos)
+ switch (Value)
{
- std::size_t Offset = 0;
- zen::ExtendableStringBuilder<512> PathBuilder;
- while (BackslashPos != std::string::npos)
- {
- PathBuilder.Append(InOutString.substr(Offset, BackslashPos + 1 - Offset));
- PathBuilder.Append('\\');
- Offset = BackslashPos + 1;
- BackslashPos = InOutString.find('\\', Offset);
- }
- PathBuilder.Append(InOutString.substr(Offset, BackslashPos));
- InOutString = PathBuilder.ToString();
+ case UpstreamCachePolicy::Read:
+ StringBuilder.Append("readonly");
+ break;
+ case UpstreamCachePolicy::Write:
+ StringBuilder.Append("writeonly");
+ break;
+ case UpstreamCachePolicy::Disabled:
+ StringBuilder.Append("disabled");
+ break;
+ case UpstreamCachePolicy::ReadWrite:
+ StringBuilder.Append("readwrite");
+ break;
+ default:
+ ZEN_ASSERT(false);
}
}
-
- class OptionValue
- {
- public:
- virtual void Print(std::string_view Indent, zen::StringBuilderBase& StringBuilder) = 0;
- virtual void Parse(sol::object Object) = 0;
-
- virtual ~OptionValue() {}
- };
-
- typedef std::shared_ptr<OptionValue> TOptionValue;
-
- class StringOption : public OptionValue
- {
- public:
- StringOption(std::string& Value) : Value(Value) {}
- virtual void Print(std::string_view, zen::StringBuilderBase& StringBuilder) override
- {
- StringBuilder.Append(fmt::format("\"{}\"", Value));
- }
- virtual void Parse(sol::object Object) override { Value = Object.as<std::string>(); }
- std::string& Value;
- };
-
- class FilePathOption : public OptionValue
+ virtual void Parse(sol::object Object) override
{
- public:
- FilePathOption(std::filesystem::path& Value) : Value(Value) {}
- virtual void Print(std::string_view, zen::StringBuilderBase& StringBuilder) override
+ std::string PolicyString = Object.as<std::string>();
+ if (PolicyString == "readonly")
{
- std::string Path = Value.string();
- EscapeBackslash(Path);
- StringBuilder.Append(fmt::format("\"{}\"", Path));
+ Value = UpstreamCachePolicy::Read;
}
- virtual void Parse(sol::object Object) override
+ else if (PolicyString == "writeonly")
{
- std::string Str = Object.as<std::string>();
- if (!Str.empty())
- {
- Value = MakeSafePath(Str);
- }
+ Value = UpstreamCachePolicy::Write;
}
- std::filesystem::path& Value;
- };
-
- class BoolOption : public OptionValue
- {
- public:
- BoolOption(bool& Value) : Value(Value) {}
- virtual void Print(std::string_view, zen::StringBuilderBase& StringBuilder) override
+ else if (PolicyString == "disabled")
{
- StringBuilder.Append(Value ? "true" : "false");
+ Value = UpstreamCachePolicy::Disabled;
}
- virtual void Parse(sol::object Object) override { Value = Object.as<bool>(); }
- bool& Value;
- };
-
- class CachePolicyOption : public OptionValue
- {
- public:
- CachePolicyOption(UpstreamCachePolicy& Value) : Value(Value) {}
- virtual void Print(std::string_view, zen::StringBuilderBase& StringBuilder) override
+ else if (PolicyString == "readwrite")
{
- switch (Value)
- {
- case UpstreamCachePolicy::Read:
- StringBuilder.Append("readonly");
- break;
- case UpstreamCachePolicy::Write:
- StringBuilder.Append("writeonly");
- break;
- case UpstreamCachePolicy::Disabled:
- StringBuilder.Append("disabled");
- break;
- case UpstreamCachePolicy::ReadWrite:
- StringBuilder.Append("readwrite");
- break;
- default:
- ZEN_ASSERT(false);
- }
+ Value = UpstreamCachePolicy::ReadWrite;
}
- virtual void Parse(sol::object Object) override
- {
- std::string PolicyString = Object.as<std::string>();
- if (PolicyString == "readonly")
- {
- Value = UpstreamCachePolicy::Read;
- }
- else if (PolicyString == "writeonly")
- {
- Value = UpstreamCachePolicy::Write;
- }
- else if (PolicyString == "disabled")
- {
- Value = UpstreamCachePolicy::Disabled;
- }
- else if (PolicyString == "readwrite")
- {
- Value = UpstreamCachePolicy::ReadWrite;
- }
- }
- UpstreamCachePolicy& Value;
- };
-
- template<Integral T>
- class NumberOption : public OptionValue
- {
- public:
- NumberOption(T& Value) : Value(Value) {}
- virtual void Print(std::string_view, zen::StringBuilderBase& StringBuilder) override
- {
- StringBuilder.Append(fmt::format("{}", Value));
- }
- virtual void Parse(sol::object Object) override { Value = Object.as<T>(); }
- T& Value;
- };
+ }
+ UpstreamCachePolicy& Value;
+};
- class LuaContainerWriter
+class ZenAuthConfigOption : public LuaConfig::OptionValue
+{
+public:
+ ZenAuthConfigOption(ZenAuthConfig& Value) : Value(Value) {}
+ virtual void Print(std::string_view Indent, zen::StringBuilderBase& StringBuilder) override
{
- public:
- LuaContainerWriter(zen::StringBuilderBase& StringBuilder, std::string_view Indent)
- : StringBuilder(StringBuilder)
- , InitialIndent(Indent.length())
- , LocalIndent(Indent)
+ if (Value.OpenIdProviders.empty())
{
- StringBuilder.Append("{\n");
- LocalIndent.push_back('\t');
- }
- ~LuaContainerWriter()
- {
- LocalIndent.pop_back();
- StringBuilder.Append(LocalIndent);
- StringBuilder.Append("}");
- }
-
- void BeginContainer(std::string_view Name)
- {
- StringBuilder.Append(LocalIndent);
- if (!Name.empty())
- {
- StringBuilder.Append(Name);
- StringBuilder.Append(" = {\n");
- }
- else
- {
- StringBuilder.Append("{\n");
- }
- LocalIndent.push_back('\t');
+ StringBuilder.Append("{}");
+ return;
}
- void WriteValue(std::string_view Name, std::string_view Value)
+ LuaConfig::LuaContainerWriter Writer(StringBuilder, Indent);
+ for (const ZenOpenIdProviderConfig& Config : Value.OpenIdProviders)
{
- if (Name.empty())
- {
- StringBuilder.Append(fmt::format("{}\"{}\",\n", LocalIndent, Value));
- }
- else
+ Writer.BeginContainer("");
{
- StringBuilder.Append(fmt::format("{}{} = \"{}\",\n", LocalIndent, Name, Value));
+ Writer.WriteValue("name", Config.Name);
+ Writer.WriteValue("url", Config.Url);
+ Writer.WriteValue("clientid", Config.ClientId);
}
+ Writer.EndContainer();
}
- void EndContainer()
- {
- LocalIndent.pop_back();
- StringBuilder.Append(LocalIndent);
- StringBuilder.Append("}");
- StringBuilder.Append(",\n");
- }
-
- private:
- zen::StringBuilderBase& StringBuilder;
- const std::size_t InitialIndent;
- std::string LocalIndent;
- };
-
- class StringArrayOption : public OptionValue
+ }
+ virtual void Parse(sol::object Object) override
{
- public:
- StringArrayOption(std::vector<std::string>& Value) : Value(Value) {}
- virtual void Print(std::string_view Indent, zen::StringBuilderBase& StringBuilder) override
- {
- if (Value.empty())
- {
- StringBuilder.Append("{}");
- }
- if (Value.size() == 1)
- {
- StringBuilder.Append(fmt::format("\"{}\"", Value[0]));
- }
- else
- {
- LuaContainerWriter Writer(StringBuilder, Indent);
- for (std::string String : Value)
- {
- Writer.WriteValue("", String);
- }
- }
- }
- virtual void Parse(sol::object Object) override
+ if (sol::optional<sol::table> OpenIdProviders = Object.as<sol::table>())
{
- if (Object.get_type() == sol::type::string)
+ for (const auto& Kv : OpenIdProviders.value())
{
- Value.push_back(Object.as<std::string>());
- }
- else if (Object.get_type() == sol::type::table)
- {
- for (const auto& Kv : Object.as<sol::table>())
+ if (sol::optional<sol::table> OpenIdProvider = Kv.second.as<sol::table>())
{
- Value.push_back(Kv.second.as<std::string>());
- }
- }
- }
-
- private:
- std::vector<std::string>& Value;
- };
+ std::string Name = OpenIdProvider.value().get_or("name", std::string("Default"));
+ std::string Url = OpenIdProvider.value().get_or("url", std::string());
+ std::string ClientId = OpenIdProvider.value().get_or("clientid", std::string());
- class ZenAuthConfigOption : public OptionValue
- {
- public:
- ZenAuthConfigOption(ZenAuthConfig& Value) : Value(Value) {}
- virtual void Print(std::string_view Indent, zen::StringBuilderBase& StringBuilder) override
- {
- if (Value.OpenIdProviders.empty())
- {
- StringBuilder.Append("{}");
- return;
- }
- LuaContainerWriter Writer(StringBuilder, Indent);
- for (const ZenOpenIdProviderConfig& Config : Value.OpenIdProviders)
- {
- Writer.BeginContainer("");
- {
- Writer.WriteValue("name", Config.Name);
- Writer.WriteValue("url", Config.Url);
- Writer.WriteValue("clientid", Config.ClientId);
- }
- Writer.EndContainer();
- }
- }
- virtual void Parse(sol::object Object) override
- {
- if (sol::optional<sol::table> OpenIdProviders = Object.as<sol::table>())
- {
- for (const auto& Kv : OpenIdProviders.value())
- {
- if (sol::optional<sol::table> OpenIdProvider = Kv.second.as<sol::table>())
- {
- std::string Name = OpenIdProvider.value().get_or("name", std::string("Default"));
- std::string Url = OpenIdProvider.value().get_or("url", std::string());
- std::string ClientId = OpenIdProvider.value().get_or("clientid", std::string());
-
- Value.OpenIdProviders.push_back({.Name = std::move(Name), .Url = std::move(Url), .ClientId = std::move(ClientId)});
- }
+ Value.OpenIdProviders.push_back({.Name = std::move(Name), .Url = std::move(Url), .ClientId = std::move(ClientId)});
}
}
}
- ZenAuthConfig& Value;
- };
+ }
+ ZenAuthConfig& Value;
+};
- class ZenObjectStoreConfigOption : public OptionValue
+class ZenObjectStoreConfigOption : public LuaConfig::OptionValue
+{
+public:
+ ZenObjectStoreConfigOption(ZenObjectStoreConfig& Value) : Value(Value) {}
+ virtual void Print(std::string_view Indent, zen::StringBuilderBase& StringBuilder) override
{
- public:
- ZenObjectStoreConfigOption(ZenObjectStoreConfig& Value) : Value(Value) {}
- virtual void Print(std::string_view Indent, zen::StringBuilderBase& StringBuilder) override
+ if (Value.Buckets.empty())
{
- if (Value.Buckets.empty())
- {
- StringBuilder.Append("{}");
- return;
- }
- LuaContainerWriter Writer(StringBuilder, Indent);
- for (const ZenObjectStoreConfig::BucketConfig& Config : Value.Buckets)
- {
- Writer.BeginContainer("");
- {
- Writer.WriteValue("name", Config.Name);
- std::string Directory = Config.Directory.string();
- EscapeBackslash(Directory);
- Writer.WriteValue("directory", Directory);
- }
- Writer.EndContainer();
- }
+ StringBuilder.Append("{}");
+ return;
}
- virtual void Parse(sol::object Object) override
+ LuaConfig::LuaContainerWriter Writer(StringBuilder, Indent);
+ for (const ZenObjectStoreConfig::BucketConfig& Config : Value.Buckets)
{
- if (sol::optional<sol::table> Buckets = Object.as<sol::table>())
+ Writer.BeginContainer("");
{
- for (const auto& Kv : Buckets.value())
- {
- if (sol::optional<sol::table> Bucket = Kv.second.as<sol::table>())
- {
- std::string Name = Bucket.value().get_or("name", std::string("Default"));
- std::string Directory = Bucket.value().get_or("directory", std::string());
-
- Value.Buckets.push_back({.Name = std::move(Name), .Directory = MakeSafePath(Directory)});
- }
- }
+ Writer.WriteValue("name", Config.Name);
+ std::string Directory = Config.Directory.string();
+ LuaConfig::EscapeBackslash(Directory);
+ Writer.WriteValue("directory", Directory);
}
+ Writer.EndContainer();
}
- ZenObjectStoreConfig& Value;
- };
-
- std::shared_ptr<OptionValue> MakeOption(std::string& Value) { return std::make_shared<StringOption>(Value); };
-
- std::shared_ptr<OptionValue> MakeOption(std::filesystem::path& Value) { return std::make_shared<FilePathOption>(Value); };
-
- template<Integral T>
- std::shared_ptr<OptionValue> MakeOption(T& Value)
- {
- return std::make_shared<NumberOption<T>>(Value);
- };
-
- std::shared_ptr<OptionValue> MakeOption(bool& Value) { return std::make_shared<BoolOption>(Value); };
-
- std::shared_ptr<OptionValue> MakeOption(UpstreamCachePolicy& Value) { return std::make_shared<CachePolicyOption>(Value); };
-
- std::shared_ptr<OptionValue> MakeOption(std::vector<std::string>& Value) { return std::make_shared<StringArrayOption>(Value); };
-
- std::shared_ptr<OptionValue> MakeOption(ZenAuthConfig& Value) { return std::make_shared<ZenAuthConfigOption>(Value); };
-
- std::shared_ptr<OptionValue> MakeOption(ZenObjectStoreConfig& Value) { return std::make_shared<ZenObjectStoreConfigOption>(Value); };
-
- struct Option
- {
- std::string CommandLineOptionName;
- TOptionValue Value;
- };
-
- struct Options
+ }
+ virtual void Parse(sol::object Object) override
{
- public:
- template<typename T>
- void AddOption(std::string_view Key, T& Value, std::string_view CommandLineOptionName = "")
- {
- OptionMap.insert_or_assign(std::string(Key),
- Option{.CommandLineOptionName = std::string(CommandLineOptionName), .Value = MakeOption(Value)});
- };
-
- void Parse(const std::filesystem::path& Path, const cxxopts::ParseResult& CmdLineResult)
- {
- zen::IoBuffer LuaScript = zen::IoBufferBuilder::MakeFromFile(Path);
-
- if (LuaScript)
- {
- sol::state lua;
-
- lua.open_libraries(sol::lib::base);
-
- lua.set_function("getenv", [&](const std::string env) -> sol::object {
-#if ZEN_PLATFORM_WINDOWS
- std::wstring EnvVarValue;
- size_t RequiredSize = 0;
- std::wstring EnvWide = zen::Utf8ToWide(env);
- _wgetenv_s(&RequiredSize, nullptr, 0, EnvWide.c_str());
-
- if (RequiredSize == 0)
- return sol::make_object(lua, sol::lua_nil);
-
- EnvVarValue.resize(RequiredSize);
- _wgetenv_s(&RequiredSize, EnvVarValue.data(), RequiredSize, EnvWide.c_str());
- return sol::make_object(lua, zen::WideToUtf8(EnvVarValue.c_str()));
-#elif ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC
- char* EnvVariable = getenv(env.c_str());
- if (EnvVariable == nullptr)
- {
- return sol::make_object(lua, sol::lua_nil);
- }
- return sol::make_object(lua, EnvVariable);
-#else
- ZEN_UNUSED(env);
- return sol::make_object(lua, sol::lua_nil);
-#endif
- });
-
- try
- {
- sol::load_result config = lua.load(std::string_view((const char*)LuaScript.Data(), LuaScript.Size()), "zen_cfg");
-
- if (!config.valid())
- {
- sol::error err = config;
-
- std::string ErrorString = sol::to_string(config.status());
-
- throw std::runtime_error(fmt::format("{} error: {}", ErrorString, err.what()));
- }
-
- config();
- }
- catch (std::exception& e)
- {
- throw std::runtime_error(fmt::format("failed to load config script ('{}'): {}", Path, e.what()).c_str());
- }
-
- Parse(lua, CmdLineResult);
- }
- }
-
- void Parse(const sol::state& LuaState, const cxxopts::ParseResult& CmdLineResult)
- {
- for (auto It : LuaState)
- {
- sol::object Key = It.first;
- sol::type KeyType = Key.get_type();
- if (KeyType == sol::type::string)
- {
- sol::type ValueType = It.second.get_type();
- switch (ValueType)
- {
- case sol::type::table:
- {
- std::string Name = Key.as<std::string>();
- if (Name.starts_with("_"))
- {
- continue;
- }
- if (Name == "base")
- {
- continue;
- }
- Traverse(It.second.as<sol::table>(), Name, CmdLineResult);
- }
- break;
- default:
- break;
- }
- }
- }
- }
-
- void Touch(std::string_view Key) { UsedKeys.insert(std::string(Key)); }
-
- void Print(zen::StringBuilderBase& SB, const cxxopts::ParseResult& CmdLineResult)
+ if (sol::optional<sol::table> Buckets = Object.as<sol::table>())
{
- for (auto It : OptionMap)
+ for (const auto& Kv : Buckets.value())
{
- if (CmdLineResult.count(It.second.CommandLineOptionName) != 0)
+ if (sol::optional<sol::table> Bucket = Kv.second.as<sol::table>())
{
- UsedKeys.insert(It.first);
- }
- }
+ std::string Name = Bucket.value().get_or("name", std::string("Default"));
+ std::string Directory = Bucket.value().get_or("directory", std::string());
- std::vector<std::string> SortedKeys(UsedKeys.begin(), UsedKeys.end());
- std::sort(SortedKeys.begin(), SortedKeys.end());
- auto GetTablePath = [](const std::string& Key) -> std::vector<std::string> {
- std::vector<std::string> Path;
- zen::ForEachStrTok(Key, '.', [&Path](std::string_view Part) {
- Path.push_back(std::string(Part));
- return true;
- });
- return Path;
- };
- std::vector<std::string> CurrentTablePath;
- std::string Indent;
- auto It = SortedKeys.begin();
- for (const std::string& Key : SortedKeys)
- {
- std::vector<std::string> KeyPath = GetTablePath(Key);
- std::string Name = KeyPath.back();
- KeyPath.pop_back();
- if (CurrentTablePath != KeyPath)
- {
- size_t EqualCount = 0;
- while (EqualCount < CurrentTablePath.size() && EqualCount < KeyPath.size() &&
- CurrentTablePath[EqualCount] == KeyPath[EqualCount])
- {
- EqualCount++;
- }
- while (CurrentTablePath.size() > EqualCount)
- {
- CurrentTablePath.pop_back();
- Indent.pop_back();
- SB.Append(Indent);
- SB.Append("}");
- if (CurrentTablePath.size() == EqualCount && !Indent.empty() && KeyPath.size() >= EqualCount)
- {
- SB.Append(",");
- }
- SB.Append("\n");
- if (Indent.empty())
- {
- SB.Append("\n");
- }
- }
- while (EqualCount < KeyPath.size())
- {
- SB.Append(Indent);
- SB.Append(KeyPath[EqualCount]);
- SB.Append(" = {\n");
- Indent.push_back('\t');
- CurrentTablePath.push_back(KeyPath[EqualCount]);
- EqualCount++;
- }
+ Value.Buckets.push_back({.Name = std::move(Name), .Directory = LuaConfig::MakeSafePath(Directory)});
}
-
- SB.Append(Indent);
- SB.Append(Name);
- SB.Append(" = ");
- OptionMap[Key].Value->Print(Indent, SB);
- SB.Append(",\n");
- }
- while (!CurrentTablePath.empty())
- {
- Indent.pop_back();
- SB.Append(Indent);
- SB.Append("}\n");
- CurrentTablePath.pop_back();
}
}
+ }
+ ZenObjectStoreConfig& Value;
+};
- private:
- void Traverse(sol::table Table, std::string_view PathPrefix, const cxxopts::ParseResult& CmdLineResult)
- {
- for (auto It : Table)
- {
- sol::object Key = It.first;
- sol::type KeyType = Key.get_type();
- if (KeyType == sol::type::string || KeyType == sol::type::number)
- {
- sol::type ValueType = It.second.get_type();
- switch (ValueType)
- {
- case sol::type::table:
- case sol::type::string:
- case sol::type::number:
- case sol::type::boolean:
- {
- std::string Name = Key.as<std::string>();
- if (Name.starts_with("_"))
- {
- continue;
- }
- Name = std::string(PathPrefix) + "." + Key.as<std::string>();
- auto OptionIt = OptionMap.find(Name);
- if (OptionIt != OptionMap.end())
- {
- UsedKeys.insert(Name);
- if (CmdLineResult.count(OptionIt->second.CommandLineOptionName) != 0)
- {
- continue;
- }
- OptionIt->second.Value->Parse(It.second);
- continue;
- }
- if (ValueType == sol::type::table)
- {
- if (Name == "base")
- {
- continue;
- }
- Traverse(It.second.as<sol::table>(), Name, CmdLineResult);
- }
- }
- break;
- default:
- break;
- }
- }
- }
- }
+std::shared_ptr<LuaConfig::OptionValue>
+MakeOption(zen::UpstreamCachePolicy& Value)
+{
+ return std::make_shared<CachePolicyOption>(Value);
+};
- std::unordered_map<std::string, Option> OptionMap;
- std::unordered_set<std::string> UsedKeys;
- };
+std::shared_ptr<LuaConfig::OptionValue>
+MakeOption(zen::ZenAuthConfig& Value)
+{
+ return std::make_shared<ZenAuthConfigOption>(Value);
+};
-} // namespace LuaConfig
+std::shared_ptr<LuaConfig::OptionValue>
+MakeOption(zen::ZenObjectStoreConfig& Value)
+{
+ return std::make_shared<ZenObjectStoreConfigOption>(Value);
+};
void
ParseConfigFile(const std::filesystem::path& Path,
@@ -887,6 +453,10 @@ ParseConfigFile(const std::filesystem::path& Path,
LuaOptions.AddOption("gc.lightweightntervalseconds"sv,
ServerOptions.GcConfig.LightweightIntervalSeconds,
"gc-lightweight-interval-seconds"sv);
+ LuaOptions.AddOption("gc.compactblockthreshold"sv,
+ ServerOptions.GcConfig.CompactBlockUsageThresholdPercent,
+ "gc-compactblock-threshold"sv);
+ LuaOptions.AddOption("gc.verbose"sv, ServerOptions.GcConfig.Verbose, "gc-verbose"sv);
////// gc
LuaOptions.AddOption("gc.cache.maxdurationseconds"sv, ServerOptions.GcConfig.Cache.MaxDurationSeconds, "gc-cache-duration-seconds"sv);
@@ -938,6 +508,7 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions)
std::string AbsLogFile;
std::string ConfigFile;
std::string OutputConfigFile;
+ std::string BaseSnapshotDir;
cxxopts::Options options("zenserver", "Zen Server");
options.add_options()("dedicated",
@@ -947,12 +518,20 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions)
options.add_options()("clean",
"Clean out all state at startup",
cxxopts::value<bool>(ServerOptions.IsCleanStart)->default_value("false"));
+ options.add_options()("scrub",
+ "Validate state at startup",
+ cxxopts::value(ServerOptions.ScrubOptions)->implicit_value("yes"),
+ "(nocas,nogc,nodelete,yes,no)*");
options.add_options()("help", "Show command line help");
options.add_options()("t, test", "Enable test mode", cxxopts::value<bool>(ServerOptions.IsTest)->default_value("false"));
- options.add_options()("log-id", "Specify id for adding context to log output", cxxopts::value<std::string>(ServerOptions.LogId));
options.add_options()("data-dir", "Specify persistence root", cxxopts::value<std::string>(DataDir));
+ options.add_options()("snapshot-dir",
+ "Specify a snapshot of server state to mirror into the persistence root at startup",
+ cxxopts::value<std::string>(BaseSnapshotDir));
options.add_options()("content-dir", "Frontend content directory", cxxopts::value<std::string>(ContentDir));
- options.add_options()("abslog", "Path to log file", cxxopts::value<std::string>(AbsLogFile));
+ options.add_options()("powercycle",
+ "Exit immediately after initialization is complete",
+ cxxopts::value<bool>(ServerOptions.IsPowerCycle));
options.add_options()("config", "Path to Lua config file", cxxopts::value<std::string>(ConfigFile));
options.add_options()("write-config", "Path to output Lua config file", cxxopts::value<std::string>(OutputConfigFile));
options.add_options()("no-sentry",
@@ -961,7 +540,21 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions)
options.add_options()("sentry-allow-personal-info",
"Allow personally identifiable information in sentry crash reports",
cxxopts::value<bool>(ServerOptions.SentryAllowPII)->default_value("false"));
- options.add_options()("quiet", "Disable console logging", cxxopts::value<bool>(ServerOptions.NoConsoleOutput)->default_value("false"));
+
+ // clang-format off
+ options.add_options("logging")
+ ("abslog", "Path to log file", cxxopts::value<std::string>(AbsLogFile))
+ ("log-id", "Specify id for adding context to log output", cxxopts::value<std::string>(ServerOptions.LogId))
+ ("quiet", "Disable console logging", cxxopts::value<bool>(ServerOptions.NoConsoleOutput)->default_value("false"))
+ ("log-trace", "Change selected loggers to level TRACE", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Trace]))
+ ("log-debug", "Change selected loggers to level DEBUG", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Debug]))
+ ("log-info", "Change selected loggers to level INFO", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Info]))
+ ("log-warn", "Change selected loggers to level WARN", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Warn]))
+ ("log-error", "Change selected loggers to level ERROR", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Err]))
+ ("log-critical", "Change selected loggers to level CRITICAL", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Critical]))
+ ("log-off", "Change selected loggers to level OFF", cxxopts::value<std::string>(ServerOptions.Loggers[logging::level::Off]))
+ ;
+ // clang-format on
options.add_option("security",
"",
@@ -1313,6 +906,21 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions)
cxxopts::value<uint64_t>(ServerOptions.GcConfig.DiskSizeSoftLimit)->default_value("0"),
"");
+ options.add_option("gc",
+ "",
+ "gc-compactblock-threshold",
+ "Garbage collection - how much of a compact block should be used to skip compacting the block. 0 - compact only "
+ "empty eligible blocks, 100 - compact all non-full eligible blocks.",
+ cxxopts::value<uint32_t>(ServerOptions.GcConfig.CompactBlockUsageThresholdPercent)->default_value("60"),
+ "");
+
+ options.add_option("gc",
+ "",
+ "gc-verbose",
+ "Enable verbose logging for GC.",
+ cxxopts::value<bool>(ServerOptions.GcConfig.Verbose)->default_value("false"),
+ "");
+
options.add_option("objectstore",
"",
"objectstore-enabled",
@@ -1337,9 +945,18 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions)
try
{
- auto result = options.parse(argc, argv);
+ cxxopts::ParseResult Result;
- if (result.count("help"))
+ try
+ {
+ Result = options.parse(argc, argv);
+ }
+ catch (std::exception& Ex)
+ {
+ throw zen::OptionParseException(Ex.what());
+ }
+
+ if (Result.count("help"))
{
ZEN_CONSOLE("{}", options.help());
#if ZEN_PLATFORM_WINDOWS
@@ -1352,12 +969,28 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions)
exit(0);
}
+ for (int i = 0; i < logging::level::LogLevelCount; ++i)
+ {
+ logging::ConfigureLogLevels(logging::level::LogLevel(i), ServerOptions.Loggers[i]);
+ }
+ logging::RefreshLogLevels();
+
ServerOptions.DataDir = MakeSafePath(DataDir);
+ ServerOptions.BaseSnapshotDir = MakeSafePath(BaseSnapshotDir);
ServerOptions.ContentDir = MakeSafePath(ContentDir);
ServerOptions.AbsLogFile = MakeSafePath(AbsLogFile);
ServerOptions.ConfigFile = MakeSafePath(ConfigFile);
ServerOptions.UpstreamCacheConfig.CachePolicy = ParseUpstreamCachePolicy(UpstreamCachePolicyOptions);
+ if (!BaseSnapshotDir.empty())
+ {
+ if (DataDir.empty())
+ throw zen::OptionParseException("You must explicitly specify a data directory when specifying a base snapshot");
+
+ if (!std::filesystem::is_directory(ServerOptions.BaseSnapshotDir))
+ throw OptionParseException(fmt::format("Snapshot directory must be a directory: '{}", BaseSnapshotDir));
+ }
+
if (OpenIdProviderUrl.empty() == false)
{
if (OpenIdClientId.empty())
@@ -1373,21 +1006,15 @@ ParseCliOptions(int argc, char* argv[], ZenServerOptions& ServerOptions)
if (!ServerOptions.ConfigFile.empty())
{
- ParseConfigFile(ServerOptions.ConfigFile, ServerOptions, result, OutputConfigFile);
+ ParseConfigFile(ServerOptions.ConfigFile, ServerOptions, Result, OutputConfigFile);
}
else
{
- ParseConfigFile(ServerOptions.DataDir / "zen_cfg.lua", ServerOptions, result, OutputConfigFile);
+ ParseConfigFile(ServerOptions.DataDir / "zen_cfg.lua", ServerOptions, Result, OutputConfigFile);
}
ValidateOptions(ServerOptions);
}
- catch (cxxopts::OptionParseException& e)
- {
- ZEN_CONSOLE_ERROR("Error parsing zenserver arguments: {}\n\n{}", e.what(), options.help());
-
- throw;
- }
catch (zen::OptionParseException& e)
{
ZEN_CONSOLE_ERROR("Error parsing zenserver arguments: {}\n\n{}", e.what(), options.help());