evolution: use index for filtering out ancestors of candidates in new_parent()

This speeds up `jj evolve` of 100 linear commits of the "what's
cooking" branch in the git.git repo further, from ~700 ms to ~400 ms.
This commit is contained in:
Martin von Zweigbergk 2021-03-16 22:51:05 -07:00
parent 985e5b030f
commit 5aec8b9d77
3 changed files with 30 additions and 30 deletions

View file

@ -17,7 +17,7 @@ use std::sync::Arc;
use crate::commit::Commit;
use crate::commit_builder::CommitBuilder;
use crate::dag_walk::{bfs, closest_common_node, leaves, walk_ancestors};
use crate::dag_walk::{bfs, closest_common_node, leaves};
use crate::repo::{MutableRepo, ReadonlyRepo, RepoRef};
use crate::repo_path::DirRepoPath;
use crate::rewrite::{merge_commit_trees, rebase_commit};
@ -228,7 +228,8 @@ impl State {
}
}
pub fn new_parent(&self, store: &StoreWrapper, old_parent_id: &CommitId) -> HashSet<CommitId> {
pub fn new_parent(&self, repo: RepoRef, old_parent_id: &CommitId) -> HashSet<CommitId> {
let store = repo.store();
let mut new_parents = HashSet::new();
if let Some(successor_ids) = self.successors.get(old_parent_id) {
let old_parent = store.get_commit(old_parent_id).unwrap();
@ -286,22 +287,20 @@ impl State {
);
for candidate in candidates {
all_candidates.insert(candidate.clone());
all_candidates.insert(candidate.id().clone());
}
}
// Filter out candidates that are ancestors of or other candidates.
let non_heads: Vec<_> = all_candidates
.iter()
.flat_map(|commit| commit.parents())
// Filter out candidates that are ancestors of other candidates.
let all_candidates: Vec<CommitId> = repo
.index()
.heads(all_candidates.iter())
.into_iter()
.collect();
for commit in walk_ancestors(non_heads) {
all_candidates.remove(&commit);
}
for candidate in all_candidates {
// TODO: Make this not recursive
for effective_successor in self.new_parent(store, candidate.id()) {
for effective_successor in self.new_parent(repo, &candidate) {
new_parents.insert(effective_successor);
}
}
@ -363,10 +362,10 @@ impl EvolutionRef<'_> {
/// change id as A). Then C is rebased to somewhere else and becomes C'.
/// We will choose that C' as effective successor even though it has a
/// different change id and is not a descendant of one that does.
pub fn new_parent(&self, store: &StoreWrapper, old_parent_id: &CommitId) -> HashSet<CommitId> {
pub fn new_parent(&self, repo: RepoRef, old_parent_id: &CommitId) -> HashSet<CommitId> {
match self {
EvolutionRef::Readonly(evolution) => evolution.new_parent(store, old_parent_id),
EvolutionRef::Mutable(evolution) => evolution.new_parent(store, old_parent_id),
EvolutionRef::Readonly(evolution) => evolution.new_parent(repo, old_parent_id),
EvolutionRef::Mutable(evolution) => evolution.new_parent(repo, old_parent_id),
}
}
}
@ -421,8 +420,8 @@ impl ReadonlyEvolution {
self.state.is_divergent(change_id)
}
pub fn new_parent(&self, store: &StoreWrapper, old_parent_id: &CommitId) -> HashSet<CommitId> {
self.state.new_parent(store, old_parent_id)
pub fn new_parent(&self, repo: RepoRef, old_parent_id: &CommitId) -> HashSet<CommitId> {
self.state.new_parent(repo, old_parent_id)
}
}
@ -453,8 +452,8 @@ impl MutableEvolution {
self.state.is_divergent(change_id)
}
pub fn new_parent(&self, store: &StoreWrapper, old_parent_id: &CommitId) -> HashSet<CommitId> {
self.state.new_parent(store, old_parent_id)
pub fn new_parent(&self, repo: RepoRef, old_parent_id: &CommitId) -> HashSet<CommitId> {
self.state.new_parent(repo, old_parent_id)
}
pub fn add_commit(&mut self, commit: &Commit) {
@ -521,7 +520,8 @@ pub fn evolve(
let mut ambiguous_new_parents = false;
let evolution = mut_repo.evolution();
for old_parent in &old_parents {
let new_parent_candidates = evolution.new_parent(&store, old_parent.id());
let new_parent_candidates =
evolution.new_parent(mut_repo.as_repo_ref(), old_parent.id());
if new_parent_candidates.len() > 1 {
ambiguous_new_parents = true;
break;

View file

@ -174,7 +174,7 @@ fn test_new_parent_rewritten(use_git: bool) {
assert_eq!(
mut_repo
.evolution()
.new_parent(mut_repo.store(), original.id()),
.new_parent(mut_repo.as_repo_ref(), original.id()),
vec![rewritten.id().clone()].into_iter().collect()
);
tx.discard();
@ -197,7 +197,7 @@ fn test_new_parent_cherry_picked(use_git: bool) {
assert_eq!(
mut_repo
.evolution()
.new_parent(mut_repo.store(), original.id()),
.new_parent(mut_repo.as_repo_ref(), original.id()),
vec![original.id().clone()].into_iter().collect()
);
tx.discard();
@ -224,7 +224,7 @@ fn test_new_parent_is_pruned(use_git: bool) {
assert_eq!(
mut_repo
.evolution()
.new_parent(mut_repo.store(), original.id()),
.new_parent(mut_repo.as_repo_ref(), original.id()),
vec![new_parent.id().clone()].into_iter().collect()
);
tx.discard();
@ -256,7 +256,7 @@ fn test_new_parent_divergent(use_git: bool) {
assert_eq!(
mut_repo
.evolution()
.new_parent(mut_repo.store(), original.id()),
.new_parent(mut_repo.as_repo_ref(), original.id()),
vec![
rewritten1.id().clone(),
rewritten2.id().clone(),
@ -300,7 +300,7 @@ fn test_new_parent_divergent_one_not_pruned(use_git: bool) {
assert_eq!(
mut_repo
.evolution()
.new_parent(mut_repo.store(), original.id()),
.new_parent(mut_repo.as_repo_ref(), original.id()),
vec![
rewritten1.id().clone(),
parent2.id().clone(),
@ -346,7 +346,7 @@ fn test_new_parent_divergent_all_pruned(use_git: bool) {
assert_eq!(
mut_repo
.evolution()
.new_parent(mut_repo.store(), original.id()),
.new_parent(mut_repo.as_repo_ref(), original.id()),
vec![
parent1.id().clone(),
parent2.id().clone(),
@ -385,7 +385,7 @@ fn test_new_parent_split(use_git: bool) {
assert_eq!(
mut_repo
.evolution()
.new_parent(mut_repo.store(), original.id()),
.new_parent(mut_repo.as_repo_ref(), original.id()),
vec![rewritten3.id().clone()].into_iter().collect()
);
tx.discard();
@ -422,7 +422,7 @@ fn test_new_parent_split_pruned_descendant(use_git: bool) {
assert_eq!(
mut_repo
.evolution()
.new_parent(mut_repo.store(), original.id()),
.new_parent(mut_repo.as_repo_ref(), original.id()),
vec![rewritten2.id().clone()].into_iter().collect()
);
tx.discard();
@ -459,7 +459,7 @@ fn test_new_parent_split_forked(use_git: bool) {
assert_eq!(
mut_repo
.evolution()
.new_parent(mut_repo.store(), original.id()),
.new_parent(mut_repo.as_repo_ref(), original.id()),
vec![rewritten2.id().clone(), rewritten3.id().clone()]
.into_iter()
.collect()
@ -498,7 +498,7 @@ fn test_new_parent_split_forked_pruned(use_git: bool) {
assert_eq!(
mut_repo
.evolution()
.new_parent(mut_repo.store(), original.id()),
.new_parent(mut_repo.as_repo_ref(), original.id()),
vec![rewritten3.id().clone()].into_iter().collect()
);
tx.discard();

View file

@ -258,7 +258,7 @@ fn update_checkout_after_rewrite(ui: &mut Ui, mut_repo: &mut MutableRepo) {
// TODO: Perhaps this method should be in MutableRepo.
let new_checkout_candidates = mut_repo
.evolution()
.new_parent(mut_repo.store(), mut_repo.view().checkout());
.new_parent(mut_repo.as_repo_ref(), mut_repo.view().checkout());
if new_checkout_candidates.is_empty() {
return;
}