[PATCH 3 of 3] log: Speed up hg log on untracked files (issue1340)

S Muralidhar smuralid at yahoo.com
Thu Sep 13 12:41:28 CDT 2012


# HG changeset patch
# User smuralid
# Date 1347511152 25200
# Node ID 46c4a5f7f808504706ecf584f470cfd5406dafbd
# Parent  53e10b4a0769c55d7f475a2669d8fa9294352aae
log: Speed up hg log on untracked files (issue1340)

'hg log' on untracked files tends to be fairly slow. The root cause is that we end up using the 'slowpath' when we can't find a revlog for the files listed. This could happen if the file in question is an untracked file, or it is a directory.
This diff tries to speed up 'hg log' (by avoiding the slowpath) for files if we can determine if that file is not (and was never) a directory. We use the previously added store.__contains__ methods to test if the directory exists (or existed) in the store.

'hg log' will continue to be slow for directories.

diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -979,6 +979,14 @@
             if windowsize < sizelimit:
                 windowsize *= 2
 
+def _containsdir(repo, d):
+    '''Checks if the repo contains (or ever contained) this directory'''
+    if d == '.':
+        return True
+    if not d.endswith('/'):
+        d = d + '/'
+    return d in repo.store
+
 def walkchangerevs(repo, match, opts, prepare):
     '''Iterate over files and the revs in which they changed.
 
@@ -1074,8 +1082,17 @@
                     if follow:
                         raise util.Abort(
                             _('cannot follow nonexistent file: "%s"') % file_)
-                    slowpath = True
-                    break
+                    # Check to see if this was ever a directory. If not, then
+                    # we know that no such file/directory with this name
+                    # existed (as evidenced by the zero-length filelog) - so,
+                    # there's nothing to log.
+                    # For directories, we still need to take the slow path
+                    if _containsdir(repo, file_):
+                        repo.ui.debug("%s may be a directory" % file_)
+                        slowpath = True
+                        break
+                    else:
+                        continue
                 else:
                     continue
 
@@ -1283,7 +1300,15 @@
                 if follow:
                     raise util.Abort(
                         _('cannot follow nonexistent file: "%s"') % f)
-                slowpath = True
+                # Check to see if this was ever a directory. If not, then
+                # we know that no such file/directory with this name
+                # existed (as evidenced by the zero-length filelog) - so,
+                # there's nothing to log.
+                # For directories, we still need to take the slow path
+                if _containsdir(repo, f):
+                    repo.ui.debug("%s may be a directory" % f)
+                    slowpath = True
+                    break
     if slowpath:
         # See walkchangerevs() slow path.
         #
diff --git a/tests/test-glog.t b/tests/test-glog.t
--- a/tests/test-glog.t
+++ b/tests/test-glog.t
@@ -1597,15 +1597,14 @@
   $ testlog a c
   []
   (group
-    (func
-      ('symbol', '_matchfiles')
-      (list
-        (list
-          (list
-            ('string', 'r:')
-            ('string', 'd:relpath'))
-          ('string', 'p:a'))
-        ('string', 'p:c'))))
+    (group
+      (or
+        (func
+          ('symbol', 'filelog')
+          ('string', 'a'))
+        (func
+          ('symbol', 'filelog')
+          ('string', 'c')))))
 
 Test multiple --include/--exclude/paths
 
diff --git a/tests/test-log.t b/tests/test-log.t
--- a/tests/test-log.t
+++ b/tests/test-log.t
@@ -1213,3 +1213,52 @@
   1
 
   $ cd ..
+
+test hg log on non-existent files and on directories
+  $ hg init issue1340
+  $ cd issue1340
+  $ mkdir d1; mkdir D2; mkdir D3.i; mkdir d4.hg; mkdir d5.d; mkdir .d6
+  $ echo 1 > d1/f1
+  $ echo 1 > D2/f1
+  $ echo 1 > D3.i/f1
+  $ echo 1 > d4.hg/f1
+  $ echo 1 > d5.d/f1
+  $ echo 1 > .d6/f1
+  $ hg add .
+  adding .d6/f1
+  adding D2/f1
+  adding D3.i/f1
+  adding d1/f1
+  adding d4.hg/f1
+  adding d5.d/f1
+  $ hg commit -m "a bunch of weird directories"
+  $ hg log -l1 d1/f1 | grep changeset
+  changeset:   0:65624cd9070a
+  $ hg log -l1 f1
+  $ hg log -l1 . | grep changeset
+  changeset:   0:65624cd9070a
+  $ hg log -l1 ./ | grep changeset
+  changeset:   0:65624cd9070a
+  $ hg log -l1 d1 | grep changeset
+  changeset:   0:65624cd9070a
+  $ hg log -l1 D2 | grep changeset
+  changeset:   0:65624cd9070a
+  $ hg log -l1 D2/f1 | grep changeset
+  changeset:   0:65624cd9070a
+  $ hg log -l1 D3.i | grep changeset
+  changeset:   0:65624cd9070a
+  $ hg log -l1 D3.i/f1 | grep changeset
+  changeset:   0:65624cd9070a
+  $ hg log -l1 d4.hg | grep changeset
+  changeset:   0:65624cd9070a
+  $ hg log -l1 d4.hg/f1 | grep changeset
+  changeset:   0:65624cd9070a
+  $ hg log -l1 d5.d | grep changeset
+  changeset:   0:65624cd9070a
+  $ hg log -l1 d5.d/f1 | grep changeset
+  changeset:   0:65624cd9070a
+  $ hg log -l1 .d6 | grep changeset
+  changeset:   0:65624cd9070a
+  $ hg log -l1 .d6/f1 | grep changeset
+  changeset:   0:65624cd9070a
+  $ cd ..


More information about the Mercurial-devel mailing list