summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Cristian Sarbu <paul.cristian.sarbu@huawei.com>2024-10-08 16:57:48 +0200
committerPaul Cristian Sarbu <paul.cristian.sarbu@huawei.com>2024-10-25 13:00:43 +0200
commit30fed59c215e786745c66481bf3ecafb40c2b3be (patch)
treec65e90078a34ca0ff75e0cb14310e5f0ac3d912d
parenta5567a39fc5b73f69c72eb7304fba484c9b049a1 (diff)
downloadjustbuild-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.
-rw-r--r--src/buildtool/serve_api/serve_service/TARGETS6
-rw-r--r--src/buildtool/serve_api/serve_service/serve_server_implementation.cpp42
-rw-r--r--src/buildtool/serve_api/serve_service/source_tree.cpp324
-rw-r--r--src/buildtool/serve_api/serve_service/source_tree.hpp17
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