Skip to content

Commit

Permalink
create git caches atomically
Browse files Browse the repository at this point in the history
When working on speeding up the CI,
I triggered a race condition in the creation of the tarball cache.
This code now instead will ensure that half-initialized repositories
are no longer visible to any other nix process.

This is the error message that I got before:

error: opening Git repository '"/Users/runner/.cache/nix/tarball-cache"': could not find repository at '/Users/runner/.cache/nix/tarball-cache'
  • Loading branch information
Mic92 committed Sep 24, 2024
1 parent 322d2c7 commit bf6e491
Showing 1 changed file with 21 additions and 6 deletions.
27 changes: 21 additions & 6 deletions src/libfetchers/git-utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,23 @@ static git_packbuilder_progress PACKBUILDER_PROGRESS_CHECK_INTERRUPT = &packBuil

} // extern "C"

static void initRepoAtomically(std::filesystem::path &path, bool bare) {
Path tmpDir = createTempDir(std::filesystem::path(path).parent_path());
AutoDelete delTmpDir(tmpDir, true);
Repository tmpRepo;
if (git_repository_init(Setter(tmpRepo), tmpDir.c_str(), bare))
throw Error("creating Git repository %s: %s", path, git_error_last()->message);
try {
std::filesystem::rename(tmpDir, path);
delTmpDir.cancel();
} catch (std::filesystem::filesystem_error & e) {
// Someone might race us to create the repository.
if (e.code() != std::errc::file_exists) {
throw SysError("moving temporary git repository from %s to %s", tmpDir, path);
}
}
}

struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
{
/** Location of the repository on disk. */
Expand All @@ -226,13 +243,11 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
{
initLibGit2();

if (pathExists(path.string())) {
if (git_repository_open(Setter(repo), path.string().c_str()))
throw Error("opening Git repository '%s': %s", path, git_error_last()->message);
} else {
if (git_repository_init(Setter(repo), path.string().c_str(), bare))
throw Error("creating Git repository '%s': %s", path, git_error_last()->message);
if (!pathExists(path.string())) {
initRepoAtomically(path, bare);
}
if (git_repository_open(Setter(repo), path.string().c_str()))
throw Error("opening Git repository %s: %s", path, git_error_last()->message);

ObjectDb odb;
if (git_repository_odb(Setter(odb), repo.get()))
Expand Down

0 comments on commit bf6e491

Please sign in to comment.