Patchwork [2,of,2,V2] cat: increase perf when catting single files

login
register
mail settings
Submitter Durham Goode
Date Jan. 14, 2014, 9:52 p.m.
Message ID <c7652078e0d4e1880fce.1389736351@dev010.prn1.facebook.com>
Download mbox | patch
Permalink /patch/3323/
State Accepted
Commit 2f6b3900be64cd5978c509dc98f823d2b1196628
Headers show

Comments

Durham Goode - Jan. 14, 2014, 9:52 p.m.
# HG changeset patch
# User Durham Goode <durham@fb.com>
# Date 1389735496 28800
#      Tue Jan 14 13:38:16 2014 -0800
# Node ID c7652078e0d4e1880fce51405cf44c2869edbed7
# Parent  9c531e73a03eb7ddd809da0778d98612ae41134e
cat: increase perf when catting single files

Special case the single file case in hg cat. This allows us to avoid
parsing the manifest, which shaves 15% off hg cat perf. This is worth
it, since automation often uses hg cat for retrieving single files.
Matt Mackall - Jan. 18, 2014, 3:23 a.m.
On Tue, 2014-01-14 at 13:52 -0800, Durham Goode wrote:
> # HG changeset patch
> # User Durham Goode <durham@fb.com>
> # Date 1389735496 28800
> #      Tue Jan 14 13:38:16 2014 -0800
> # Node ID c7652078e0d4e1880fce51405cf44c2869edbed7
> # Parent  9c531e73a03eb7ddd809da0778d98612ae41134e
> cat: increase perf when catting single files

These are queued for default, thanks.

Patch

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -1157,14 +1157,28 @@ 
     ctx = scmutil.revsingle(repo, opts.get('rev'))
     err = 1
     m = scmutil.match(ctx, (file1,) + pats, opts)
-    for abs in ctx.walk(m):
+
+    def write(path):
         fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
-                                 pathname=abs)
-        data = ctx[abs].data()
+                                 pathname=path)
+        data = ctx[path].data()
         if opts.get('decode'):
-            data = repo.wwritedata(abs, data)
+            data = repo.wwritedata(path, data)
         fp.write(data)
         fp.close()
+
+    # Automation often uses hg cat on single files, so special case it
+    # for performance to avoid the cost of parsing the manifest.
+    if len(m.files()) == 1 and not m.anypats():
+        file = m.files()[0]
+        mf = repo.manifest
+        mfnode = ctx._changeset[0]
+        if mf.find(mfnode, file)[0]:
+            write(file)
+            return 0
+
+    for abs in ctx.walk(m):
+        write(abs)
         err = 0
     return err