diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/buildtool/execution_api/local/TARGETS | 1 | ||||
-rw-r--r-- | src/buildtool/execution_api/local/local_action.cpp | 82 | ||||
-rw-r--r-- | src/buildtool/execution_api/local/local_action.hpp | 10 |
3 files changed, 78 insertions, 15 deletions
diff --git a/src/buildtool/execution_api/local/TARGETS b/src/buildtool/execution_api/local/TARGETS index 64f8bb6e..da3e4432 100644 --- a/src/buildtool/execution_api/local/TARGETS +++ b/src/buildtool/execution_api/local/TARGETS @@ -45,6 +45,7 @@ , ["src/buildtool/logging", "logging"] , ["src/buildtool/execution_api/execution_service", "cas_utils"] , ["src/buildtool/file_system", "git_repo"] + , ["src/utils/cpp", "tmp_dir"] ] , "stage": ["src", "buildtool", "execution_api", "local"] , "private-deps": diff --git a/src/buildtool/execution_api/local/local_action.cpp b/src/buildtool/execution_api/local/local_action.cpp index 060390cb..4b8bc0dc 100644 --- a/src/buildtool/execution_api/local/local_action.cpp +++ b/src/buildtool/execution_api/local/local_action.cpp @@ -19,6 +19,7 @@ #include <filesystem> #include <optional> #include <string> +#include <system_error> #include <utility> #include "src/buildtool/common/bazel_types.hpp" @@ -183,15 +184,25 @@ auto LocalAction::Run(bazel_re::Digest const& action_id) const noexcept return std::nullopt; } -auto LocalAction::StageInput(std::filesystem::path const& target_path, - Artifact::ObjectInfo const& info) const noexcept - -> bool { +auto LocalAction::StageInput( + std::filesystem::path const& target_path, + Artifact::ObjectInfo const& info, + gsl::not_null<LocalAction::FileCopies*> copies) const noexcept -> bool { + static std::string const kCopyFileName{"blob"}; + if (IsTreeObject(info.type)) { return FileSystemManager::CreateDirectory(target_path); } - auto blob_path = - storage_.CAS().BlobPath(info.digest, IsExecutableObject(info.type)); + std::optional<std::filesystem::path> blob_path{}; + + if (auto lookup = copies->find(info); lookup != copies->end()) { + blob_path = lookup->second->GetPath() / kCopyFileName; + } + else { + blob_path = + storage_.CAS().BlobPath(info.digest, IsExecutableObject(info.type)); + } if (not blob_path) { logger_.Emit(LogLevel::Error, @@ -212,12 +223,54 @@ auto LocalAction::StageInput(std::filesystem::path const& target_path, return FileSystemManager::CreateSymlink(*to, target_path); } - return FileSystemManager::CreateDirectory(target_path.parent_path()) and - FileSystemManager::CreateFileHardlink(*blob_path, target_path); + if (not FileSystemManager::CreateDirectory(target_path.parent_path())) { + return false; + } + auto res = FileSystemManager::CreateFileHardlink( + *blob_path, target_path, LogLevel::Debug); + if (res) { + return true; + } + if (res.error() != std::errc::too_many_links) { + logger_.Emit(LogLevel::Warning, + "Failed to link {} to {}: {}, {}", + nlohmann::json(blob_path->string()).dump(), + nlohmann::json(target_path.string()).dump(), + res.error().value(), + res.error().message()); + return false; + } + TmpDirPtr new_copy_dir = storage_config_.CreateTypedTmpDir("blob-copy"); + if (new_copy_dir == nullptr) { + logger_.Emit(LogLevel::Warning, + "Failed to create a temporary directory for a blob copy"); + return false; + } + auto new_copy = new_copy_dir->GetPath() / kCopyFileName; + if (not FileSystemManager::CopyFile( + *blob_path, new_copy, IsExecutableObject(info.type))) { + logger_.Emit(LogLevel::Warning, + "Failed to create a copy of {}", + info.ToString()); + return false; + } + if (not FileSystemManager::CreateFileHardlinkAs<true>( + new_copy, target_path, info.type)) { + return false; + } + try { + copies->insert_or_assign(info, new_copy_dir); + } catch (std::exception const& e) { + logger_.Emit(LogLevel::Warning, + "Failed to update temp-copies map (continuing anyway): {}", + e.what()); + } + return true; } auto LocalAction::StageInputs( - std::filesystem::path const& exec_path) const noexcept -> bool { + std::filesystem::path const& exec_path, + gsl::not_null<LocalAction::FileCopies*> copies) const noexcept -> bool { if (FileSystemManager::IsRelativePath(exec_path)) { return false; } @@ -228,7 +281,7 @@ auto LocalAction::StageInputs( return false; } for (std::size_t i{}; i < result->paths.size(); ++i) { - if (not StageInput(result->paths.at(i), result->infos.at(i))) { + if (not StageInput(result->paths.at(i), result->infos.at(i), copies)) { return false; } } @@ -250,10 +303,13 @@ auto LocalAction::CreateDirectoryStructure( } // stage inputs (files, leaf trees) to execution directory - if (not StageInputs(exec_path)) { - logger_.Emit(LogLevel::Error, - "failed to stage input files to exec_path"); - return false; + { + LocalAction::FileCopies copies{}; + if (not StageInputs(exec_path, &copies)) { + logger_.Emit(LogLevel::Error, + "failed to stage input files to exec_path"); + return false; + } } // create output paths diff --git a/src/buildtool/execution_api/local/local_action.hpp b/src/buildtool/execution_api/local/local_action.hpp index 13f1e4c0..a6c69b29 100644 --- a/src/buildtool/execution_api/local/local_action.hpp +++ b/src/buildtool/execution_api/local/local_action.hpp @@ -19,6 +19,7 @@ #include <map> #include <memory> #include <string> +#include <unordered_map> #include <utility> // std::move #include <vector> @@ -29,6 +30,7 @@ #include "src/buildtool/logging/logger.hpp" #include "src/buildtool/storage/config.hpp" #include "src/buildtool/storage/storage.hpp" +#include "src/utils/cpp/tmp_dir.hpp" class LocalApi; @@ -47,6 +49,8 @@ class LocalAction final : public IExecutionAction { using OutputDirOrSymlink = std::variant<bazel_re::OutputDirectory, bazel_re::OutputSymlink>; + using FileCopies = std::unordered_map<Artifact::ObjectInfo, TmpDirPtr>; + auto Execute(Logger const* logger) noexcept -> IExecutionResponse::Ptr final; @@ -111,7 +115,8 @@ class LocalAction final : public IExecutionAction { [[nodiscard]] auto StageInput( std::filesystem::path const& target_path, - Artifact::ObjectInfo const& info) const noexcept -> bool; + Artifact::ObjectInfo const& info, + gsl::not_null<FileCopies*> copies) const noexcept -> bool; /// \brief Stage input artifacts and leaf trees to the execution directory. /// Stage artifacts and their parent directory structure from CAS to the @@ -119,7 +124,8 @@ class LocalAction final : public IExecutionAction { /// \param[in] exec_path Absolute path to the execution directory. /// \returns Success indicator. [[nodiscard]] auto StageInputs( - std::filesystem::path const& exec_path) const noexcept -> bool; + std::filesystem::path const& exec_path, + gsl::not_null<FileCopies*> copies) const noexcept -> bool; [[nodiscard]] auto CreateDirectoryStructure( std::filesystem::path const& exec_path) const noexcept -> bool; |