Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 10 additions & 36 deletions src/cargo/sources/git/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1313,62 +1313,36 @@ fn fetch_with_libgit2(
/// descriptors, getting us dangerously close to blowing out the OS limits of
/// how many fds we can have open. This is detailed in [#4403].
///
/// To try to combat this problem we attempt a `git gc` here. Note, though, that
/// we may not even have `git` installed on the system! As a result we
/// opportunistically try a `git gc` when the pack directory looks too big, and
/// failing that we just blow away the repository and start over.
///
/// In theory this shouldn't be too expensive compared to the network request
/// we're about to issue.
/// Instead of trying to be clever about when gc is needed, we just run
/// `git gc --auto` and let git figure it out. It checks its own thresholds
/// (gc.auto, gc.autoPackLimit) and either does the work or exits quickly.
/// If git isn't installed, no worries - we skip it.
///
/// [#4403]: https://github.com/rust-lang/cargo/issues/4403
fn maybe_gc_repo(repo: &mut git2::Repository, gctx: &GlobalContext) -> CargoResult<()> {
// Here we arbitrarily declare that if you have more than 100 files in your
// `pack` folder that we need to do a gc.
let entries = match repo.path().join("objects/pack").read_dir() {
Ok(e) => e.count(),
Err(_) => {
debug!("skipping gc as pack dir appears gone");
return Ok(());
}
};
let max = gctx
.get_env("__CARGO_PACKFILE_LIMIT")
.ok()
.and_then(|s| s.parse::<usize>().ok())
.unwrap_or(100);
if entries < max {
debug!("skipping gc as there's only {} pack files", entries);
return Ok(());
}

// First up, try a literal `git gc` by shelling out to git. This is pretty
// likely to fail though as we may not have `git` installed. Note that
// libgit2 doesn't currently implement the gc operation, so there's no
// equivalent there.
fn maybe_gc_repo(repo: &mut git2::Repository, _gctx: &GlobalContext) -> CargoResult<()> {
// Let git decide whether gc is actually needed based on its config.
match Command::new("git")
.arg("gc")
.arg("--auto")
.current_dir(repo.path())
.output()
{
Ok(out) => {
debug!(
"git-gc status: {}\n\nstdout ---\n{}\nstderr ---\n{}",
"git-gc --auto status: {}\n\nstdout ---\n{}\nstderr ---\n{}",
out.status,
String::from_utf8_lossy(&out.stdout),
String::from_utf8_lossy(&out.stderr)
);
if out.status.success() {
let new = git2::Repository::open(repo.path())?;
*repo = new;
return Ok(());
}
}
Err(e) => debug!("git-gc failed to spawn: {}", e),
Err(e) => debug!("git-gc --auto failed to spawn: {}", e),
}

// Alright all else failed, let's start over.
reinitialize(repo)
Comment on lines -1370 to -1371
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this removed?

Ok(())
}

/// Removes temporary files left from previous activity.
Expand Down
23 changes: 2 additions & 21 deletions tests/testsuite/git_gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,32 +62,13 @@ fn run_test(path_env: Option<&OsStr>) {
drop((repo, index));
Package::new("bar", "0.1.1").publish();

let before = find_index()
.join(".git/objects/pack")
.read_dir()
.unwrap()
.count();
assert!(before > N);

// We can't really test gc behavior directly since it depends on git's
// internal thresholds, so just make sure cargo update works fine.
let mut cmd = foo.cargo("update");
cmd.env("__CARGO_PACKFILE_LIMIT", "10");
if let Some(path) = path_env {
cmd.env("PATH", path);
}
cmd.env("CARGO_LOG", "trace");
cmd.run();
let after = find_index()
.join(".git/objects/pack")
.read_dir()
.unwrap()
.count();
assert!(
after < before,
"packfiles before: {}\n\
packfiles after: {}",
before,
after
);
}

#[cargo_test(requires = "git")]
Expand Down