[PATCH 3 of 4] dirstate: split the foldmap into separate ones for files and directories

Siddharth Agarwal sid0 at fb.com
Tue Mar 31 11:52:58 CDT 2015


# HG changeset patch
# User Siddharth Agarwal <sid0 at fb.com>
# Date 1427683369 25200
#      Sun Mar 29 19:42:49 2015 -0700
# Node ID cf5e06980f6cd6591497b82cb6dbfb5f52f99f00
# Parent  21df72baa78f0ba8c6f7d98f4159c48b4dffddf3
dirstate: split the foldmap into separate ones for files and directories

Computing the set of directories in the dirstate can be pretty expensive. For
'hg status' without arguments, it turns out we actually never need to figure
out the right case for directories in the foldmap. (An upcoming patch explains
why.)

This patch splits up the directory and file maps into separate ones, allowing
for the subsequent optimization in status.

diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -87,15 +87,21 @@
         return self._copymap
 
     @propertycache
-    def _foldmap(self):
+    def _filefoldmap(self):
         f = {}
         normcase = util.normcase
         for name, s in self._map.iteritems():
             if s[0] != 'r':
                 f[normcase(name)] = name
+        f['.'] = '.' # prevents useless util.fspath() invocation
+        return f
+
+    @propertycache
+    def _dirfoldmap(self):
+        f = {}
+        normcase = util.normcase
         for name in self._dirs:
             f[normcase(name)] = name
-        f['.'] = '.' # prevents useless util.fspath() invocation
         return f
 
     @repocache('branch')
@@ -332,8 +338,8 @@
             self._pl = p
 
     def invalidate(self):
-        for a in ("_map", "_copymap", "_foldmap", "_branch", "_pl", "_dirs",
-                "_ignore"):
+        for a in ("_map", "_copymap", "_filefoldmap", "_dirfoldmap", "_branch",
+                  "_pl", "_dirs", "_ignore"):
             if a in self.__dict__:
                 delattr(self, a)
         self._lastnormaltime = 0
@@ -492,24 +498,27 @@
 
     def _normalizefile(self, path, isknown, ignoremissing=False, exists=None):
         normed = util.normcase(path)
-        folded = self._foldmap.get(normed, None)
+        folded = self._filefoldmap.get(normed, None)
         if folded is None:
             if isknown:
                 folded = path
             else:
                 folded = self._discoverpath(path, normed, ignoremissing, exists,
-                                            self._foldmap)
+                                            self._filefoldmap)
         return folded
 
     def _normalize(self, path, isknown, ignoremissing=False, exists=None):
         normed = util.normcase(path)
-        folded = self._foldmap.get(normed, None)
+        folded = self._filefoldmap.get(normed,
+                                       self._dirfoldmap.get(normed, None))
         if folded is None:
             if isknown:
                 folded = path
             else:
+                # store discovered result in dirfoldmap so that future
+                # normalizefile calls don't start matching directories
                 folded = self._discoverpath(path, normed, ignoremissing, exists,
-                                            self._foldmap)
+                                            self._dirfoldmap)
         return folded
 
     def normalize(self, path, isknown=False, ignoremissing=False):


More information about the Mercurial-devel mailing list