summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKlaus Aehlig <klaus.aehlig@huawei.com>2024-07-04 13:26:00 +0200
committerKlaus Aehlig <klaus.aehlig@huawei.com>2024-07-05 15:22:36 +0200
commitd96d56340883ecad0767139638cd10872d867acc (patch)
tree8861ad9637ec356b18a4f8373ff06f177e3e526b /src
parentabe2c89fc0e4f41f00aca3510e9bb4902e52c9e7 (diff)
downloadjustbuild-d96d56340883ecad0767139638cd10872d867acc.tar.gz
local action: copy input file on reaching symlink limit
... and continue with the newly created copy as target for the next hard links. In this way, we get rid of the restriction we used to have that the number of identical inputs be not greater than the hardlink limit.
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;