aboutsummaryrefslogtreecommitdiff
path: root/src/zen/cmds/admin_cmd.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zen/cmds/admin_cmd.cpp')
-rw-r--r--src/zen/cmds/admin_cmd.cpp184
1 files changed, 184 insertions, 0 deletions
diff --git a/src/zen/cmds/admin_cmd.cpp b/src/zen/cmds/admin_cmd.cpp
index 8b8b416ba..b041aa46e 100644
--- a/src/zen/cmds/admin_cmd.cpp
+++ b/src/zen/cmds/admin_cmd.cpp
@@ -1,10 +1,12 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "admin_cmd.h"
+#include <zencore/filesystem.h>
#include <zencore/logging.h>
#include <zenhttp/formatters.h>
#include <zenhttp/httpclient.h>
#include <zenhttp/httpcommon.h>
+#include <zenutil/basicfile.h>
ZEN_THIRD_PARTY_INCLUDES_START
#include <cpr/cpr.h>
@@ -455,4 +457,186 @@ FlushCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
return 1;
}
+//////////////////////////////////////////////////////////////////////////
+
+CopyStateCommand::CopyStateCommand()
+{
+ m_Options.add_options()("h,help", "Print help");
+ m_Options.add_option("", "", "data-path", "Zen server source data path", cxxopts::value(m_DataPath), "<data-path>");
+ m_Options.add_option("", "", "target-path", "Target data path", cxxopts::value(m_TargetPath), "<target-path>");
+ m_Options.add_option("",
+ "",
+ "skip-logs",
+ "Only copy state index files, not log files (recommended to issue a zen flush before using this option)",
+ cxxopts::value(m_SkipLogs)->default_value("false"),
+ "<skip-logs>");
+ m_Options.parse_positional({"data-path", "target-path"});
+}
+
+CopyStateCommand::~CopyStateCommand() = default;
+
+static void
+Copy(const std::filesystem::path& Source, const std::filesystem::path& Target)
+{
+ CreateDirectories(Target.parent_path());
+ BasicFile SourceFile;
+ SourceFile.Open(Source, BasicFile::Mode::kRead);
+ BasicFile TargetFile;
+ TargetFile.Open(Target, BasicFile::Mode::kTruncate);
+ uint64_t Size = SourceFile.FileSize();
+ uint64_t Offset = 0;
+ std::vector<uint8_t> Buffer(Min(size_t(Size), size_t(65536u)));
+ while (Offset < Size)
+ {
+ uint64_t CopyCount = Min<uint64_t>(Size - Offset, size_t(Buffer.size()));
+ SourceFile.Read(Buffer.data(), CopyCount, Offset);
+ TargetFile.Write(Buffer.data(), CopyCount, Offset);
+ Offset += CopyCount;
+ }
+ TargetFile.Flush();
+}
+
+static bool
+TryCopy(const std::filesystem::path& Source, const std::filesystem::path& Target)
+{
+ if (!std::filesystem::is_regular_file(Source))
+ {
+ return false;
+ }
+ Copy(Source, Target);
+ return true;
+}
+
+int
+CopyStateCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
+{
+ ZEN_UNUSED(GlobalOptions);
+
+ if (!ParseOptions(argc, argv))
+ {
+ return 0;
+ }
+
+ if (m_DataPath.empty())
+ {
+ throw OptionParseException("data path must be given");
+ }
+
+ if (!std::filesystem::is_directory(m_DataPath))
+ {
+ throw OptionParseException("data path must exist");
+ }
+
+ if (m_TargetPath.empty())
+ {
+ throw OptionParseException("target path must be given");
+ }
+
+ std::filesystem::path RootManifestPath = m_DataPath / "root_manifest";
+ std::filesystem::path TargetRootManifestPath = m_TargetPath / "root_manifest";
+
+ if (!TryCopy(RootManifestPath, TargetRootManifestPath))
+ {
+ throw OptionParseException("data path is invalid, missing root_manifest");
+ }
+
+ std::filesystem::path CachePath = m_DataPath / "cache";
+ std::filesystem::path TargetCachePath = m_TargetPath / "cache";
+
+ // Copy cache state
+ DirectoryContent CacheDirectoryContent;
+ GetDirectoryContent(CachePath, DirectoryContent::IncludeDirsFlag, CacheDirectoryContent);
+ for (const std::filesystem::path& NamespacePath : CacheDirectoryContent.Directories)
+ {
+ std::filesystem::path NamespaceName = NamespacePath.filename();
+ std::filesystem::path TargetNamespacePath = TargetCachePath / NamespaceName;
+
+ DirectoryContent CacheNamespaceContent;
+ GetDirectoryContent(NamespacePath, DirectoryContent::IncludeDirsFlag, CacheNamespaceContent);
+
+ for (const std::filesystem::path& BucketPath : CacheNamespaceContent.Directories)
+ {
+ std::filesystem::path BucketName = BucketPath.filename();
+ std::filesystem::path TargetBucketPath = TargetNamespacePath / BucketName;
+
+ std::filesystem::path ManifestPath = BucketPath / "zen_manifest";
+ std::filesystem::path TargetManifestPath = TargetBucketPath / "zen_manifest";
+ if (TryCopy(ManifestPath, TargetManifestPath))
+ {
+ if (!m_SkipLogs)
+ {
+ std::filesystem::path LogName = fmt::format("{}.{}", BucketName.string(), "slog");
+ std::filesystem::path LogPath = BucketPath / LogName;
+ std::filesystem::path TargetLogPath = TargetBucketPath / LogName;
+ Copy(LogPath, TargetLogPath);
+ }
+
+ std::filesystem::path IndexName = fmt::format("{}.{}", BucketName.string(), "uidx");
+ std::filesystem::path IndexPath = BucketPath / IndexName;
+ std::filesystem::path TargetIndexPath = TargetBucketPath / IndexName;
+ TryCopy(IndexPath, TargetIndexPath);
+ }
+ }
+ }
+
+ std::filesystem::path CasPath = m_DataPath / "cas";
+ std::filesystem::path TargetCasPath = m_TargetPath / "cas";
+
+ {
+ std::filesystem::path UCasRootPath = CasPath / ".ucas_root";
+ std::filesystem::path TargetUCasRootPath = TargetCasPath / ".ucas_root";
+ Copy(UCasRootPath, TargetUCasRootPath);
+ }
+
+ if (!m_SkipLogs)
+ {
+ std::filesystem::path LogPath = CasPath / "cas.ulog";
+ std::filesystem::path TargetLogPath = TargetCasPath / "cas.ulog";
+ Copy(LogPath, TargetLogPath);
+ }
+
+ {
+ std::filesystem::path IndexPath = CasPath / "cas.uidx";
+ std::filesystem::path TargetIndexPath = TargetCasPath / "cas.uidx";
+ TryCopy(IndexPath, TargetIndexPath);
+ }
+
+ {
+ std::filesystem::path SobsRootPath = CasPath / "sobs";
+ std::filesystem::path TargetSobsRootPath = TargetCasPath / "sobs";
+
+ {
+ std::filesystem::path SobsIndexPath = SobsRootPath / "sobs.uidx";
+ std::filesystem::path TargetSobsIndexPath = TargetSobsRootPath / "sobs.uidx";
+ TryCopy(SobsIndexPath, TargetSobsIndexPath);
+
+ if (!m_SkipLogs)
+ {
+ std::filesystem::path SobsLogPath = SobsRootPath / "sobs.ulog";
+ std::filesystem::path TargetSobsLogPath = TargetSobsRootPath / "sobs.ulog";
+ Copy(SobsLogPath, TargetSobsLogPath);
+ }
+ }
+ }
+
+ {
+ std::filesystem::path TobsRootPath = CasPath / "tobs";
+ std::filesystem::path TargetTobsRootPath = TargetCasPath / "tobs";
+ {
+ std::filesystem::path TobsIndexPath = TobsRootPath / "tobs.uidx";
+ std::filesystem::path TargetTobsIndexPath = TargetTobsRootPath / "tobs.uidx";
+ TryCopy(TobsIndexPath, TargetTobsIndexPath);
+
+ if (!m_SkipLogs)
+ {
+ std::filesystem::path TobsLogPath = TobsRootPath / "tobs.ulog";
+ std::filesystem::path TargetTobsLogPath = TargetTobsRootPath / "tobs.ulog";
+ Copy(TobsLogPath, TargetTobsLogPath);
+ }
+ }
+ }
+
+ return 0;
+}
+
} // namespace zen