diff options
author | Paul Cristian Sarbu <paul.cristian.sarbu@huawei.com> | 2024-10-08 16:57:48 +0200 |
---|---|---|
committer | Paul Cristian Sarbu <paul.cristian.sarbu@huawei.com> | 2024-10-25 13:00:43 +0200 |
commit | 30fed59c215e786745c66481bf3ecafb40c2b3be (patch) | |
tree | c65e90078a34ca0ff75e0cb14310e5f0ac3d912d /src | |
parent | a5567a39fc5b73f69c72eb7304fba484c9b049a1 (diff) | |
download | justbuild-30fed59c215e786745c66481bf3ecafb40c2b3be.tar.gz |
serve service: Give SourceTreeService access to both local storages
...native and compatible, even if currently only native is active.
While there, be more explicit in which storage instance is being
used.
Diffstat (limited to 'src')
4 files changed, 240 insertions, 149 deletions
diff --git a/src/buildtool/serve_api/serve_service/TARGETS b/src/buildtool/serve_api/serve_service/TARGETS index 488b4328..6b5afe1c 100644 --- a/src/buildtool/serve_api/serve_service/TARGETS +++ b/src/buildtool/serve_api/serve_service/TARGETS @@ -24,9 +24,6 @@ , ["src/buildtool/file_system/symlinks_map", "resolve_symlinks_map"] , ["src/buildtool/logging", "logging"] , ["src/buildtool/serve_api/remote", "config"] - , ["src/buildtool/storage", "config"] - , ["src/buildtool/storage", "repository_garbage_collector"] - , ["src/buildtool/storage", "storage"] , ["src/utils/cpp", "expected"] ] , "stage": ["src", "buildtool", "serve_api", "serve_service"] @@ -41,6 +38,7 @@ , ["src/buildtool/logging", "log_level"] , ["src/buildtool/multithreading", "async_map_utils"] , ["src/buildtool/storage", "fs_utils"] + , ["src/buildtool/storage", "repository_garbage_collector"] , ["src/utils/archive", "archive_ops"] ] } @@ -76,6 +74,8 @@ , ["src/buildtool/execution_api/execution_service", "execution_server"] , ["src/buildtool/execution_api/execution_service", "operations_server"] , ["src/buildtool/logging", "log_level"] + , ["src/buildtool/storage", "config"] + , ["src/buildtool/storage", "storage"] ] } , "target_service": diff --git a/src/buildtool/serve_api/serve_service/serve_server_implementation.cpp b/src/buildtool/serve_api/serve_service/serve_server_implementation.cpp index 89b2f68d..f03a21e8 100644 --- a/src/buildtool/serve_api/serve_service/serve_server_implementation.cpp +++ b/src/buildtool/serve_api/serve_service/serve_server_implementation.cpp @@ -43,6 +43,8 @@ #include "src/buildtool/serve_api/serve_service/configuration.hpp" #include "src/buildtool/serve_api/serve_service/source_tree.hpp" #include "src/buildtool/serve_api/serve_service/target.hpp" +#include "src/buildtool/storage/config.hpp" +#include "src/buildtool/storage/storage.hpp" namespace { template <typename T> @@ -114,7 +116,9 @@ auto ServeServerImpl::Run( auto const hash_type = local_context->storage_config->hash_function.GetType(); - SourceTreeService sts{&serve_config, local_context, &apis}; + + // TargetService and ConfigurationService use the default apis, which know + // how to dispatch builds. TargetService ts{&serve_config, local_context, remote_context, @@ -122,6 +126,42 @@ auto ServeServerImpl::Run( serve ? &*serve : nullptr}; ConfigurationService cs{hash_type, remote_context->exec_config}; + // For the SourceTreeService we need to always have access to a native + // storage. In compatible mode, this requires creating a second local + // context, as the default one is compatible. + std::unique_ptr<StorageConfig> secondary_storage_config = nullptr; + std::unique_ptr<Storage> secondary_storage = nullptr; + std::unique_ptr<LocalContext> secondary_local_context = nullptr; + if (not ProtocolTraits::IsNative(hash_type)) { + auto config = + StorageConfig::Builder{} + .SetBuildRoot(local_context->storage_config->build_root) + .SetHashType(HashFunction::Type::GitSHA1) + .Build(); + if (not config) { + Logger::Log(LogLevel::Error, config.error()); + return false; + } + secondary_storage_config = + std::make_unique<StorageConfig>(*std::move(config)); + secondary_storage = std::make_unique<Storage>( + Storage::Create(&*secondary_storage_config)); + secondary_local_context = std::make_unique<LocalContext>( + LocalContext{.exec_config = local_context->exec_config, + .storage_config = &*secondary_storage_config, + .storage = &*secondary_storage}); + } + + SourceTreeService sts{&serve_config, + &apis, + /*native_context=*/secondary_local_context != nullptr + ? &*secondary_local_context + : local_context, + /*compat_context=*/secondary_local_context != nullptr + ? &*local_context + : nullptr}; + + // set up the server grpc::ServerBuilder builder; builder.RegisterService(&sts); diff --git a/src/buildtool/serve_api/serve_service/source_tree.cpp b/src/buildtool/serve_api/serve_service/source_tree.cpp index 5aae6e07..3099de77 100644 --- a/src/buildtool/serve_api/serve_service/source_tree.cpp +++ b/src/buildtool/serve_api/serve_service/source_tree.cpp @@ -200,7 +200,8 @@ auto SourceTreeService::ServeCommitTree( ::grpc::ServerContext* /* context */, const ::justbuild::just_serve::ServeCommitTreeRequest* request, ServeCommitTreeResponse* response) -> ::grpc::Status { - auto repo_lock = RepositoryGarbageCollector::SharedLock(storage_config_); + 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(ServeCommitTreeResponse::INTERNAL_ERROR); @@ -211,14 +212,14 @@ auto SourceTreeService::ServeCommitTree( auto const& subdir{request->subdir()}; // try in local build root Git cache auto res = GetSubtreeFromCommit( - storage_config_.GitRoot(), commit, subdir, logger_); + native_context_->storage_config->GitRoot(), commit, subdir, logger_); if (res) { auto tree_id = *std::move(res); auto status = ServeCommitTreeResponse::OK; if (request->sync_tree()) { status = SyncGitEntryToCas<ObjectType::Tree, ServeCommitTreeResponse>( - tree_id, storage_config_.GitRoot()); + tree_id, native_context_->storage_config->GitRoot()); } *(response->mutable_tree()) = std::move(tree_id); response->set_status(status); @@ -231,7 +232,7 @@ auto SourceTreeService::ServeCommitTree( "repository {}", subdir, commit, - storage_config_.GitRoot().string()); + native_context_->storage_config->GitRoot().string()); response->set_status(ServeCommitTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; } @@ -287,7 +288,8 @@ auto SourceTreeService::SyncGitEntryToCas( std::string const& object_hash, std::filesystem::path const& repo_path) const noexcept -> std::remove_cvref_t<decltype(TResponse::OK)> { - auto const hash_type = storage_config_.hash_function.GetType(); + auto const hash_type = + native_context_->storage_config->hash_function.GetType(); if (IsTreeObject(kType) and not ProtocolTraits::IsTreeAllowed(hash_type)) { logger_->Emit(LogLevel::Error, "Cannot sync tree {} from repository {} with " @@ -333,7 +335,7 @@ auto SourceTreeService::ResolveContentTree( if (resolve_special) { // get the resolved tree auto tree_id_file = StorageUtils::GetResolvedTreeIDFile( - storage_config_, tree_id, *resolve_special); + *native_context_->storage_config, tree_id, *resolve_special); if (FileSystemManager::Exists(tree_id_file)) { // read resolved tree id auto resolved_tree_id = FileSystemManager::ReadFile(tree_id_file); @@ -348,11 +350,12 @@ auto SourceTreeService::ResolveContentTree( *resolved_tree_id, repo_path, sync_tree, response); } // resolve tree; target repository is always the Git cache - auto target_cas = GitCAS::Open(storage_config_.GitRoot()); + auto target_cas = + GitCAS::Open(native_context_->storage_config->GitRoot()); if (not target_cas) { logger_->Emit(LogLevel::Error, "Failed to open Git ODB at {}", - storage_config_.GitRoot().string()); + native_context_->storage_config->GitRoot().string()); response->set_status(ServeArchiveTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; } @@ -415,7 +418,7 @@ auto SourceTreeService::ResolveContentTree( // keep tree alive in the Git cache via a tagged commit auto wrapped_logger = std::make_shared<GitRepo::anon_logger_t>( [logger = logger_, - storage_config = &storage_config_, + storage_config = native_context_->storage_config, resolved_tree](auto const& msg, bool fatal) { if (fatal) { logger->Emit(LogLevel::Error, @@ -429,11 +432,13 @@ auto SourceTreeService::ResolveContentTree( // this is a non-thread-safe Git operation, so it must be guarded! std::shared_lock slock{mutex_}; // open real repository at Git CAS location - auto git_repo = GitRepo::Open(storage_config_.GitRoot()); + auto git_repo = + GitRepo::Open(native_context_->storage_config->GitRoot()); if (not git_repo) { - logger_->Emit(LogLevel::Error, - "Failed to open Git CAS repository {}", - storage_config_.GitRoot().string()); + logger_->Emit( + LogLevel::Error, + "Failed to open Git CAS repository {}", + native_context_->storage_config->GitRoot().string()); response->set_status(ServeArchiveTreeResponse::RESOLVE_ERROR); return ::grpc::Status::OK; } @@ -465,7 +470,8 @@ auto SourceTreeService::CommonImportToGit( std::string const& commit_message) -> expected<std::string, std::string> { // the repository path that imports the content must be separate from the // content path, to avoid polluting the entries - auto tmp_dir = storage_config_.CreateTypedTmpDir("import-repo"); + auto tmp_dir = + native_context_->storage_config->CreateTypedTmpDir("import-repo"); if (not tmp_dir) { return unexpected{ std::string("Failed to create tmp path for import repository")}; @@ -497,20 +503,24 @@ auto SourceTreeService::CommonImportToGit( return unexpected{err}; } // open the Git CAS repo - auto just_git_cas = GitCAS::Open(storage_config_.GitRoot()); + auto just_git_cas = + GitCAS::Open(native_context_->storage_config->GitRoot()); if (not just_git_cas) { - return unexpected{fmt::format("Failed to open Git ODB at {}", - storage_config_.GitRoot().string())}; + return unexpected{ + fmt::format("Failed to open Git ODB at {}", + native_context_->storage_config->GitRoot().string())}; } auto just_git_repo = GitRepo::Open(just_git_cas); if (not just_git_repo) { - return unexpected{fmt::format("Failed to open Git repository {}", - storage_config_.GitRoot().string())}; + return unexpected{ + fmt::format("Failed to open Git repository {}", + native_context_->storage_config->GitRoot().string())}; } // wrap logger for GitRepo call err.clear(); wrapped_logger = std::make_shared<GitRepo::anon_logger_t>( - [&err, storage_config = &storage_config_](auto const& msg, bool fatal) { + [&err, storage_config = native_context_->storage_config]( + auto const& msg, bool fatal) { if (fatal) { err = fmt::format("While fetching in repository {}:\n{}", storage_config->GitRoot().string(), @@ -519,17 +529,18 @@ auto SourceTreeService::CommonImportToGit( }); // fetch the new commit into the Git CAS via tmp directory; the call is // thread-safe, so it needs no guarding - if (not just_git_repo->LocalFetchViaTmpRepo(storage_config_, - repo_path.string(), - /*branch=*/std::nullopt, - wrapped_logger)) { + if (not just_git_repo->LocalFetchViaTmpRepo( + *native_context_->storage_config, + repo_path.string(), + /*branch=*/std::nullopt, + wrapped_logger)) { return unexpected{err}; } // wrap logger for GitRepo call err.clear(); wrapped_logger = std::make_shared<GitRepo::anon_logger_t>( - [commit_hash, storage_config = &storage_config_, &err](auto const& msg, - bool fatal) { + [commit_hash, storage_config = native_context_->storage_config, &err]( + auto const& msg, bool fatal) { if (fatal) { err = fmt::format("While tagging commit {} in repository {}:\n{}", @@ -543,11 +554,12 @@ auto SourceTreeService::CommonImportToGit( // this is a non-thread-safe Git operation, so it must be guarded! std::shared_lock slock{mutex_}; // open real repository at Git CAS location - auto git_repo = GitRepo::Open(storage_config_.GitRoot()); + auto git_repo = + GitRepo::Open(native_context_->storage_config->GitRoot()); if (not git_repo) { - return unexpected{ - fmt::format("Failed to open Git CAS repository {}", - storage_config_.GitRoot().string())}; + return unexpected{fmt::format( + "Failed to open Git CAS repository {}", + native_context_->storage_config->GitRoot().string())}; } // Important: message must be consistent with just-mr! if (not git_repo->KeepTag(*commit_hash, @@ -605,11 +617,12 @@ auto SourceTreeService::ArchiveImportToGit( return ::grpc::Status::OK; } // open the Git CAS repo - auto just_git_cas = GitCAS::Open(storage_config_.GitRoot()); + auto just_git_cas = + GitCAS::Open(native_context_->storage_config->GitRoot()); if (not just_git_cas) { logger_->Emit(LogLevel::Error, "Failed to open Git ODB at {}", - storage_config_.GitRoot().string()); + native_context_->storage_config->GitRoot().string()); response->set_status(ServeArchiveTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; } @@ -617,7 +630,7 @@ auto SourceTreeService::ArchiveImportToGit( if (not just_git_repo) { logger_->Emit(LogLevel::Error, "Failed to open Git repository {}", - storage_config_.GitRoot().string()); + native_context_->storage_config->GitRoot().string()); response->set_status(ServeArchiveTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; } @@ -641,7 +654,7 @@ auto SourceTreeService::ArchiveImportToGit( return ::grpc::Status::OK; } return ResolveContentTree(*subtree_id, - storage_config_.GitRoot(), + native_context_->storage_config->GitRoot(), /*repo_is_git_cache=*/true, resolve_special, sync_tree, @@ -679,7 +692,8 @@ auto SourceTreeService::ServeArchiveTree( ::grpc::ServerContext* /* context */, const ::justbuild::just_serve::ServeArchiveTreeRequest* request, ServeArchiveTreeResponse* response) -> ::grpc::Status { - auto repo_lock = RepositoryGarbageCollector::SharedLock(storage_config_); + 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(ServeArchiveTreeResponse::INTERNAL_ERROR); @@ -694,7 +708,7 @@ auto SourceTreeService::ServeArchiveTree( // check for archive_tree_id_file auto archive_tree_id_file = StorageUtils::GetArchiveTreeIDFile( - storage_config_, archive_type, content); + *native_context_->storage_config, archive_type, content); if (FileSystemManager::Exists(archive_tree_id_file)) { // read archive_tree_id from file tree_id_file auto archive_tree_id = @@ -707,21 +721,25 @@ auto SourceTreeService::ServeArchiveTree( return ::grpc::Status::OK; } // check local build root Git cache - auto res = GetSubtreeFromTree( - storage_config_.GitRoot(), *archive_tree_id, subdir, logger_); + auto res = + GetSubtreeFromTree(native_context_->storage_config->GitRoot(), + *archive_tree_id, + subdir, + logger_); if (res) { - return ResolveContentTree(*res, // tree_id - storage_config_.GitRoot(), - /*repo_is_git_cache=*/true, - resolve_special, - request->sync_tree(), - response); + return ResolveContentTree( + *res, // tree_id + native_context_->storage_config->GitRoot(), + /*repo_is_git_cache=*/true, + resolve_special, + request->sync_tree(), + response); } // check for fatal error if (res.error() == GitLookupError::Fatal) { logger_->Emit(LogLevel::Error, "Failed to open repository {}", - storage_config_.GitRoot().string()); + native_context_->storage_config->GitRoot().string()); response->set_status(ServeArchiveTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; } @@ -754,32 +772,38 @@ auto SourceTreeService::ServeArchiveTree( response->set_status(ServeArchiveTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; } - // acquire lock for CAS - auto lock = GarbageCollector::SharedLock(storage_config_); + // acquire lock for native CAS + auto lock = GarbageCollector::SharedLock(*native_context_->storage_config); if (not lock) { logger_->Emit(LogLevel::Error, "Could not acquire gc SharedLock"); response->set_status(ServeArchiveTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; } - // check if content is in local CAS already + // check if content is in native local CAS already auto const digest = ArtifactDigestFactory::Create( - storage_config_.hash_function.GetType(), content, 0, /*is_tree=*/false); - auto const& cas = storage_.CAS(); + native_context_->storage_config->hash_function.GetType(), + content, + 0, + /*is_tree=*/false); + auto const& native_cas = native_context_->storage->CAS(); auto content_cas_path = - digest ? cas.BlobPath(*digest, /*is_executable=*/false) : std::nullopt; + digest ? native_cas.BlobPath(*digest, /*is_executable=*/false) + : std::nullopt; if (not content_cas_path) { // check if content blob is in Git cache - auto res = GetBlobFromRepo(storage_config_.GitRoot(), content, logger_); + auto res = GetBlobFromRepo( + native_context_->storage_config->GitRoot(), content, logger_); if (res) { - // add to CAS - content_cas_path = StorageUtils::AddToCAS(storage_, *res); + // add to native CAS + content_cas_path = + StorageUtils::AddToCAS(*native_context_->storage, *res); } if (res.error() == GitLookupError::Fatal) { logger_->Emit( LogLevel::Error, "Failed while trying to retrieve content {} from repository {}", content, - storage_config_.GitRoot().string()); + native_context_->storage_config->GitRoot().string()); response->set_status(ServeArchiveTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; } @@ -789,8 +813,9 @@ auto SourceTreeService::ServeArchiveTree( for (auto const& path : serve_config_.known_repositories) { auto res = GetBlobFromRepo(path, content, logger_); if (res) { - // add to CAS - content_cas_path = StorageUtils::AddToCAS(storage_, *res); + // add to native CAS + content_cas_path = + StorageUtils::AddToCAS(*native_context_->storage, *res); if (content_cas_path) { break; } @@ -817,18 +842,21 @@ auto SourceTreeService::ServeArchiveTree( response->set_status(ServeArchiveTreeResponse::NOT_FOUND); return ::grpc::Status::OK; } - // content should now be in CAS - content_cas_path = cas.BlobPath(*digest, /*is_executable=*/false); + // content should now be in native CAS + content_cas_path = + native_cas.BlobPath(*digest, /*is_executable=*/false); if (not content_cas_path) { - logger_->Emit(LogLevel::Error, - "Retrieving content {} from CAS failed unexpectedly", - content); + logger_->Emit( + LogLevel::Error, + "Retrieving content {} from native CAS failed unexpectedly", + content); response->set_status(ServeArchiveTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; } } // extract archive - auto tmp_dir = storage_config_.CreateTypedTmpDir(archive_type); + auto tmp_dir = + native_context_->storage_config->CreateTypedTmpDir(archive_type); if (not tmp_dir) { logger_->Emit( LogLevel::Error, @@ -842,7 +870,7 @@ auto SourceTreeService::ServeArchiveTree( ExtractArchive(*content_cas_path, archive_type, tmp_dir->GetPath()); if (res != std::nullopt) { logger_->Emit(LogLevel::Error, - "Failed to extract archive {} from CAS:\n{}", + "Failed to extract archive {} from native CAS:\n{}", content_cas_path->string(), *res); response->set_status(ServeArchiveTreeResponse::UNPACK_ERROR); @@ -866,7 +894,8 @@ auto SourceTreeService::DistdirImportToGit( content_list, bool sync_tree, ServeDistdirTreeResponse* response) -> ::grpc::Status { - auto repo_lock = RepositoryGarbageCollector::SharedLock(storage_config_); + 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(ServeDistdirTreeResponse::INTERNAL_ERROR); @@ -874,7 +903,8 @@ auto SourceTreeService::DistdirImportToGit( } // create tmp directory for the distdir - auto distdir_tmp_dir = storage_config_.CreateTypedTmpDir("distdir"); + auto distdir_tmp_dir = + native_context_->storage_config->CreateTypedTmpDir("distdir"); if (not distdir_tmp_dir) { logger_->Emit(LogLevel::Error, "Failed to create tmp path for distdir target {}", @@ -883,21 +913,22 @@ auto SourceTreeService::DistdirImportToGit( return ::grpc::Status::OK; } auto const& tmp_path = distdir_tmp_dir->GetPath(); - // link the CAS blobs into the tmp dir - auto const& cas = storage_.CAS(); + // link the native CAS blobs into the tmp dir + auto const& native_cas = native_context_->storage->CAS(); if (not std::all_of( content_list.begin(), content_list.end(), - [&cas, tmp_path](auto const& kv) { + [&native_cas, tmp_path](auto const& kv) { auto const digest = ArtifactDigestFactory::Create( - cas.GetHashFunction().GetType(), + native_cas.GetHashFunction().GetType(), kv.second.first, 0, /*is_tree=*/false); if (not digest) { return false; } - auto content_path = cas.BlobPath(*digest, kv.second.second); + auto content_path = + native_cas.BlobPath(*digest, kv.second.second); if (content_path) { return FileSystemManager::CreateFileHardlink( *content_path, // from: cas_path/content_id @@ -907,7 +938,7 @@ auto SourceTreeService::DistdirImportToGit( return false; })) { logger_->Emit(LogLevel::Error, - "Failed to create links to CAS content {}", + "Failed to create links to native CAS content {}", content_id); response->set_status(ServeDistdirTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; @@ -937,7 +968,7 @@ auto SourceTreeService::DistdirImportToGit( auto status = ServeDistdirTreeResponse::OK; if (sync_tree) { status = SyncGitEntryToCas<ObjectType::Tree, ServeDistdirTreeResponse>( - tree_id, storage_config_.GitRoot()); + tree_id, native_context_->storage_config->GitRoot()); } // set response on success *(response->mutable_tree()) = std::move(tree_id); @@ -949,8 +980,8 @@ auto SourceTreeService::ServeDistdirTree( ::grpc::ServerContext* /* context */, const ::justbuild::just_serve::ServeDistdirTreeRequest* request, ServeDistdirTreeResponse* response) -> ::grpc::Status { - // acquire lock for CAS - auto lock = GarbageCollector::SharedLock(storage_config_); + // acquire lock for native CAS + auto lock = GarbageCollector::SharedLock(*native_context_->storage_config); if (not lock) { logger_->Emit(LogLevel::Error, "Could not acquire gc SharedLock"); response->set_status(ServeDistdirTreeResponse::INTERNAL_ERROR); @@ -960,47 +991,48 @@ auto SourceTreeService::ServeDistdirTree( GitRepo::tree_entries_t entries{}; entries.reserve(request->distfiles().size()); - auto const& cas = storage_.CAS(); + auto const& native_cas = native_context_->storage->CAS(); std::unordered_map<std::string, std::pair<std::string, bool>> content_list{}; content_list.reserve(request->distfiles().size()); bool const is_native = - ProtocolTraits::IsNative(storage_config_.hash_function.GetType()); + ProtocolTraits::IsNative(apis_.hash_function.GetType()); for (auto const& kv : request->distfiles()) { bool blob_found{}; std::string blob_digest; // The digest of the requested distfile, taken // by the hash applicable for our CAS; this // might be different from content, if our CAS - // ist not based on git blob identifiers + // is not based on git blob identifiers // (i.e., if we're not in native mode). auto const& content = kv.content(); // check content blob is known - // first check the local CAS itself, provided it uses the same type - // of identifier + // first check the native local CAS itself, provided it uses the same + // type of identifier auto const digest = ArtifactDigestFactory::Create( - storage_config_.hash_function.GetType(), + native_context_->storage_config->hash_function.GetType(), content, 0, /*is_tree=*/false); if (is_native) { - blob_found = digest and cas.BlobPath(*digest, kv.executable()); + blob_found = + digest and native_cas.BlobPath(*digest, kv.executable()); } if (blob_found) { blob_digest = content; } else { // check local Git cache - auto res = - GetBlobFromRepo(storage_config_.GitRoot(), content, logger_); + auto res = GetBlobFromRepo( + native_context_->storage_config->GitRoot(), content, logger_); if (res) { - // add content to local CAS - auto stored_blob = cas.StoreBlob(*res, kv.executable()); + // add content to native local CAS + auto stored_blob = native_cas.StoreBlob(*res, kv.executable()); if (not stored_blob) { logger_->Emit(LogLevel::Error, "Failed to store content {} from local Git " - "cache to local CAS", + "cache to native local CAS", content); response->set_status( ServeDistdirTreeResponse::INTERNAL_ERROR); @@ -1011,11 +1043,12 @@ auto SourceTreeService::ServeDistdirTree( } else { if (res.error() == GitLookupError::Fatal) { - logger_->Emit(LogLevel::Error, - "Failed while trying to retrieve content {} " - "from repository {}", - content, - storage_config_.GitRoot().string()); + logger_->Emit( + LogLevel::Error, + "Failed while trying to retrieve content {} from " + "repository {}", + content, + native_context_->storage_config->GitRoot().string()); response->set_status( ServeDistdirTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; @@ -1024,14 +1057,16 @@ auto SourceTreeService::ServeDistdirTree( for (auto const& path : serve_config_.known_repositories) { auto res = GetBlobFromRepo(path, content, logger_); if (res) { - // add content to local CAS - auto stored_blob = cas.StoreBlob(*res, kv.executable()); + // add content to native local CAS + auto stored_blob = + native_cas.StoreBlob(*res, kv.executable()); if (not stored_blob) { - logger_->Emit(LogLevel::Error, - "Failed to store content {} from " - "known repository {} to local CAS", - path.string(), - content); + logger_->Emit( + LogLevel::Error, + "Failed to store content {} from known " + "repository {} to native local CAS", + path.string(), + content); response->set_status( ServeDistdirTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; @@ -1056,7 +1091,7 @@ auto SourceTreeService::ServeDistdirTree( // check remote CAS if (is_native and digest and apis_.remote->IsAvailable(*digest)) { - // retrieve content to local CAS + // retrieve content to native local CAS if (not apis_.remote->RetrieveToCas( {Artifact::ObjectInfo{ .digest = *digest, @@ -1066,7 +1101,7 @@ auto SourceTreeService::ServeDistdirTree( *apis_.local)) { logger_->Emit(LogLevel::Error, "Failed to retrieve content {} from " - "remote to local CAS", + "remote to native local CAS", content); response->set_status( ServeDistdirTreeResponse::INTERNAL_ERROR); @@ -1116,21 +1151,22 @@ auto SourceTreeService::ServeDistdirTree( } // get hash from raw_id auto tree_id = ToHexString(tree->first); - // add tree to local CAS - if (not cas.StoreTree(tree->second)) { + // add tree to native local CAS + if (not native_cas.StoreTree(tree->second)) { logger_->Emit(LogLevel::Error, - "Failed to store distdir tree {} to local CAS", + "Failed to store distdir tree {} to native local CAS", tree_id); response->set_status(ServeDistdirTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; } // check if tree is already in Git cache - auto has_tree = IsTreeInRepo(tree_id, storage_config_.GitRoot(), logger_); + auto has_tree = IsTreeInRepo( + tree_id, native_context_->storage_config->GitRoot(), logger_); if (not has_tree) { logger_->Emit(LogLevel::Error, "Failed while checking for tree {} in repository {}", tree_id, - storage_config_.GitRoot().string()); + native_context_->storage_config->GitRoot().string()); response->set_status(ServeDistdirTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; } @@ -1140,7 +1176,7 @@ auto SourceTreeService::ServeDistdirTree( if (request->sync_tree()) { status = SyncGitEntryToCas<ObjectType::Tree, ServeDistdirTreeResponse>( - tree_id, storage_config_.GitRoot()); + tree_id, native_context_->storage_config->GitRoot()); } // set response on success *(response->mutable_tree()) = std::move(tree_id); @@ -1172,7 +1208,7 @@ auto SourceTreeService::ServeDistdirTree( return ::grpc::Status::OK; } } - // otherwise, we import the tree from CAS ourselves + // otherwise, we import the tree from native local CAS ourselves return DistdirImportToGit( tree_id, content_id, content_list, request->sync_tree(), response); } @@ -1183,14 +1219,15 @@ auto SourceTreeService::ServeContent( ServeContentResponse* response) -> ::grpc::Status { auto const& content{request->content()}; // acquire locks - auto repo_lock = RepositoryGarbageCollector::SharedLock(storage_config_); + 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(ServeContentResponse::INTERNAL_ERROR); return ::grpc::Status::OK; } - auto lock = GarbageCollector::SharedLock(storage_config_); + auto lock = GarbageCollector::SharedLock(*native_context_->storage_config); if (not lock) { logger_->Emit(LogLevel::Error, "Could not acquire gc SharedLock"); response->set_status(ServeContentResponse::INTERNAL_ERROR); @@ -1198,11 +1235,12 @@ auto SourceTreeService::ServeContent( } // check if content blob is in Git cache - auto res = GetBlobFromRepo(storage_config_.GitRoot(), content, logger_); + auto res = GetBlobFromRepo( + native_context_->storage_config->GitRoot(), content, logger_); if (res) { auto const status = SyncGitEntryToCas<ObjectType::File, ServeContentResponse>( - content, storage_config_.GitRoot()); + content, native_context_->storage_config->GitRoot()); response->set_status(status); return ::grpc::Status::OK; } @@ -1210,7 +1248,7 @@ auto SourceTreeService::ServeContent( logger_->Emit(LogLevel::Error, "Failed while checking for content {} in repository {}", content, - storage_config_.GitRoot().string()); + native_context_->storage_config->GitRoot().string()); response->set_status(ServeContentResponse::INTERNAL_ERROR); return ::grpc::Status::OK; } @@ -1238,7 +1276,10 @@ auto SourceTreeService::ServeContent( // check also in the local CAS auto const digest = ArtifactDigestFactory::Create( - storage_config_.hash_function.GetType(), content, 0, /*is_tree=*/false); + native_context_->storage_config->hash_function.GetType(), + content, + 0, + /*is_tree=*/false); if (digest and apis_.local->IsAvailable(*digest)) { if (not apis_.local->RetrieveToCas( {Artifact::ObjectInfo{.digest = *digest, @@ -1265,14 +1306,15 @@ auto SourceTreeService::ServeTree( ServeTreeResponse* response) -> ::grpc::Status { auto const& tree_id{request->tree()}; // acquire locks - auto repo_lock = RepositoryGarbageCollector::SharedLock(storage_config_); + 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(ServeTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; } - auto lock = GarbageCollector::SharedLock(storage_config_); + auto lock = GarbageCollector::SharedLock(*native_context_->storage_config); if (not lock) { logger_->Emit(LogLevel::Error, "Could not acquire gc SharedLock"); response->set_status(ServeTreeResponse::INTERNAL_ERROR); @@ -1280,19 +1322,20 @@ auto SourceTreeService::ServeTree( } // check if tree is in Git cache - auto has_tree = IsTreeInRepo(tree_id, storage_config_.GitRoot(), logger_); + auto has_tree = IsTreeInRepo( + tree_id, native_context_->storage_config->GitRoot(), logger_); if (not has_tree) { logger_->Emit(LogLevel::Error, "Failed while checking for tree {} in repository {}", tree_id, - storage_config_.GitRoot().string()); + native_context_->storage_config->GitRoot().string()); response->set_status(ServeTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; } if (*has_tree) { auto const status = SyncGitEntryToCas<ObjectType::Tree, ServeTreeResponse>( - tree_id, storage_config_.GitRoot()); + tree_id, native_context_->storage_config->GitRoot()); response->set_status(status); return ::grpc::Status::OK; } @@ -1316,15 +1359,16 @@ auto SourceTreeService::ServeTree( } } // check also in the local CAS - auto const hash_type = storage_config_.hash_function.GetType(); + auto const hash_type = + native_context_->storage_config->hash_function.GetType(); auto const digest = ArtifactDigestFactory::Create(hash_type, tree_id, 0, /*is_tree=*/true); if (digest and apis_.local->IsAvailable(*digest)) { // upload tree to remote CAS; only possible in native mode if (not ProtocolTraits::IsNative(hash_type)) { logger_->Emit(LogLevel::Error, - "Cannot sync tree {} from local CAS with the remote " - "in compatible mode", + "Cannot sync tree {} from native local CAS with the " + "remote in compatible mode", tree_id); response->set_status(ServeTreeResponse::SYNC_ERROR); return ::grpc::Status::OK; @@ -1334,7 +1378,7 @@ auto SourceTreeService::ServeTree( .type = ObjectType::Tree}}, *apis_.remote)) { logger_->Emit(LogLevel::Error, - "Failed to sync tree {} from local CAS", + "Failed to sync tree {} from native local CAS", tree_id); response->set_status(ServeTreeResponse::SYNC_ERROR); return ::grpc::Status::OK; @@ -1354,26 +1398,28 @@ auto SourceTreeService::CheckRootTree( CheckRootTreeResponse* response) -> ::grpc::Status { auto const& tree_id{request->tree()}; // acquire locks - auto repo_lock = RepositoryGarbageCollector::SharedLock(storage_config_); + 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(CheckRootTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; } - auto lock = GarbageCollector::SharedLock(storage_config_); + auto lock = GarbageCollector::SharedLock(*native_context_->storage_config); if (not lock) { logger_->Emit(LogLevel::Error, "Could not acquire gc SharedLock"); response->set_status(CheckRootTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; } // check first in the Git cache - auto has_tree = IsTreeInRepo(tree_id, storage_config_.GitRoot(), logger_); + auto has_tree = IsTreeInRepo( + tree_id, native_context_->storage_config->GitRoot(), logger_); if (not has_tree) { logger_->Emit(LogLevel::Error, "Failed while checking for tree {} in repository {}", tree_id, - storage_config_.GitRoot().string()); + native_context_->storage_config->GitRoot().string()); response->set_status(CheckRootTreeResponse::INTERNAL_ERROR); return ::grpc::Status::OK; } @@ -1399,14 +1445,17 @@ auto SourceTreeService::CheckRootTree( return ::grpc::Status::OK; } } - // now check in the local CAS + // now check in the native local CAS auto const digest = ArtifactDigestFactory::Create( - storage_config_.hash_function.GetType(), tree_id, 0, /*is_tree=*/true); - if (digest and storage_.CAS().TreePath(*digest)) { + native_context_->storage_config->hash_function.GetType(), + tree_id, + 0, + /*is_tree=*/true); + if (digest and native_context_->storage->CAS().TreePath(*digest)) { // As we currently build only against roots in Git repositories, we need // to move the tree from CAS to local Git storage - auto tmp_dir = - storage_config_.CreateTypedTmpDir("source-tree-check-root-tree"); + auto tmp_dir = native_context_->storage_config->CreateTypedTmpDir( + "source-tree-check-root-tree"); if (not tmp_dir) { logger_->Emit(LogLevel::Error, "Failed to create tmp directory for copying git-tree " @@ -1463,7 +1512,7 @@ auto SourceTreeService::GetRemoteTree( GetRemoteTreeResponse* response) -> ::grpc::Status { auto const& tree_id{request->tree()}; // acquire locks - auto lock = GarbageCollector::SharedLock(storage_config_); + auto lock = GarbageCollector::SharedLock(*native_context_->storage_config); if (not lock) { logger_->Emit(LogLevel::Error, "Could not acquire gc SharedLock"); response->set_status(GetRemoteTreeResponse::INTERNAL_ERROR); @@ -1472,7 +1521,10 @@ auto SourceTreeService::GetRemoteTree( // get tree from remote CAS into tmp dir auto const digest = ArtifactDigestFactory::Create( - storage_config_.hash_function.GetType(), tree_id, 0, /*is_tree=*/true); + native_context_->storage_config->hash_function.GetType(), + tree_id, + 0, + /*is_tree=*/true); if (not digest or not apis_.remote->IsAvailable(*digest)) { logger_->Emit(LogLevel::Error, "Remote CAS does not contain expected tree {}", @@ -1480,8 +1532,8 @@ auto SourceTreeService::GetRemoteTree( response->set_status(GetRemoteTreeResponse::FAILED_PRECONDITION); return ::grpc::Status::OK; } - auto tmp_dir = - storage_config_.CreateTypedTmpDir("source-tree-get-remote-tree"); + auto tmp_dir = native_context_->storage_config->CreateTypedTmpDir( + "source-tree-get-remote-tree"); if (not tmp_dir) { logger_->Emit(LogLevel::Error, "Failed to create tmp directory for copying git-tree {} " diff --git a/src/buildtool/serve_api/serve_service/source_tree.hpp b/src/buildtool/serve_api/serve_service/source_tree.hpp index fb0259f9..7a63bcf9 100644 --- a/src/buildtool/serve_api/serve_service/source_tree.hpp +++ b/src/buildtool/serve_api/serve_service/source_tree.hpp @@ -37,8 +37,6 @@ #include "src/buildtool/file_system/symlinks_map/resolve_symlinks_map.hpp" #include "src/buildtool/logging/logger.hpp" #include "src/buildtool/serve_api/remote/config.hpp" -#include "src/buildtool/storage/config.hpp" -#include "src/buildtool/storage/storage.hpp" #include "src/utils/cpp/expected.hpp" // Service for improved interaction with the target-level cache. @@ -63,12 +61,13 @@ class SourceTreeService final explicit SourceTreeService( gsl::not_null<RemoteServeConfig const*> const& serve_config, - gsl::not_null<LocalContext const*> const& local_context, - gsl::not_null<ApiBundle const*> const& apis) noexcept + gsl::not_null<ApiBundle const*> const& apis, + gsl::not_null<LocalContext const*> const& native_context, + LocalContext const* compat_context = nullptr) noexcept : serve_config_{*serve_config}, - storage_{*local_context->storage}, - storage_config_{*local_context->storage_config}, - apis_{*apis} {} + apis_{*apis}, + native_context_{native_context}, + compat_context_{compat_context} {} // Retrieve the Git-subtree identifier from a given Git commit. // @@ -135,9 +134,9 @@ class SourceTreeService final private: RemoteServeConfig const& serve_config_; - StorageConfig const& storage_config_; - Storage const& storage_; ApiBundle const& apis_; + gsl::not_null<LocalContext const*> native_context_; + LocalContext const* compat_context_; mutable std::shared_mutex mutex_; std::shared_ptr<Logger> logger_{std::make_shared<Logger>("serve-service")}; // symlinks resolver map |