Patchwork D11615: rhg: faster hg cat when many files are requested

login
register
mail settings
Submitter phabricator
Date Oct. 5, 2021, 2:16 p.m.
Message ID <differential-rev-PHID-DREV-w6tywyipk4uvh4sxg5n2-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/49940/
State Superseded
Headers show

Comments

phabricator - Oct. 5, 2021, 2:16 p.m.
aalekseyev created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D11615

AFFECTED FILES
  rust/hg-core/src/operations/cat.rs
  rust/rhg/src/commands/cat.rs

CHANGE DETAILS




To: aalekseyev, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/rust/rhg/src/commands/cat.rs b/rust/rhg/src/commands/cat.rs
--- a/rust/rhg/src/commands/cat.rs
+++ b/rust/rhg/src/commands/cat.rs
@@ -59,7 +59,7 @@ 
 
     match rev {
         Some(rev) => {
-            let output = cat(&repo, rev, &files).map_err(|e| (e, rev))?;
+            let output = cat(&repo, rev, files).map_err(|e| (e, rev))?;
             invocation.ui.write_stdout(&output.concatenated)?;
             if !output.missing.is_empty() {
                 let short = format!("{:x}", output.node.short()).into_bytes();
diff --git a/rust/hg-core/src/operations/cat.rs b/rust/hg-core/src/operations/cat.rs
--- a/rust/hg-core/src/operations/cat.rs
+++ b/rust/hg-core/src/operations/cat.rs
@@ -11,6 +11,9 @@ 
 
 use crate::utils::hg_path::HgPathBuf;
 
+use itertools::EitherOrBoth::{Both, Left, Right};
+use itertools::Itertools;
+
 pub struct CatOutput {
     /// Whether any file in the manifest matched the paths given as CLI
     /// arguments
@@ -31,7 +34,7 @@ 
 pub fn cat<'a>(
     repo: &Repo,
     revset: &str,
-    files: &'a [HgPathBuf],
+    mut files: Vec<HgPathBuf>,
 ) -> Result<CatOutput, RevlogError> {
     let rev = crate::revset::resolve_single(revset, repo)?;
     let manifest = repo.manifest_for_rev(rev)?;
@@ -40,13 +43,21 @@ 
         .node_from_rev(rev)
         .expect("should succeed when repo.manifest did");
     let mut bytes = vec![];
-    let mut matched = vec![false; files.len()];
     let mut found_any = false;
+    files.sort_unstable();
+
+    let mut missing = vec![];
 
-    for (manifest_file, node_bytes) in manifest.files_with_nodes() {
-        for (cat_file, is_matched) in files.iter().zip(&mut matched) {
-            if cat_file.as_bytes() == manifest_file.as_bytes() {
-                *is_matched = true;
+    for entry in manifest
+        .files_with_nodes()
+        .merge_join_by(files.iter(), |(manifest_file, _), file| {
+            manifest_file.cmp(&file.as_ref())
+        })
+    {
+        match entry {
+            Left(_) => (),
+            Right(path) => missing.push(path),
+            Both((manifest_file, node_bytes), _) => {
                 found_any = true;
                 let file_log = repo.filelog(manifest_file)?;
                 let file_node = Node::from_hex_for_repo(node_bytes)?;
@@ -56,11 +67,12 @@ 
         }
     }
 
+    // make the order of the [missing] files
+    // match the order they were specified on the command line
     let missing: Vec<_> = files
         .iter()
-        .zip(&matched)
-        .filter(|pair| !*pair.1)
-        .map(|pair| pair.0.clone())
+        .filter(|file| missing.contains(file))
+        .map(|file| file.clone())
         .collect();
     Ok(CatOutput {
         found_any,