diff options
Diffstat (limited to 'src')
6 files changed, 128 insertions, 0 deletions
diff --git a/src/buildtool/serve_api/remote/serve_api.hpp b/src/buildtool/serve_api/remote/serve_api.hpp index 0c301ee6..d7fb1c9a 100644 --- a/src/buildtool/serve_api/remote/serve_api.hpp +++ b/src/buildtool/serve_api/remote/serve_api.hpp @@ -125,6 +125,11 @@ class ServeApi final { return stc_.GetRemoteTree(digest); } + [[nodiscard]] auto ComputeTreeStructure(ArtifactDigest const& digest) + const noexcept -> expected<ArtifactDigest, GitLookupError> { + return stc_.ComputeTreeStructure(digest); + } + [[nodiscard]] auto ServeTargetVariables(std::string const& target_root_id, std::string const& target_file, std::string const& target) diff --git a/src/buildtool/serve_api/remote/source_tree_client.cpp b/src/buildtool/serve_api/remote/source_tree_client.cpp index 73114350..bdf3fa57 100644 --- a/src/buildtool/serve_api/remote/source_tree_client.cpp +++ b/src/buildtool/serve_api/remote/source_tree_client.cpp @@ -360,4 +360,41 @@ auto SourceTreeClient::GetRemoteTree( return true; } +auto SourceTreeClient::ComputeTreeStructure(ArtifactDigest const& tree) + const noexcept -> expected<ArtifactDigest, GitLookupError> { + justbuild::just_serve::ComputeTreeStructureRequest request{}; + request.set_tree(tree.hash()); + + grpc::ClientContext context; + justbuild::just_serve::ComputeTreeStructureResponse response; + grpc::Status status = + stub_->ComputeTreeStructure(&context, request, &response); + + if (not status.ok()) { + LogStatus(&logger_, LogLevel::Debug, status); + return unexpected{GitLookupError::Fatal}; + } + if (response.status() != + ::justbuild::just_serve::ComputeTreeStructureResponse::OK) { + logger_.Emit(LogLevel::Debug, + "ComputeTreeStructure response returned with {}", + static_cast<int>(response.status())); + return unexpected{response.status() != + ::justbuild::just_serve:: + ComputeTreeStructureResponse::NOT_FOUND + ? GitLookupError::Fatal + : GitLookupError::NotFound}; + } + // ComputeTreeStructure operates on git digests. + auto digest = ArtifactDigestFactory::Create(HashFunction::Type::GitSHA1, + response.tree_structure_hash(), + /*size_unknown=*/0, + /*is_tree=*/true); + if (not digest) { + logger_.Emit(LogLevel::Debug, std::move(digest).error()); + return unexpected{GitLookupError::Fatal}; + } + return *std::move(digest); +} + #endif // BOOTSTRAP_BUILD_TOOL diff --git a/src/buildtool/serve_api/remote/source_tree_client.hpp b/src/buildtool/serve_api/remote/source_tree_client.hpp index 32fb910c..e6ad6083 100644 --- a/src/buildtool/serve_api/remote/source_tree_client.hpp +++ b/src/buildtool/serve_api/remote/source_tree_client.hpp @@ -133,6 +133,13 @@ class SourceTreeClient { [[nodiscard]] auto GetRemoteTree( ArtifactDigest const& digest) const noexcept -> bool; + /// \brief Compute tree structure of a tree + /// \param tree Tree to compute + /// \return Git digest of the tree structure computed for tree on + /// success or an unexpected error on failure (fatal or content not found). + [[nodiscard]] auto ComputeTreeStructure(ArtifactDigest const& tree) + const noexcept -> expected<ArtifactDigest, GitLookupError>; + private: HashFunction const& hash_function_; // hash function of the remote std::unique_ptr<justbuild::just_serve::SourceTree::Stub> stub_; diff --git a/src/buildtool/serve_api/serve_service/TARGETS b/src/buildtool/serve_api/serve_service/TARGETS index b149c1f4..673553f8 100644 --- a/src/buildtool/serve_api/serve_service/TARGETS +++ b/src/buildtool/serve_api/serve_service/TARGETS @@ -50,6 +50,7 @@ , ["src/buildtool/storage", "garbage_collector"] , ["src/buildtool/storage", "repository_garbage_collector"] , ["src/buildtool/storage", "storage"] + , ["src/buildtool/tree_structure", "tree_structure_utils"] , ["src/utils/archive", "archive_ops"] , ["src/utils/cpp", "file_locking"] , ["src/utils/cpp", "hex_string"] diff --git a/src/buildtool/serve_api/serve_service/source_tree.cpp b/src/buildtool/serve_api/serve_service/source_tree.cpp index ff12baee..8a45365d 100644 --- a/src/buildtool/serve_api/serve_service/source_tree.cpp +++ b/src/buildtool/serve_api/serve_service/source_tree.cpp @@ -44,6 +44,7 @@ #include "src/buildtool/storage/garbage_collector.hpp" #include "src/buildtool/storage/repository_garbage_collector.hpp" #include "src/buildtool/storage/storage.hpp" +#include "src/buildtool/tree_structure/tree_structure_utils.hpp" #include "src/utils/archive/archive_ops.hpp" #include "src/utils/cpp/expected.hpp" #include "src/utils/cpp/file_locking.hpp" @@ -1669,4 +1670,70 @@ auto SourceTreeService::GetRemoteTree( return ::grpc::Status::OK; } +auto SourceTreeService::ComputeTreeStructure( + ::grpc::ServerContext* /*context*/, + const ::justbuild::just_serve::ComputeTreeStructureRequest* request, + ComputeTreeStructureResponse* response) -> ::grpc::Status { + auto repo_lock = RepositoryGarbageCollector::SharedLock( + *native_context_->storage_config); + if (not repo_lock) { + logger_->Emit(LogLevel::Error, "Could not acquire repo gc SharedLock"); + response->set_status(ComputeTreeStructureResponse::INTERNAL_ERROR); + return ::grpc::Status::OK; + } + // ensure Git cache exists + if (auto done = EnsureGitCacheRoot(); not done) { + logger_->Emit(LogLevel::Error, std::move(done).error()); + response->set_status(ComputeTreeStructureResponse::INTERNAL_ERROR); + return ::grpc::Status::OK; + } + // get gc lock for native storage + auto lock = GarbageCollector::SharedLock(*native_context_->storage_config); + if (not lock) { + logger_->Emit(LogLevel::Error, "Could not acquire gc SharedLock"); + response->set_status(ComputeTreeStructureResponse::INTERNAL_ERROR); + return ::grpc::Status::OK; + } + + auto const tree_digest = + ArtifactDigestFactory::Create(HashFunction::Type::GitSHA1, + request->tree(), + /*size_unknown=*/0, + /*is_tree=*/true); + if (not tree_digest) { + logger_->Emit(LogLevel::Error, tree_digest.error()); + response->set_status(ComputeTreeStructureResponse::INTERNAL_ERROR); + return ::grpc::Status::OK; + } + + auto known_repositories = serve_config_.known_repositories; + known_repositories.push_back(native_context_->storage_config->GitRoot()); + + std::optional<ArtifactDigest> tree_structure; + if (auto from_local = TreeStructureUtils::ComputeStructureLocally( + *tree_digest, + known_repositories, + *native_context_->storage_config, + &mutex_)) { + tree_structure = std::move(from_local).value(); + } + else { + // A critical error occurred: + logger_->Emit(LogLevel::Error, std::move(from_local).error()); + response->set_status(ComputeTreeStructureResponse::INTERNAL_ERROR); + return ::grpc::Status::OK; + } + + if (not tree_structure.has_value()) { + logger_->Emit( + LogLevel::Error, "Failed to find {}", tree_digest->hash()); + response->set_status(ComputeTreeStructureResponse::NOT_FOUND); + return ::grpc::Status::OK; + } + + response->set_tree_structure_hash(tree_structure->hash()); + response->set_status(ComputeTreeStructureResponse::OK); + return ::grpc::Status::OK; +} + #endif // BOOTSTRAP_BUILD_TOOL diff --git a/src/buildtool/serve_api/serve_service/source_tree.hpp b/src/buildtool/serve_api/serve_service/source_tree.hpp index 0f58a0a9..ea93cb54 100644 --- a/src/buildtool/serve_api/serve_service/source_tree.hpp +++ b/src/buildtool/serve_api/serve_service/source_tree.hpp @@ -59,6 +59,8 @@ class SourceTreeService final ::justbuild::just_serve::CheckRootTreeResponse; using GetRemoteTreeResponse = ::justbuild::just_serve::GetRemoteTreeResponse; + using ComputeTreeStructureResponse = + ::justbuild::just_serve::ComputeTreeStructureResponse; explicit SourceTreeService( gsl::not_null<RemoteServeConfig const*> const& serve_config, @@ -133,6 +135,15 @@ class SourceTreeService final const ::justbuild::just_serve::GetRemoteTreeRequest* request, GetRemoteTreeResponse* response) -> ::grpc::Status override; + // Compute the tree structure of the given tree and return the Git tree + // identifier of the resulting structure. + // + // There are no method-specific errors. + auto ComputeTreeStructure( + ::grpc::ServerContext* context, + const ::justbuild::just_serve::ComputeTreeStructureRequest* request, + ComputeTreeStructureResponse* response) -> ::grpc::Status override; + private: RemoteServeConfig const& serve_config_; ApiBundle const& apis_; |