comparison mercurial/pathutil.py @ 49890:1b701d425c37

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
author Arseniy Alekseyev <aalekseyev@janestreet.com>
date Wed, 04 Jan 2023 16:48:32 +0000
parents 445b4d819e9a
children 76d1e9f229fe
comparison
equal deleted inserted replaced
49889:3aa8e569478a 49890:1b701d425c37
117 for i in range(len(parts)): 117 for i in range(len(parts)):
118 prefix = pycompat.ossep.join(parts[: i + 1]) 118 prefix = pycompat.ossep.join(parts[: i + 1])
119 if prefix in self.auditeddir: 119 if prefix in self.auditeddir:
120 continue 120 continue
121 if self._realfs: 121 if self._realfs:
122 self._checkfs(prefix, path) 122 res = self._checkfs_exists(prefix, path)
123 if self._cached: 123 if self._cached:
124 self.auditeddir.add(prefix) 124 self.auditeddir.add(prefix)
125 if not res:
126 break
125 127
126 if self._cached: 128 if self._cached:
127 self.audited.add(path) 129 self.audited.add(path)
128 130
129 def _checkfs(self, prefix, path): 131 def _checkfs_exists(self, prefix, path):
130 # type: (bytes, bytes) -> None 132 # type: (bytes, bytes) -> bool
131 """raise exception if a file system backed check fails""" 133 """raise exception if a file system backed check fails.
134
135 Return a bool that indicates that the directory (or file) exists."""
132 curpath = os.path.join(self.root, prefix) 136 curpath = os.path.join(self.root, prefix)
133 try: 137 try:
134 st = os.lstat(curpath) 138 st = os.lstat(curpath)
135 except OSError as err: 139 except OSError as err:
140 if err.errno == errno.ENOENT:
141 return False
136 # EINVAL can be raised as invalid path syntax under win32. 142 # EINVAL can be raised as invalid path syntax under win32.
137 # They must be ignored for patterns can be checked too. 143 # They must be ignored for patterns can be checked too.
138 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL): 144 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
139 raise 145 raise
140 else: 146 else:
148 os.path.join(curpath, b'.hg') 154 os.path.join(curpath, b'.hg')
149 ): 155 ):
150 if not self.callback or not self.callback(curpath): 156 if not self.callback or not self.callback(curpath):
151 msg = _(b"path '%s' is inside nested repo %r") 157 msg = _(b"path '%s' is inside nested repo %r")
152 raise error.Abort(msg % (path, pycompat.bytestr(prefix))) 158 raise error.Abort(msg % (path, pycompat.bytestr(prefix)))
159 return True
153 160
154 def check(self, path): 161 def check(self, path):
155 # type: (bytes) -> bool 162 # type: (bytes) -> bool
156 try: 163 try:
157 self(path) 164 self(path)