summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/buildtool/execution_api/local/TARGETS1
-rw-r--r--src/buildtool/execution_api/local/local_action.cpp82
-rw-r--r--src/buildtool/execution_api/local/local_action.hpp10
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;