mirror of
https://github.com/martinvonz/jj.git
synced 2024-11-28 17:41:14 +00:00
revset: reimplement children to not scan visible ancestors twice
It's slightly faster, and removes the use of RevsetExpression::descendants() API.
This commit is contained in:
parent
5dd99db250
commit
adfd52445b
2 changed files with 42 additions and 51 deletions
|
@ -284,45 +284,6 @@ fn predicate_fn_from_iter<'index, 'iter>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct ChildrenRevset<'index> {
|
|
||||||
// The revisions we want to find children for
|
|
||||||
root_set: Box<dyn InternalRevset<'index> + 'index>,
|
|
||||||
// Consider only candidates from this set
|
|
||||||
candidate_set: Box<dyn InternalRevset<'index> + 'index>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'index> InternalRevset<'index> for ChildrenRevset<'index> {
|
|
||||||
fn iter(&self) -> Box<dyn Iterator<Item = IndexEntry<'index>> + '_> {
|
|
||||||
let roots: HashSet<_> = self
|
|
||||||
.root_set
|
|
||||||
.iter()
|
|
||||||
.map(|parent| parent.position())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Box::new(self.candidate_set.iter().filter(move |candidate| {
|
|
||||||
candidate
|
|
||||||
.parent_positions()
|
|
||||||
.iter()
|
|
||||||
.any(|parent_pos| roots.contains(parent_pos))
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_predicate<'a>(self: Box<Self>) -> Box<dyn ToPredicateFn + 'a>
|
|
||||||
where
|
|
||||||
Self: 'a,
|
|
||||||
{
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToPredicateFn for ChildrenRevset<'_> {
|
|
||||||
fn to_predicate_fn(&self) -> Box<dyn FnMut(&IndexEntry<'_>) -> bool + '_> {
|
|
||||||
// TODO: can be optimized if candidate_set contains all heads
|
|
||||||
predicate_fn_from_iter(self.iter())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct FilterRevset<'index, P> {
|
struct FilterRevset<'index, P> {
|
||||||
candidates: Box<dyn InternalRevset<'index> + 'index>,
|
candidates: Box<dyn InternalRevset<'index> + 'index>,
|
||||||
|
@ -639,11 +600,20 @@ impl<'index, 'heads> EvaluationContext<'index, 'heads> {
|
||||||
}
|
}
|
||||||
RevsetExpression::Children(roots) => {
|
RevsetExpression::Children(roots) => {
|
||||||
let root_set = self.evaluate(roots)?;
|
let root_set = self.evaluate(roots)?;
|
||||||
let candidates_expression = roots.descendants();
|
let head_set = self.revset_for_commit_ids(self.visible_heads);
|
||||||
let candidate_set = self.evaluate(&candidates_expression)?;
|
let (walk, root_positions) = self.walk_ancestors_until_roots(&*root_set, &head_set);
|
||||||
Ok(Box::new(ChildrenRevset {
|
let roots: HashSet<_> = root_positions.into_iter().collect();
|
||||||
root_set,
|
let candidates = Box::new(RevWalkRevset { walk });
|
||||||
candidate_set,
|
let predicate = pure_predicate_fn(move |entry| {
|
||||||
|
entry
|
||||||
|
.parent_positions()
|
||||||
|
.iter()
|
||||||
|
.any(|parent_pos| roots.contains(parent_pos))
|
||||||
|
});
|
||||||
|
// TODO: ToPredicateFn version can be optimized to only test the predicate()
|
||||||
|
Ok(Box::new(FilterRevset {
|
||||||
|
candidates,
|
||||||
|
predicate,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
RevsetExpression::Ancestors { heads, generation } => {
|
RevsetExpression::Ancestors { heads, generation } => {
|
||||||
|
@ -818,6 +788,29 @@ impl<'index, 'heads> EvaluationContext<'index, 'heads> {
|
||||||
self.composite_index.walk_revs(&head_ids, &[])
|
self.composite_index.walk_revs(&head_ids, &[])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn walk_ancestors_until_roots<'a, 'b, S, T>(
|
||||||
|
&self,
|
||||||
|
root_set: &S,
|
||||||
|
head_set: &T,
|
||||||
|
) -> (
|
||||||
|
impl Iterator<Item = IndexEntry<'index>> + Clone,
|
||||||
|
Vec<IndexPosition>,
|
||||||
|
)
|
||||||
|
where
|
||||||
|
S: InternalRevset<'a> + ?Sized,
|
||||||
|
T: InternalRevset<'b> + ?Sized,
|
||||||
|
{
|
||||||
|
// We can also make RevWalk stop visiting based on the generation number. Maybe
|
||||||
|
// it will perform better for unbalanced branchy history.
|
||||||
|
// https://github.com/martinvonz/jj/pull/1492#discussion_r1160678325
|
||||||
|
let root_positions = root_set.iter().map(|entry| entry.position()).collect_vec();
|
||||||
|
let bottom_position = *root_positions.last().unwrap_or(&IndexPosition::MAX);
|
||||||
|
let walk = self
|
||||||
|
.walk_ancestors(head_set)
|
||||||
|
.take_while(move |entry| entry.position() >= bottom_position);
|
||||||
|
(walk, root_positions)
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculates `root_set:head_set`.
|
/// Calculates `root_set:head_set`.
|
||||||
///
|
///
|
||||||
/// The returned `HashSet` contains all `root_set` positions no matter if
|
/// The returned `HashSet` contains all `root_set` positions no matter if
|
||||||
|
@ -832,15 +825,10 @@ impl<'index, 'heads> EvaluationContext<'index, 'heads> {
|
||||||
S: InternalRevset<'a> + ?Sized,
|
S: InternalRevset<'a> + ?Sized,
|
||||||
T: InternalRevset<'b> + ?Sized,
|
T: InternalRevset<'b> + ?Sized,
|
||||||
{
|
{
|
||||||
let root_positions = root_set.iter().map(|entry| entry.position()).collect_vec();
|
let (walk, root_positions) = self.walk_ancestors_until_roots(root_set, head_set);
|
||||||
let bottom_position = *root_positions.last().unwrap_or(&IndexPosition::MAX);
|
|
||||||
let mut reachable: HashSet<_> = root_positions.into_iter().collect();
|
let mut reachable: HashSet<_> = root_positions.into_iter().collect();
|
||||||
let mut index_entries = vec![];
|
let mut index_entries = vec![];
|
||||||
let candidates = self
|
for candidate in walk.collect_vec().into_iter().rev() {
|
||||||
.walk_ancestors(head_set)
|
|
||||||
.take_while(|entry| entry.position() >= bottom_position)
|
|
||||||
.collect_vec();
|
|
||||||
for candidate in candidates.into_iter().rev() {
|
|
||||||
if reachable.contains(&candidate.position())
|
if reachable.contains(&candidate.position())
|
||||||
|| candidate
|
|| candidate
|
||||||
.parent_positions()
|
.parent_positions()
|
||||||
|
|
|
@ -803,6 +803,9 @@ fn test_evaluate_expression_children(use_git: bool) {
|
||||||
),
|
),
|
||||||
vec![commit5.id().clone()]
|
vec![commit5.id().clone()]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Empty root
|
||||||
|
assert_eq!(resolve_commit_ids(mut_repo, "none()+"), vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test_case(false ; "local backend")]
|
#[test_case(false ; "local backend")]
|
||||||
|
|
Loading…
Reference in a new issue