merge: short-circuit the _checkfs loop upon getting ENOENT
authorArseniy Alekseyev <aalekseyev@janestreet.com>
Wed, 04 Jan 2023 16:48:32 +0000
changeset 49890 1b701d425c37
parent 49889 3aa8e569478a
child 49891 76d1e9f229fe
merge: short-circuit the _checkfs loop upon getting ENOENT This reduces the number of [lstat] calls when updating from rev(-1) to a rev with lots of files by a factor of several: for path foo/bar/baz/quux.txt without this patch we're lstatting: foo foo/bar foo/bar/baz foo/bar/baz/quux.txt and with this patch: foo foo/bar/baz/quux.txt
mercurial/pathutil.py
--- a/mercurial/pathutil.py	Wed Jan 04 19:13:41 2023 +0000
+++ b/mercurial/pathutil.py	Wed Jan 04 16:48:32 2023 +0000
@@ -119,20 +119,26 @@
             if prefix in self.auditeddir:
                 continue
             if self._realfs:
-                self._checkfs(prefix, path)
+                res = self._checkfs_exists(prefix, path)
             if self._cached:
                 self.auditeddir.add(prefix)
+            if not res:
+                break
 
         if self._cached:
             self.audited.add(path)
 
-    def _checkfs(self, prefix, path):
-        # type: (bytes, bytes) -> None
-        """raise exception if a file system backed check fails"""
+    def _checkfs_exists(self, prefix, path):
+        # type: (bytes, bytes) -> bool
+        """raise exception if a file system backed check fails.
+
+        Return a bool that indicates that the directory (or file) exists."""
         curpath = os.path.join(self.root, prefix)
         try:
             st = os.lstat(curpath)
         except OSError as err:
+            if err.errno == errno.ENOENT:
+                return False
             # EINVAL can be raised as invalid path syntax under win32.
             # They must be ignored for patterns can be checked too.
             if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
@@ -150,6 +156,7 @@
                 if not self.callback or not self.callback(curpath):
                     msg = _(b"path '%s' is inside nested repo %r")
                     raise error.Abort(msg % (path, pycompat.bytestr(prefix)))
+        return True
 
     def check(self, path):
         # type: (bytes) -> bool