diff options
author | Maksim Denisov <denisov.maksim@huawei.com> | 2024-11-29 16:27:00 +0100 |
---|---|---|
committer | Maksim Denisov <denisov.maksim@huawei.com> | 2024-12-02 11:04:20 +0100 |
commit | 0dc8ddb40878115a58c520476f11f02ff352210c (patch) | |
tree | f24f392b1fb4cabab3f9a698631bc6506a33d52a /src/buildtool/file_system/git_repo.cpp | |
parent | e5df21209e665f03b57cfaa83707e30e14012097 (diff) | |
download | justbuild-0dc8ddb40878115a58c520476f11f02ff352210c.tar.gz |
Synchronize initialization of a git repo across processes
Diffstat (limited to 'src/buildtool/file_system/git_repo.cpp')
-rw-r--r-- | src/buildtool/file_system/git_repo.cpp | 52 |
1 files changed, 29 insertions, 23 deletions
diff --git a/src/buildtool/file_system/git_repo.cpp b/src/buildtool/file_system/git_repo.cpp index 0ad5048c..2d4110a1 100644 --- a/src/buildtool/file_system/git_repo.cpp +++ b/src/buildtool/file_system/git_repo.cpp @@ -34,6 +34,7 @@ #include "src/buildtool/file_system/git_context.hpp" #include "src/buildtool/logging/log_level.hpp" #include "src/buildtool/logging/logger.hpp" +#include "src/utils/cpp/file_locking.hpp" #include "src/utils/cpp/hex_string.hpp" #include "src/utils/cpp/path.hpp" #include "src/utils/cpp/tmp_dir.hpp" @@ -525,40 +526,45 @@ auto GitRepo::InitAndOpen(std::filesystem::path const& repo_path, GitContext::Create(); // initialize libgit2 - // check if init is actually needed - if (git_repository_open_ext(nullptr, - repo_path.c_str(), - GIT_REPOSITORY_OPEN_NO_SEARCH, - nullptr) == 0) { - return GitRepo(repo_path); // success - } - git_repository* tmp_repo{nullptr}; - std::size_t max_attempts = kGitLockNumTries; // number of tries int err = 0; std::string err_mess{}; - while (max_attempts > 0) { - --max_attempts; - err = git_repository_init(&tmp_repo, - repo_path.c_str(), - static_cast<std::size_t>(is_bare)); + for (auto attempt = 0U; attempt < kGitLockNumTries; ++attempt) { + // check if init is needed or has already happened in another + // process + if (git_repository_open_ext(nullptr, + repo_path.c_str(), + GIT_REPOSITORY_OPEN_NO_SEARCH, + nullptr) == 0) { + return GitRepo(repo_path); // success + } + + // Initialization must be guarded across processes trying to + // initialize the same repo. + if (auto const lock_file = LockFile::Acquire( + repo_path.parent_path() / "init_open.lock", + /*is_shared=*/false)) { + err = git_repository_init(&tmp_repo, + repo_path.c_str(), + static_cast<std::size_t>(is_bare)); + } + else { + Logger::Log(LogLevel::Error, + "initializing git repository {} failed to " + "acquire lock."); + return std::nullopt; + } + if (err == 0) { git_repository_free(tmp_repo); return GitRepo(repo_path); // success } - err_mess = GitLastError(); // store last error message + err_mess = GitLastError(); // store last error message + git_repository_free(tmp_repo); // cleanup before next attempt // only retry if failure is due to locking if (err != GIT_ELOCKED) { break; } - git_repository_free(tmp_repo); // cleanup before next attempt - // check if init hasn't already happened in another process - if (git_repository_open_ext(nullptr, - repo_path.c_str(), - GIT_REPOSITORY_OPEN_NO_SEARCH, - nullptr) == 0) { - return GitRepo(repo_path); // success - } // repo still not created, so sleep and try again std::this_thread::sleep_for( std::chrono::milliseconds(kGitLockWaitTime)); |