Skip to content

Commit

Permalink
Massive performance increase on big repo.
Browse files Browse the repository at this point in the history
git2::Repository::remotes() and find_remote(..) are incredibly slow.
Calling them every time for each branch is unnecessarily slow.

Please note that this is not yet the best way to implement this. We are
still iterating through all remote.refspecs() for each branch. Just that
all Remote structs are cached.

An alternative would be to work on `expand_refspec()` and create a
map/index of (branch name, remote branches) once.

\foriequal0#20
  • Loading branch information
siedentop committed Nov 15, 2020
1 parent 88044cd commit e7c42b1
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 3 deletions.
21 changes: 21 additions & 0 deletions src/branch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,27 @@ impl RemoteTrackingBranch {
}
Err(RemoteBranchError::RemoteNotFound)
}

/// Faster implementation that avoids calling git2::Repository methods remotes() and find_remote().
pub fn to_remote_branch_cached(
&self,
remotes: &Vec<git2::Remote>,
) -> std::result::Result<RemoteBranch, RemoteBranchError> {
for remote in remotes.iter() {
if let Some(expanded) = expand_refspec(
&remote,
&self.refname,
Direction::Fetch,
ExpansionSide::Left,
)? {
return Ok(RemoteBranch {
remote: remote.name().context("non-utf8 remote name")?.to_string(),
refname: expanded,
});
}
}
Err(RemoteBranchError::RemoteNotFound)
}
}

impl Refname for RemoteTrackingBranch {
Expand Down
13 changes: 10 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ pub fn get_trim_plan(git: &Git, param: &PlanParam) -> Result<TrimPlan> {
let mut classifier = Classifier::new(git, &merge_tracker);
let mut skipped = HashMap::new();

let mut remotes = vec![];
for remote_name in git.repo.remotes()?.iter() {
let remote_name = remote_name.context("non-utf8 remote name")?;
let remote = git.repo.find_remote(&remote_name)?;
remotes.push(remote);
}

info!("Enqueue classification requests");
if param.delete.scan_tracking() {
for (local, upstream) in &tracking_branches {
Expand Down Expand Up @@ -116,7 +123,7 @@ pub fn get_trim_plan(git: &Git, param: &PlanParam) -> Result<TrimPlan> {
} else {
for (local, upstream) in &tracking_branches {
if let Some(upstream) = upstream {
let remote = upstream.to_remote_branch(&git.repo)?.remote;
let remote = upstream.to_remote_branch_cached(&remotes)?.remote;
let suggestion = SkipSuggestion::TrackingRemote(remote);
skipped.insert(local.refname.clone(), suggestion.clone());
skipped.insert(upstream.refname.clone(), suggestion.clone());
Expand Down Expand Up @@ -144,14 +151,14 @@ pub fn get_trim_plan(git: &Git, param: &PlanParam) -> Result<TrimPlan> {

for base in &base_upstreams {
for remote_tracking in &non_upstream_branches {
let remote = remote_tracking.to_remote_branch(&git.repo)?;
let remote = remote_tracking.to_remote_branch_cached(&remotes)?;
if param.delete.scan_non_upstream_remote(&remote.remote) {
classifier.queue_request(NonUpstreamBranchClassificationRequest {
base,
remote: remote_tracking,
});
} else {
let remote = remote_tracking.to_remote_branch(&git.repo)?.remote;
let remote = remote_tracking.to_remote_branch_cached(&remotes)?.remote;
skipped.insert(
remote_tracking.refname.clone(),
SkipSuggestion::NonUpstream(remote),
Expand Down

0 comments on commit e7c42b1

Please sign in to comment.