summaryrefslogtreecommitdiff
path: root/src/buildtool/execution_api
diff options
context:
space:
mode:
Diffstat (limited to 'src/buildtool/execution_api')
-rw-r--r--src/buildtool/execution_api/common/local_tree_map.hpp4
-rw-r--r--src/buildtool/execution_api/local/TARGETS1
-rw-r--r--src/buildtool/execution_api/local/local_action.cpp71
-rw-r--r--src/buildtool/execution_api/local/local_api.hpp14
-rw-r--r--src/buildtool/execution_api/local/local_storage.cpp113
-rw-r--r--src/buildtool/execution_api/local/local_storage.hpp17
6 files changed, 168 insertions, 52 deletions
diff --git a/src/buildtool/execution_api/common/local_tree_map.hpp b/src/buildtool/execution_api/common/local_tree_map.hpp
index 77de2d53..2758c339 100644
--- a/src/buildtool/execution_api/common/local_tree_map.hpp
+++ b/src/buildtool/execution_api/common/local_tree_map.hpp
@@ -11,7 +11,9 @@
#include "src/buildtool/common/artifact.hpp"
#include "src/buildtool/logging/logger.hpp"
-/// \brief Maps digest of `bazel_re::Directory` to `LocalTree`.
+/// \brief Maps `bazel_re::Digest` to `LocalTree`.
+/// Digest may refer to `bazel_re::Directory` or Git tree object, depending on
+/// mode being compatible or native, respectively.
class LocalTreeMap {
/// \brief Thread-safe pool of unique object infos.
class ObjectInfoPool {
diff --git a/src/buildtool/execution_api/local/TARGETS b/src/buildtool/execution_api/local/TARGETS
index e395f7d2..4af36d70 100644
--- a/src/buildtool/execution_api/local/TARGETS
+++ b/src/buildtool/execution_api/local/TARGETS
@@ -29,6 +29,7 @@
, ["src/buildtool/execution_api/bazel_msg", "bazel_msg_factory"]
, ["src/buildtool/file_system", "file_system_manager"]
, ["src/buildtool/file_system", "object_type"]
+ , ["src/buildtool/compatibility", "compatibility"]
, ["src/buildtool/system", "system_command"]
, ["src/buildtool/logging", "logging"]
]
diff --git a/src/buildtool/execution_api/local/local_action.cpp b/src/buildtool/execution_api/local/local_action.cpp
index 3ccc58eb..331aaaa5 100644
--- a/src/buildtool/execution_api/local/local_action.cpp
+++ b/src/buildtool/execution_api/local/local_action.cpp
@@ -235,26 +235,59 @@ auto LocalAction::CollectOutputDir(std::filesystem::path const& exec_path,
Logger::Log(LogLevel::Error, "expected directory at {}", local_path);
return std::nullopt;
}
- auto digest = BazelMsgFactory::CreateDirectoryDigestFromLocalTree(
- dir_path,
- [this](auto path, auto is_exec) {
- return storage_->StoreBlob</*kOwner=*/true>(path, is_exec);
- },
- [this](auto bytes, auto dir) -> std::optional<bazel_re::Digest> {
- auto digest = storage_->StoreBlob(bytes);
- if (digest and not tree_map_->HasTree(*digest)) {
- auto tree = tree_map_->CreateTree();
- if (not BazelMsgFactory::ReadObjectInfosFromDirectory(
- dir,
- [&tree](auto path, auto info) {
- return tree.AddInfo(path, info);
- }) or
- not tree_map_->AddTree(*digest, std::move(tree))) {
- return std::nullopt;
+ std::optional<bazel_re::Digest> digest{std::nullopt};
+ if (Compatibility::IsCompatible()) {
+ digest = BazelMsgFactory::CreateDirectoryDigestFromLocalTree(
+ dir_path,
+ [this](auto path, auto is_exec) {
+ return storage_->StoreBlob</*kOwner=*/true>(path, is_exec);
+ },
+ [this](auto bytes, auto dir) -> std::optional<bazel_re::Digest> {
+ auto digest = storage_->StoreBlob(bytes);
+ if (digest and not tree_map_->HasTree(*digest)) {
+ auto tree = tree_map_->CreateTree();
+ if (not BazelMsgFactory::ReadObjectInfosFromDirectory(
+ dir,
+ [&tree](auto path, auto info) {
+ return tree.AddInfo(path, info);
+ }) or
+ not tree_map_->AddTree(*digest, std::move(tree))) {
+ return std::nullopt;
+ }
}
- }
- return digest;
- });
+ return digest;
+ });
+ }
+ else {
+ digest = BazelMsgFactory::CreateGitTreeDigestFromLocalTree(
+ dir_path,
+ [this](auto path, auto is_exec) {
+ return storage_->StoreBlob</*kOwner=*/true>(path, is_exec);
+ },
+ [this](auto bytes,
+ auto entries) -> std::optional<bazel_re::Digest> {
+ auto digest = storage_->StoreTree(bytes);
+ if (digest and not tree_map_->HasTree(*digest)) {
+ auto tree = tree_map_->CreateTree();
+ for (auto const& [raw_id, es] : entries) {
+ auto id = ToHexString(raw_id);
+ for (auto const& entry : es) {
+ auto info = Artifact::ObjectInfo{
+ ArtifactDigest{
+ id, 0, entry.type == ObjectType::Tree},
+ entry.type};
+ if (not tree.AddInfo(entry.name, info)) {
+ return std::nullopt;
+ }
+ }
+ }
+ if (not tree_map_->AddTree(*digest, std::move(tree))) {
+ return std::nullopt;
+ }
+ }
+ return digest;
+ });
+ }
if (digest) {
auto out_dir = bazel_re::OutputDirectory{};
out_dir.set_path(local_path);
diff --git a/src/buildtool/execution_api/local/local_api.hpp b/src/buildtool/execution_api/local/local_api.hpp
index c1cb1c57..1a43fe4b 100644
--- a/src/buildtool/execution_api/local/local_api.hpp
+++ b/src/buildtool/execution_api/local/local_api.hpp
@@ -7,6 +7,7 @@
#include <vector>
#include "gsl-lite/gsl-lite.hpp"
+#include "src/buildtool/compatibility/native_support.hpp"
#include "src/buildtool/execution_api/bazel_msg/bazel_blob.hpp"
#include "src/buildtool/execution_api/common/execution_api.hpp"
#include "src/buildtool/execution_api/common/local_tree_map.hpp"
@@ -75,7 +76,7 @@ class LocalApi final : public IExecutionApi {
[[nodiscard]] auto RetrieveToFds(
std::vector<Artifact::ObjectInfo> const& artifacts_info,
std::vector<int> const& fds,
- bool /*raw_tree*/) noexcept -> bool final {
+ bool raw_tree) noexcept -> bool final {
if (artifacts_info.size() != fds.size()) {
Logger::Log(LogLevel::Error,
"different number of digests and file descriptors.");
@@ -87,7 +88,8 @@ class LocalApi final : public IExecutionApi {
auto const& info = artifacts_info[i];
if (gsl::owner<FILE*> out = fdopen(fd, "wb")) { // NOLINT
- auto const success = storage_->DumpToStream(info, out);
+ auto const success =
+ storage_->DumpToStream(info, out, raw_tree);
std::fclose(out);
if (not success) {
Logger::Log(LogLevel::Error,
@@ -112,7 +114,9 @@ class LocalApi final : public IExecutionApi {
bool /*skip_find_missing*/) noexcept
-> bool final {
for (auto const& blob : blobs) {
- auto cas_digest = storage_->StoreBlob(blob.data);
+ auto const is_tree = NativeSupport::IsTree(blob.digest.hash());
+ auto cas_digest = is_tree ? storage_->StoreTree(blob.data)
+ : storage_->StoreBlob(blob.data);
if (not cas_digest or not std::equal_to<bazel_re::Digest>{}(
*cas_digest, blob.digest)) {
return false;
@@ -148,7 +152,9 @@ class LocalApi final : public IExecutionApi {
[[nodiscard]] auto IsAvailable(ArtifactDigest const& digest) const noexcept
-> bool final {
- return storage_->BlobPath(digest, false).has_value();
+ return static_cast<bool>(digest.is_tree()
+ ? storage_->TreePath(digest)
+ : storage_->BlobPath(digest, false));
}
[[nodiscard]] auto IsAvailable(std::vector<ArtifactDigest> const& digests)
diff --git a/src/buildtool/execution_api/local/local_storage.cpp b/src/buildtool/execution_api/local/local_storage.cpp
index 5e4115df..e6d9571c 100644
--- a/src/buildtool/execution_api/local/local_storage.cpp
+++ b/src/buildtool/execution_api/local/local_storage.cpp
@@ -17,15 +17,46 @@ namespace {
return std::nullopt;
}
+[[nodiscard]] auto ReadGitTree(
+ gsl::not_null<LocalStorage const*> const& storage,
+ bazel_re::Digest const& digest) noexcept
+ -> std::optional<GitCAS::tree_entries_t> {
+ if (auto const path = storage->TreePath(digest)) {
+ if (auto const content = FileSystemManager::ReadFile(*path)) {
+ return GitCAS::ReadTreeData(
+ *content,
+ HashFunction::ComputeTreeHash(*content).Bytes(),
+ /*is_hex_id=*/false);
+ }
+ }
+ Logger::Log(LogLevel::Error, "Tree {} not found in CAS", digest.hash());
+ return std::nullopt;
+}
+
+[[nodiscard]] auto DumpToStream(gsl::not_null<FILE*> const& stream,
+ std::optional<std::string> const& data) noexcept
+ -> bool {
+ if (data) {
+ std::fwrite(data->data(), 1, data->size(), stream);
+ return true;
+ }
+ return false;
+}
+
[[nodiscard]] auto TreeToStream(
gsl::not_null<LocalStorage const*> const& storage,
bazel_re::Digest const& tree_digest,
gsl::not_null<FILE*> const& stream) noexcept -> bool {
- if (auto dir = ReadDirectory(storage, tree_digest)) {
- if (auto data = BazelMsgFactory::DirectoryToString(*dir)) {
- auto const& str = *data;
- std::fwrite(str.data(), 1, str.size(), stream);
- return true;
+ if (Compatibility::IsCompatible()) {
+ if (auto dir = ReadDirectory(storage, tree_digest)) {
+ return DumpToStream(stream,
+ BazelMsgFactory::DirectoryToString(*dir));
+ }
+ }
+ else {
+ if (auto entries = ReadGitTree(storage, tree_digest)) {
+ return DumpToStream(stream,
+ BazelMsgFactory::GitTreeToString(*entries));
}
}
return false;
@@ -36,8 +67,13 @@ namespace {
Artifact::ObjectInfo const& blob_info,
gsl::not_null<FILE*> const& stream) noexcept -> bool {
constexpr std::size_t kChunkSize{512};
- if (auto const path = storage->BlobPath(
- blob_info.digest, IsExecutableObject(blob_info.type))) {
+ auto path =
+ storage->BlobPath(blob_info.digest, IsExecutableObject(blob_info.type));
+ if (not path and not Compatibility::IsCompatible()) {
+ // in native mode, lookup object in tree cas to dump tree as blob
+ path = storage->TreePath(blob_info.digest);
+ }
+ if (path) {
std::string data(kChunkSize, '\0');
if (gsl::owner<FILE*> in = std::fopen(path->c_str(), "rb")) {
while (auto size = std::fread(data.data(), 1, kChunkSize, in)) {
@@ -103,26 +139,53 @@ auto LocalStorage::ReadObjectInfosRecursively(
}
// fallback read from CAS and cache it in in-memory tree map
- if (auto dir = ReadDirectory(this, digest)) {
- auto tree = tree_map_ ? std::make_optional(tree_map_->CreateTree())
- : std::nullopt;
- return BazelMsgFactory::ReadObjectInfosFromDirectory(
- *dir,
- [this, &store_info, &parent, &tree](auto path, auto info) {
- return (not tree or tree->AddInfo(path, info)) and
- (IsTreeObject(info.type)
- ? ReadObjectInfosRecursively(
- store_info, parent / path, info.digest)
- : store_info(parent / path, info));
- }) and
- (not tree_map_ or tree_map_->AddTree(digest, std::move(*tree)));
+ if (Compatibility::IsCompatible()) {
+ if (auto dir = ReadDirectory(this, digest)) {
+ auto tree = tree_map_ ? std::make_optional(tree_map_->CreateTree())
+ : std::nullopt;
+ return BazelMsgFactory::ReadObjectInfosFromDirectory(
+ *dir,
+ [this, &store_info, &parent, &tree](auto path,
+ auto info) {
+ return (not tree or tree->AddInfo(path, info)) and
+ (IsTreeObject(info.type)
+ ? ReadObjectInfosRecursively(
+ store_info,
+ parent / path,
+ info.digest)
+ : store_info(parent / path, info));
+ }) and
+ (not tree_map_ or
+ tree_map_->AddTree(digest, std::move(*tree)));
+ }
+ }
+ else {
+ if (auto entries = ReadGitTree(this, digest)) {
+ auto tree = tree_map_ ? std::make_optional(tree_map_->CreateTree())
+ : std::nullopt;
+ return BazelMsgFactory::ReadObjectInfosFromGitTree(
+ *entries,
+ [this, &store_info, &parent, &tree](auto path,
+ auto info) {
+ return (not tree or tree->AddInfo(path, info)) and
+ (IsTreeObject(info.type)
+ ? ReadObjectInfosRecursively(
+ store_info,
+ parent / path,
+ info.digest)
+ : store_info(parent / path, info));
+ }) and
+ (not tree_map_ or
+ tree_map_->AddTree(digest, std::move(*tree)));
+ }
}
return false;
}
-auto LocalStorage::DumpToStream(
- Artifact::ObjectInfo const& info,
- gsl::not_null<FILE*> const& stream) const noexcept -> bool {
- return IsTreeObject(info.type) ? TreeToStream(this, info.digest, stream)
- : BlobToStream(this, info, stream);
+auto LocalStorage::DumpToStream(Artifact::ObjectInfo const& info,
+ gsl::not_null<FILE*> const& stream,
+ bool raw_tree) const noexcept -> bool {
+ return IsTreeObject(info.type) and not raw_tree
+ ? TreeToStream(this, info.digest, stream)
+ : BlobToStream(this, info, stream);
}
diff --git a/src/buildtool/execution_api/local/local_storage.hpp b/src/buildtool/execution_api/local/local_storage.hpp
index 4560a859..4ffe2881 100644
--- a/src/buildtool/execution_api/local/local_storage.hpp
+++ b/src/buildtool/execution_api/local/local_storage.hpp
@@ -43,6 +43,11 @@ class LocalStorage {
: cas_file_.StoreBlobFromBytes(bytes);
}
+ [[nodiscard]] auto StoreTree(std::string const& bytes) const noexcept
+ -> std::optional<bazel_re::Digest> {
+ return cas_tree_.StoreBlobFromBytes(bytes);
+ }
+
/// \brief Obtain blob path from digest with x-bit.
/// NOLINTNEXTLINE(misc-no-recursion)
[[nodiscard]] auto BlobPath(bazel_re::Digest const& digest,
@@ -53,6 +58,11 @@ class LocalStorage {
return path ? path : TrySyncBlob(digest, is_executable);
}
+ [[nodiscard]] auto TreePath(bazel_re::Digest const& digest) const noexcept
+ -> std::optional<std::filesystem::path> {
+ return cas_tree_.BlobPath(digest);
+ }
+
[[nodiscard]] auto StoreActionResult(
bazel_re::Digest const& action_id,
bazel_re::ActionResult const& result) const noexcept -> bool {
@@ -70,13 +80,14 @@ class LocalStorage {
-> std::optional<std::pair<std::vector<std::filesystem::path>,
std::vector<Artifact::ObjectInfo>>>;
- [[nodiscard]] auto DumpToStream(
- Artifact::ObjectInfo const& info,
- gsl::not_null<FILE*> const& stream) const noexcept -> bool;
+ [[nodiscard]] auto DumpToStream(Artifact::ObjectInfo const& info,
+ gsl::not_null<FILE*> const& stream,
+ bool raw_tree) const noexcept -> bool;
private:
LocalCAS<ObjectType::File> cas_file_{};
LocalCAS<ObjectType::Executable> cas_exec_{};
+ LocalCAS<ObjectType::Tree> cas_tree_{};
LocalAC ac_{&cas_file_};
std::shared_ptr<LocalTreeMap> tree_map_;