aboutsummaryrefslogtreecommitdiff
path: root/src/zencore/filesystem.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2023-11-16 17:20:52 +0100
committerGitHub <[email protected]>2023-11-16 17:20:52 +0100
commit372d3a8a1ff65e53d139a7ee1db022d8cfa55982 (patch)
treedf88c47001bf16c15d12dcfba8cf8850d7e85cbd /src/zencore/filesystem.cpp
parentchanged posix event implementation to use std::atomic instead of volatile (#547) (diff)
downloadzen-372d3a8a1ff65e53d139a7ee1db022d8cfa55982.tar.xz
zen-372d3a8a1ff65e53d139a7ee1db022d8cfa55982.zip
add zenserver state snapshot support (#543)
this introduces a --snapshot-dir command line option to zenserver which specifies a directory which will be propagated to the persistence root directory on start-up. This is most powerful with file systems which support block cloning, such as ReFS on Windows. This allows even very large state snapshots to be used repeatedly without having to worry about mutating the original dataset on disk. When using ReFS the state copy for even large state directories can be very fast since the duration is primarily proportional to the number of files in the tree rather than the size of the files being cloned. The storage requirements are also minimal as all data will be handled in a copy-on-write manner.
Diffstat (limited to 'src/zencore/filesystem.cpp')
-rw-r--r--src/zencore/filesystem.cpp97
1 files changed, 97 insertions, 0 deletions
diff --git a/src/zencore/filesystem.cpp b/src/zencore/filesystem.cpp
index 06cda7382..4a26c64e7 100644
--- a/src/zencore/filesystem.cpp
+++ b/src/zencore/filesystem.cpp
@@ -613,6 +613,103 @@ CopyFile(std::filesystem::path FromPath, std::filesystem::path ToPath, const Cop
}
void
+CopyTree(std::filesystem::path FromPath, std::filesystem::path ToPath, const CopyFileOptions& Options)
+{
+ // Validate arguments
+
+ if (FromPath.empty() || !std::filesystem::is_directory(FromPath))
+ throw std::runtime_error("invalid CopyTree source directory specified");
+
+ if (ToPath.empty())
+ throw std::runtime_error("no CopyTree target specified");
+
+ if (std::filesystem::exists(ToPath))
+ {
+ if (!std::filesystem::is_directory(ToPath))
+ {
+ throw std::runtime_error(fmt::format("specified CopyTree target '{}' is not a directory", ToPath));
+ }
+ }
+ else
+ {
+ std::filesystem::create_directories(ToPath);
+ }
+
+ struct CopyVisitor : public FileSystemTraversal::TreeVisitor
+ {
+ CopyVisitor(std::filesystem::path InBasePath, zen::CopyFileOptions InCopyOptions) : BasePath(InBasePath), CopyOptions(InCopyOptions)
+ {
+ }
+
+ virtual void VisitFile(const std::filesystem::path& Parent, const path_view& File, uint64_t FileSize) override
+ {
+ std::error_code Ec;
+ const std::filesystem::path Relative = std::filesystem::relative(Parent, BasePath, Ec);
+
+ if (Ec)
+ {
+ FailedFileCount++;
+ }
+ else
+ {
+ const std::filesystem::path FromPath = Parent / File;
+ std::filesystem::path ToPath;
+
+ if (Relative.compare("."))
+ {
+ zen::CreateDirectories(TargetPath / Relative);
+
+ ToPath = TargetPath / Relative / File;
+ }
+ else
+ {
+ ToPath = TargetPath / File;
+ }
+
+ try
+ {
+ if (zen::CopyFile(FromPath, ToPath, CopyOptions))
+ {
+ ++FileCount;
+ ByteCount += FileSize;
+ }
+ else
+ {
+ throw std::runtime_error("CopyFile failed in an unexpected way");
+ }
+ }
+ catch (std::exception& Ex)
+ {
+ ++FailedFileCount;
+
+ throw std::runtime_error(fmt::format("failed to copy '{}' to '{}': '{}'", FromPath, ToPath, Ex.what()));
+ }
+ }
+ }
+
+ virtual bool VisitDirectory(const std::filesystem::path&, const path_view&) override { return true; }
+
+ std::filesystem::path BasePath;
+ std::filesystem::path TargetPath;
+ zen::CopyFileOptions CopyOptions;
+ int FileCount = 0;
+ uint64_t ByteCount = 0;
+ int FailedFileCount = 0;
+ };
+
+ CopyVisitor Visitor{FromPath, Options};
+ Visitor.TargetPath = ToPath;
+
+ FileSystemTraversal Traversal;
+ Traversal.TraverseFileSystem(FromPath, Visitor);
+
+ if (Visitor.FailedFileCount)
+ {
+ throw std::runtime_error(fmt::format("{} file copy operations FAILED", Visitor.FailedFileCount));
+ }
+}
+
+void
WriteFile(std::filesystem::path Path, const IoBuffer* const* Data, size_t BufferCount)
{
#if ZEN_PLATFORM_WINDOWS