// Copyright 2024 Huawei Cloud Computing Technology Co., Ltd. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "src/buildtool/execution_api/serve/mr_local_api.hpp" #include #include #include "src/buildtool/common/protocol_traits.hpp" #include "src/buildtool/execution_api/utils/rehash_utils.hpp" #include "src/buildtool/logging/log_level.hpp" #include "src/buildtool/logging/logger.hpp" #include "src/buildtool/storage/config.hpp" #include "src/utils/cpp/expected.hpp" MRLocalApi::MRLocalApi( gsl::not_null const& native_context, gsl::not_null const& native_local_api, LocalContext const* compatible_context, IExecutionApi const* compatible_local_api) noexcept : native_context_{native_context}, compat_context_{compatible_context}, native_local_api_{native_local_api}, compat_local_api_{compatible_local_api} {} auto MRLocalApi::RetrieveToPaths( std::vector const& artifacts_info, std::vector const& output_paths, IExecutionApi const* /*alternative*/) const noexcept -> bool { // This method can legitimately be called with both native and // compatible digests when in compatible mode, therefore we need to // interrogate the hash type of the input. // we need at least one digest to interrogate the hash type if (artifacts_info.empty()) { return true; // nothing to do } // native artifacts get dispatched to native local api if (ProtocolTraits::IsNative(artifacts_info[0].digest.GetHashType())) { return native_local_api_->RetrieveToPaths(artifacts_info, output_paths); } // compatible digests get dispatched to compatible local api if (compat_local_api_ == nullptr) { Logger::Log(LogLevel::Error, "MRLocalApi: Unexpected digest type provided"); return false; } return compat_local_api_->RetrieveToPaths(artifacts_info, output_paths); } auto MRLocalApi::RetrieveToCas( std::vector const& artifacts_info, IExecutionApi const& api) const noexcept -> bool { // return immediately if being passed the same api if (this == &api) { return true; } // in native mode: dispatch directly to native local api if (compat_local_api_ == nullptr) { return native_local_api_->RetrieveToCas(artifacts_info, api); } // in compatible mode: if compatible hashes passed, dispatch them to // compatible local api if (not artifacts_info.empty() and not ProtocolTraits::IsNative(artifacts_info[0].digest.GetHashType())) { return compat_local_api_->RetrieveToCas(artifacts_info, api); } auto compat_artifacts = RehashUtils::RehashDigest( artifacts_info, *native_context_->storage_config, *compat_context_->storage_config, /*apis=*/std::nullopt); // all parts of git trees are present locally if (not compat_artifacts) { Logger::Log(LogLevel::Error, "MRLocalApi: {}", std::move(compat_artifacts).error()); return false; } return compat_local_api_->RetrieveToCas(*compat_artifacts, api); } auto MRLocalApi::Upload(std::unordered_set&& blobs, bool skip_find_missing) const noexcept -> bool { // in native mode, dispatch to native local api if (compat_local_api_ == nullptr) { return native_local_api_->Upload(std::move(blobs), skip_find_missing); } // in compatible mode, dispatch to compatible local api return compat_local_api_->Upload(std::move(blobs), skip_find_missing); } auto MRLocalApi::IsAvailable(ArtifactDigest const& digest) const noexcept -> bool { // This method can legitimately be called with both native and // compatible digests when in compatible mode, therefore we need to // interrogate the hash type of the input. // a native digest gets dispatched to native local api if (ProtocolTraits::IsNative(digest.GetHashType())) { return native_local_api_->IsAvailable(digest); } // compatible digests get dispatched to compatible local api if (compat_local_api_ == nullptr) { Logger::Log(LogLevel::Warning, "MRLocalApi: unexpected digest type provided"); return false; } return compat_local_api_->IsAvailable(digest); } auto MRLocalApi::GetMissingDigests( std::unordered_set const& digests) const noexcept -> std::unordered_set { // This method can legitimately be called with both native and // compatible digests when in compatible mode, therefore we need to // interrogate the hash type of the input. // we need at least one digest to interrogate the hash type if (digests.empty()) { return {}; // nothing to do } // native digests get dispatched to native local api if (ProtocolTraits::IsNative(digests.begin()->GetHashType())) { return native_local_api_->GetMissingDigests(digests); } // compatible digests get dispatched to compatible local api if (compat_local_api_ == nullptr) { Logger::Log(LogLevel::Warning, "MRLocalApi: Unexpected digest type provided"); return {}; } return compat_local_api_->GetMissingDigests(digests); } auto MRLocalApi::GetHashType() const noexcept -> HashFunction::Type { return compat_local_api_ == nullptr ? native_local_api_->GetHashType() : compat_local_api_->GetHashType(); } auto MRLocalApi::GetTempSpace() const noexcept -> TmpDir::Ptr { return native_local_api_->GetTempSpace(); }