merge: make to_tree_merge() read trees concurrently

This commit is contained in:
Martin von Zweigbergk 2025-04-20 10:14:00 -07:00
parent fc5f90c4ac
commit 5ccd0dbe32
2 changed files with 16 additions and 14 deletions

View File

@ -34,7 +34,6 @@ use smallvec::SmallVec;
use crate::backend; use crate::backend;
use crate::backend::BackendResult; use crate::backend::BackendResult;
use crate::backend::FileId; use crate::backend::FileId;
use crate::backend::TreeId;
use crate::backend::TreeValue; use crate::backend::TreeValue;
use crate::content_hash::ContentHash; use crate::content_hash::ContentHash;
use crate::content_hash::DigestUpdate; use crate::content_hash::DigestUpdate;
@ -598,7 +597,7 @@ where
/// is a `TreeValue::Tree`, this converts it to /// is a `TreeValue::Tree`, this converts it to
/// a `Merge<Tree>`, with empty trees instead of /// a `Merge<Tree>`, with empty trees instead of
/// any `None` terms. Otherwise, returns `None`. /// any `None` terms. Otherwise, returns `None`.
pub fn to_tree_merge( pub async fn to_tree_merge(
&self, &self,
store: &Arc<Store>, store: &Arc<Store>,
dir: &RepoPath, dir: &RepoPath,
@ -609,14 +608,17 @@ where
Some(_) => Err(()), Some(_) => Err(()),
}); });
if let Ok(tree_id_merge) = tree_id_merge { if let Ok(tree_id_merge) = tree_id_merge {
let get_tree = |id: &Option<&TreeId>| -> BackendResult<Tree> { Ok(Some(
tree_id_merge
.try_map_async(|id| async move {
if let Some(id) = id { if let Some(id) = id {
store.get_tree(dir.to_owned(), id) store.get_tree_async(dir.to_owned(), id).await
} else { } else {
Ok(Tree::empty(store.clone(), dir.to_owned())) Ok(Tree::empty(store.clone(), dir.to_owned()))
} }
}; })
Ok(Some(tree_id_merge.try_map(get_tree)?)) .await?,
))
} else { } else {
Ok(None) Ok(None)
} }

View File

@ -497,7 +497,7 @@ async fn merge_tree_values(
return Ok(Merge::resolved(resolved.cloned())); return Ok(Merge::resolved(resolved.cloned()));
} }
if let Some(trees) = values.to_tree_merge(store, path)? { if let Some(trees) = values.to_tree_merge(store, path).await? {
// If all sides are trees or missing, merge the trees recursively, treating // If all sides are trees or missing, merge the trees recursively, treating
// missing trees as empty. // missing trees as empty.
let empty_tree_id = store.empty_tree_id(); let empty_tree_id = store.empty_tree_id();
@ -594,7 +594,7 @@ impl Iterator for TreeEntriesIterator<'_> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while let Some(top) = self.stack.last_mut() { while let Some(top) = self.stack.last_mut() {
if let Some((path, value)) = top.entries.pop() { if let Some((path, value)) = top.entries.pop() {
let maybe_trees = match value.to_tree_merge(&self.store, &path) { let maybe_trees = match value.to_tree_merge(&self.store, &path).block_on() {
Ok(maybe_trees) => maybe_trees, Ok(maybe_trees) => maybe_trees,
Err(err) => return Some((path, Err(err))), Err(err) => return Some((path, Err(err))),
}; };
@ -656,7 +656,7 @@ impl Iterator for ConflictIterator {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while let Some(top) = self.stack.last_mut() { while let Some(top) = self.stack.last_mut() {
if let Some((path, tree_values)) = top.entries.pop() { if let Some((path, tree_values)) = top.entries.pop() {
match tree_values.to_tree_merge(&self.store, &path) { match tree_values.to_tree_merge(&self.store, &path).block_on() {
Ok(Some(trees)) => { Ok(Some(trees)) => {
// If all sides are trees or missing, descend into the merged tree // If all sides are trees or missing, descend into the merged tree
self.stack.push(ConflictsDirItem::from(&trees)); self.stack.push(ConflictsDirItem::from(&trees));
@ -723,7 +723,7 @@ impl<'matcher> TreeDiffIterator<'matcher> {
dir: &RepoPath, dir: &RepoPath,
values: &MergedTreeValue, values: &MergedTreeValue,
) -> BackendResult<Merge<Tree>> { ) -> BackendResult<Merge<Tree>> {
if let Some(trees) = values.to_tree_merge(store, dir)? { if let Some(trees) = values.to_tree_merge(store, dir).block_on()? {
Ok(trees) Ok(trees)
} else { } else {
Ok(Merge::resolved(Tree::empty(store.clone(), dir.to_owned()))) Ok(Merge::resolved(Tree::empty(store.clone(), dir.to_owned())))