From dc27514f4ed279aa6be12988ace97641dc3ada2d Mon Sep 17 00:00:00 2001 From: Zhaolong Zhu Date: Tue, 28 Mar 2023 13:28:54 -0700 Subject: [PATCH] copytrace: abstract reusable functions from trace_rename_backward Summary: refacotr the trace_rename_backward API, so that we can reuse the common parts in trace_rename_forward API in the following diff Reviewed By: quark-zju Differential Revision: D44448494 fbshipit-source-id: 997a338c5f2e9e52d1d7bb3d54641980d9119797 --- eden/scm/lib/copytrace/src/dag_copy_trace.rs | 123 ++++++++++++------- 1 file changed, 80 insertions(+), 43 deletions(-) diff --git a/eden/scm/lib/copytrace/src/dag_copy_trace.rs b/eden/scm/lib/copytrace/src/dag_copy_trace.rs index 3b1d595128..b69392ca03 100644 --- a/eden/scm/lib/copytrace/src/dag_copy_trace.rs +++ b/eden/scm/lib/copytrace/src/dag_copy_trace.rs @@ -102,6 +102,50 @@ impl DagCopyTrace { Ok((old_manifest, new_manifest)) } + + async fn trace_rename_commit( + &self, + src: dag::Vertex, + dst: dag::Vertex, + path: RepoPathBuf, + ) -> Result> { + let set = self.dag.range(src.into(), dst.into()).await?; + let mut rename_tracer = RenameTracer::new( + set, + path, + self.root_tree_reader.clone(), + self.tree_store.clone(), + ) + .await?; + let rename_commit = rename_tracer.next().await?; + Ok(rename_commit) + } + + async fn find_renames_in_direction( + &self, + commit: dag::Vertex, + direction: SearchDirection, + ) -> Result<(HashMap, dag::Vertex)> { + let parents = self.dag.parent_names(commit.clone()).await?; + if parents.is_empty() { + return Err(CopyTraceError::NoParents(commit).into()); + } + // For simplicity, we only check p1. + let p1 = &parents[0]; + let (old_manifest, new_manifest) = self.vertex_to_tree_manifest(p1, &commit).await?; + let renames = self.find_renames(&old_manifest, &new_manifest)?; + let (renames, next_commit) = match direction { + SearchDirection::Backward => (renames, p1.clone()), + SearchDirection::Forward => { + let renames = renames + .into_iter() + .map(|(k, v)| (v, k)) + .collect::>(); + (renames, commit) + } + }; + Ok((renames, next_commit)) + } } #[async_trait] @@ -120,54 +164,32 @@ impl CopyTrace for DagCopyTrace { &self, src: dag::Vertex, dst: dag::Vertex, - dst_path: types::RepoPathBuf, - ) -> Result> { + dst_path: RepoPathBuf, + ) -> Result> { tracing::trace!(?src, ?dst, ?dst_path, "trace_rename_backward"); - - let mut dst = dst; - let mut dst_path = dst_path; + let (mut curr, target, mut curr_path) = (dst, src, dst_path); loop { - tracing::trace!(?dst, ?dst_path, " inside loop"); + tracing::trace!(?curr, ?curr_path, " loop starts"); + let rename_commit = match self + .trace_rename_commit(target.clone(), curr.clone(), curr_path.clone()) + .await? + { + Some(rename_commit) => rename_commit, + None => return Ok(None), // cur_path does not exist + }; - // setup RenameTracer - let set = self.dag.range(src.clone().into(), dst.into()).await?; - let mut rename_tracer = RenameTracer::new( - set, - dst_path.clone(), - self.root_tree_reader.clone(), - self.tree_store.clone(), - ) - .await?; - - // find rename commit - let rename_commit = rename_tracer.next().await?; - - if let Some(rename_commit) = rename_commit { - if rename_commit == src { - return Ok(Some(dst_path)); - } - - // find renames by comparing rename_commit and its parent commit - let parents = self.dag.parent_names(rename_commit.clone()).await?; - if parents.is_empty() { - return Err(CopyTraceError::NoParents(rename_commit).into()); - } - // For simplicity, we only check p1. - let p1 = &parents[0]; - let (old_manifest, new_manifest) = - self.vertex_to_tree_manifest(p1, &rename_commit).await?; - let renames = self.find_renames(&old_manifest, &new_manifest)?; - - if let Some(prev_path) = renames.get(&dst_path) { - dst = p1.clone(); - dst_path = prev_path.clone(); - } else { - // dst_path was new added path - return Ok(None); - } + if rename_commit == target { + return Ok(Some(curr_path)); + } + let (renames, next_commit) = self + .find_renames_in_direction(rename_commit, SearchDirection::Backward) + .await?; + if let Some(next_path) = renames.get(&curr_path) { + curr = next_commit; + curr_path = next_path.clone(); } else { - // dst_path does not exist + // no rename info for curr_path return Ok(None); } } @@ -211,3 +233,18 @@ impl CopyTrace for DagCopyTrace { self.read_renamed_metadata(new_files) } } + +/// SearchDirection when searching renames. +/// +/// Assuming we have a commit graph like below: +/// +/// a..z # draw dag syntax +/// +/// Forward means searching from a to z. +/// Backward means searching from z to a. +#[derive(Debug)] +enum SearchDirection { + #[allow(dead_code)] + Forward, + Backward, +}