// Copyright 2023 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. #ifndef INCLUDED_SRC_BUILDTOOL_STORAGE_LOCAL_AC_TPP #define INCLUDED_SRC_BUILDTOOL_STORAGE_LOCAL_AC_TPP // IWYU pragma: private, include "src/buildtool/storage/local_ac.hpp" #include //std::ignore #include // std::move #include "fmt/core.h" #include "nlohmann/json.hpp" #include "src/buildtool/common/artifact_digest_factory.hpp" #include "src/buildtool/common/bazel_types.hpp" #include "src/buildtool/logging/log_level.hpp" #include "src/buildtool/storage/local_ac.hpp" template auto LocalAC::StoreResult( ArtifactDigest const& action_id, bazel_re::ActionResult const& result) const noexcept -> bool { auto const cas_key = WriteAction(result); return cas_key.has_value() and WriteActionKey(action_id, *cas_key); } template auto LocalAC::CachedResult(ArtifactDigest const& action_id) const noexcept -> std::optional { auto const cas_key = ReadActionKey(action_id); if (not cas_key) { logger_->Emit(LogLevel::Debug, cas_key.error()); return std::nullopt; } auto result = ReadAction(*cas_key); if (not result) { logger_->Emit(LogLevel::Warning, "Parsing action result failed for action {}", action_id.hash()); return std::nullopt; } return std::move(result); } template template requires(kIsLocalGeneration) auto LocalAC::LocalUplinkEntry( LocalGenerationAC const& latest, ArtifactDigest const& action_id) const noexcept -> bool { // Determine action cache key path in latest generation. if (FileSystemManager::IsFile( latest.file_store_.GetPath(action_id.hash()))) { return true; } // Read cache key auto const cas_key = ReadActionKey(action_id); if (not cas_key) { return false; } // Read result (cache value) auto const result = ReadAction(*cas_key); if (not result) { return false; } // Uplink result content for (auto const& file : result->output_files()) { auto const digest = ArtifactDigestFactory::FromBazel( cas_.GetHashFunction().GetType(), file.digest()); if (not digest) { return false; } if (not cas_.LocalUplinkBlob( latest.cas_, *digest, file.is_executable())) { return false; } } for (auto const& link : result->output_file_symlinks()) { if (not cas_.LocalUplinkBlob( latest.cas_, ArtifactDigestFactory::HashDataAs( cas_.GetHashFunction(), link.target()), /*is_executable=*/false)) { return false; } } for (auto const& link : result->output_directory_symlinks()) { if (not cas_.LocalUplinkBlob( latest.cas_, ArtifactDigestFactory::HashDataAs( cas_.GetHashFunction(), link.target()), /*is_executable=*/false)) { return false; } } for (auto const& directory : result->output_directories()) { auto const digest = ArtifactDigestFactory::FromBazel( cas_.GetHashFunction().GetType(), directory.tree_digest()); if (not digest) { return false; } if (not cas_.LocalUplinkTree(latest.cas_, *digest)) { return false; } } // Uplink result (cache value) if (not cas_.LocalUplinkBlob(latest.cas_, *cas_key, /*is_executable=*/false)) { return false; } auto const ac_entry_path = file_store_.GetPath(action_id.hash()); // Uplink cache key return latest.file_store_.AddFromFile(action_id.hash(), ac_entry_path, /*is_owner=*/true); } template auto LocalAC::WriteActionKey( ArtifactDigest const& action_id, ArtifactDigest const& cas_key) const noexcept -> bool { nlohmann::json const content = {cas_key.hash(), cas_key.size()}; return file_store_.AddFromBytes(action_id.hash(), content.dump()); } template auto LocalAC::ReadActionKey(ArtifactDigest const& action_id) const noexcept -> expected { auto const key_path = file_store_.GetPath(action_id.hash()); if constexpr (kDoGlobalUplink) { // Uplink any existing action-cache entries in storage generations std::ignore = uplinker_.UplinkActionCacheEntry(action_id); } auto const key_content = FileSystemManager::ReadFile(key_path, ObjectType::File); if (not key_content) { return unexpected{ fmt::format("Cache miss, entry not found {}", key_path.string())}; } try { nlohmann::json const j = nlohmann::json::parse(*key_content); return ArtifactDigestFactory::Create(cas_.GetHashFunction().GetType(), j[0].template get(), j[1].template get(), /*is_tree=*/false); } catch (...) { return unexpected{fmt::format( "Parsing cache entry failed for action {}", action_id.hash())}; } } template auto LocalAC::WriteAction(bazel_re::ActionResult const& action) const noexcept -> std::optional { return cas_.StoreBlob(action.SerializeAsString(), /*is_executable=*/false); } template auto LocalAC::ReadAction(ArtifactDigest const& cas_key) const noexcept -> std::optional { auto const action_path = cas_.BlobPath(cas_key, /*is_executable=*/false); if (not action_path) { return std::nullopt; } auto const action_content = FileSystemManager::ReadFile(*action_path); if (not action_content) { return std::nullopt; } bazel_re::ActionResult action{}; if (action.ParseFromString(*action_content)) { return action; } return std::nullopt; } #endif // INCLUDED_SRC_BUILDTOOL_STORAGE_LOCAL_AC_TPP