mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-20 11:25:34 +00:00
revset: avoid merging whole parent trees by file()/diff_contains() query
Perhaps, we should also cache merged trees, but this patch saves time until we implement the bookkeeping. Even if we had a cache, it wouldn't be ideal to calculate uncached merged trees during revset evaluation. ``` % hyperfine --sort command --warmup 3 --runs 10 -L bin jj-1,jj-2 \ 'target/release-with-debug/{bin} -R ~/mirrors/git --ignore-working-copy \ log -r "::@ & file(root:builtin)" --no-graph -n50' Benchmark 1: target/release-with-debug/jj-1 .. Time (mean ± σ): 3.512 s ± 0.014 s [User: 3.391 s, System: 0.119 s] Range (min … max): 3.489 s … 3.528 s 10 runs Benchmark 2: target/release-with-debug/jj-2 .. Time (mean ± σ): 1.351 s ± 0.010 s [User: 1.275 s, System: 0.074 s] Range (min … max): 1.332 s … 1.366 s 10 runs Relative speed comparison 2.60 ± 0.02 target/release-with-debug/jj-1 .. 1.00 target/release-with-debug/jj-2 .. ```
This commit is contained in:
parent
13f0a2f008
commit
a609580204
1 changed files with 18 additions and 11 deletions
|
@ -34,7 +34,7 @@ use crate::conflicts::{materialize_tree_value, MaterializedTreeValue};
|
|||
use crate::default_index::{AsCompositeIndex, CompositeIndex, IndexPosition};
|
||||
use crate::graph::GraphEdge;
|
||||
use crate::matchers::{Matcher, Visit};
|
||||
use crate::merged_tree::TreeDiffEntry;
|
||||
use crate::merged_tree::resolve_file_values;
|
||||
use crate::repo_path::RepoPath;
|
||||
use crate::revset::{
|
||||
ResolvedExpression, ResolvedPredicateExpression, Revset, RevsetEvaluationError,
|
||||
|
@ -1143,19 +1143,22 @@ fn has_diff_from_parent(
|
|||
return Ok(false);
|
||||
}
|
||||
}
|
||||
let from_tree =
|
||||
rewrite::merge_commit_trees_no_resolve_without_repo(store, &index, &parents)?.resolve()?;
|
||||
|
||||
// Conflict resolution is expensive, try that only for matched files.
|
||||
let from_tree = rewrite::merge_commit_trees_no_resolve_without_repo(store, &index, &parents)?;
|
||||
let to_tree = commit.tree()?;
|
||||
let copy_records = Default::default();
|
||||
let mut tree_diff = from_tree.diff_stream(&to_tree, matcher, ©_records);
|
||||
async {
|
||||
match tree_diff.next().await {
|
||||
Some(TreeDiffEntry { value: Ok(_), .. }) => Ok(true),
|
||||
Some(TreeDiffEntry {
|
||||
value: Err(err), ..
|
||||
}) => Err(err),
|
||||
None => Ok(false),
|
||||
while let Some(entry) = tree_diff.next().await {
|
||||
let (from_value, to_value) = entry.value?;
|
||||
let from_value = resolve_file_values(store, &entry.source, from_value)?;
|
||||
if from_value == to_value {
|
||||
continue;
|
||||
}
|
||||
return Ok(true);
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
.block_on()
|
||||
}
|
||||
|
@ -1169,13 +1172,17 @@ fn matches_diff_from_parent(
|
|||
) -> BackendResult<bool> {
|
||||
let copy_records = Default::default(); // TODO handle copy tracking
|
||||
let parents: Vec<_> = commit.parents().try_collect()?;
|
||||
let from_tree =
|
||||
rewrite::merge_commit_trees_no_resolve_without_repo(store, &index, &parents)?.resolve()?;
|
||||
// Conflict resolution is expensive, try that only for matched files.
|
||||
let from_tree = rewrite::merge_commit_trees_no_resolve_without_repo(store, &index, &parents)?;
|
||||
let to_tree = commit.tree()?;
|
||||
let mut tree_diff = from_tree.diff_stream(&to_tree, files_matcher, ©_records);
|
||||
async {
|
||||
while let Some(entry) = tree_diff.next().await {
|
||||
let (left_value, right_value) = entry.value?;
|
||||
let left_value = resolve_file_values(store, &entry.source, left_value)?;
|
||||
if left_value == right_value {
|
||||
continue;
|
||||
}
|
||||
// Conflicts are compared in materialized form. Alternatively,
|
||||
// conflict pairs can be compared one by one. #4062
|
||||
let left_future = materialize_tree_value(store, &entry.source, left_value);
|
||||
|
|
Loading…
Reference in a new issue