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
--- 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