From 8d9fd1818feee729e5adeab982608aff4eddd613 Mon Sep 17 00:00:00 2001 From: Paul Cristian Sarbu Date: Mon, 13 Mar 2023 16:34:12 +0100 Subject: GitRepo: Make repository initialisation more robust As the initialisation of Git repositories is something that only takes place once, we should check early and cheaply whether the repository is already there before trying to initialize it. If we do need to initilize a repo, we can afford more attempts and longer wait times between tries to initalize if the failure to initialize happens due to the internal Git locking mechanism. --- src/buildtool/file_system/git_repo.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'src/buildtool/file_system/git_repo.cpp') diff --git a/src/buildtool/file_system/git_repo.cpp b/src/buildtool/file_system/git_repo.cpp index bf0b6ddc..4c88e4a7 100644 --- a/src/buildtool/file_system/git_repo.cpp +++ b/src/buildtool/file_system/git_repo.cpp @@ -361,8 +361,16 @@ auto GitRepo::InitAndOpen(std::filesystem::path const& repo_path, auto git_state = GitContext(); // 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}; - size_t max_attempts = 3; // number of tries + size_t max_attempts = kGitLockNumTries; // number of tries int err = 0; std::string err_mess{}; while (max_attempts > 0) { @@ -373,7 +381,11 @@ auto GitRepo::InitAndOpen(std::filesystem::path const& repo_path, git_repository_free(tmp_repo); return GitRepo(repo_path); // success } - err_mess = GitLastError(); // store last error message + err_mess = GitLastError(); // store last error message + // 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, @@ -383,7 +395,8 @@ auto GitRepo::InitAndOpen(std::filesystem::path const& repo_path, return GitRepo(repo_path); // success } // repo still not created, so sleep and try again - std::this_thread::sleep_for(std::chrono::milliseconds(kWaitTime)); + std::this_thread::sleep_for( + std::chrono::milliseconds(kGitLockWaitTime)); } Logger::Log(LogLevel::Error, "initializing git repository {} failed with:\n{}", @@ -582,7 +595,7 @@ auto GitRepo::KeepTag(std::string const& commit, git_oid oid; auto name = fmt::format("keep-{}", commit); - size_t max_attempts = 3; // number of tries + size_t max_attempts = kGitLockNumTries; // number of tries int err = 0; git_strarray tag_names{}; while (max_attempts > 0) { @@ -607,7 +620,8 @@ auto GitRepo::KeepTag(std::string const& commit, git_strarray_dispose( &tag_names); // free any allocated unused space // tag still not in, so sleep and try again - std::this_thread::sleep_for(std::chrono::milliseconds(kWaitTime)); + std::this_thread::sleep_for( + std::chrono::milliseconds(kGitLockWaitTime)); } (*logger)(fmt::format("tag creation in git repository {} failed", GetGitCAS()->git_path_.string()), -- cgit v1.2.3