Skip to content

Commit

Permalink
merged_tree: add merge-join iterator over Merge<Tree> entries
Browse files Browse the repository at this point in the history
For the same reason as 2cb7e91 "merged_tree: do not re-look up non-conflicting
tree values by name." This appears to bring a similar performance improvement.

I assume this change is/will be covered by test_merged_tree.rs. I considered
adding a few unit tests, but constructing Tree object isn't trivial, and the
iterator implementation is relatively straightforward.
  • Loading branch information
yuja committed Aug 12, 2024
1 parent 5911e5c commit 6d6f599
Showing 1 changed file with 28 additions and 4 deletions.
32 changes: 28 additions & 4 deletions lib/src/merged_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,33 @@ fn all_tree_entries(
}
}

/// Suppose the given `trees` aren't resolved, iterates `(name, values)` pairs
/// non-recursively. This also works if `trees` are resolved, but is more costly
/// than `tree.entries_non_recursive()`.
fn all_merged_tree_entries(
trees: &Merge<Tree>,
) -> impl Iterator<Item = (&RepoPathComponent, MergedTreeValue)> {
let mut entries_iters = trees
.iter()
.map(|tree| tree.entries_non_recursive().peekable())
.collect_vec();
iter::from_fn(move || {
let next_name = entries_iters
.iter_mut()
.filter_map(|iter| iter.peek())
.map(|entry| entry.name())
.min()?;
let values: MergeBuilder<_> = entries_iters
.iter_mut()
.map(|iter| {
let entry = iter.next_if(|entry| entry.name() == next_name)?;
Some(entry.value().clone())
})
.collect();
Some((next_name, values.build()))
})
}

fn merged_tree_entry_diff<'a>(
trees1: &'a Merge<Tree>,
trees2: &'a Merge<Tree>,
Expand Down Expand Up @@ -427,10 +454,7 @@ fn merge_trees(merge: &Merge<Tree>) -> BackendResult<Merge<Tree>> {
// any conflicts.
let mut new_tree = backend::Tree::default();
let mut conflicts = vec![];
// TODO: add all_tree_entries()-like function that doesn't change the arity
// of conflicts?
for basename in all_tree_basenames(merge) {
let path_merge = merge.map(|tree| tree.value(basename).cloned());
for (basename, path_merge) in all_merged_tree_entries(merge) {
let path = dir.join(basename);
let path_merge = merge_tree_values(store, &path, path_merge)?;
match path_merge.into_resolved() {
Expand Down

0 comments on commit 6d6f599

Please sign in to comment.