merge: cache the fs checks made during [_checkunknownfiles]
this ~halves the number of lstat calls made when updating
from rev(-1) to a revision with lots of files
--- a/mercurial/merge.py Wed Jan 04 17:03:15 2023 +0000
+++ b/mercurial/merge.py Wed Jan 04 17:14:33 2023 +0000
@@ -145,18 +145,19 @@
warnconflicts.update(conflicts)
checkunknowndirs = _unknowndirschecker()
- for f in mresult.files(
- (
- mergestatemod.ACTION_CREATED,
- mergestatemod.ACTION_DELETED_CHANGED,
- )
- ):
- if _checkunknownfile(repo, wctx, mctx, f):
- fileconflicts.add(f)
- elif pathconfig and f not in wctx:
- path = checkunknowndirs(repo, wctx, f)
- if path is not None:
- pathconflicts.add(path)
+ with repo.wvfs.audit.cached():
+ for f in mresult.files(
+ (
+ mergestatemod.ACTION_CREATED,
+ mergestatemod.ACTION_DELETED_CHANGED,
+ )
+ ):
+ if _checkunknownfile(repo, wctx, mctx, f):
+ fileconflicts.add(f)
+ elif pathconfig and f not in wctx:
+ path = checkunknowndirs(repo, wctx, f)
+ if path is not None:
+ pathconflicts.add(path)
for f, args, msg in mresult.getactions(
[mergestatemod.ACTION_LOCAL_DIR_RENAME_GET]
):
--- a/mercurial/pathutil.py Wed Jan 04 17:03:15 2023 +0000
+++ b/mercurial/pathutil.py Wed Jan 04 17:14:33 2023 +0000
@@ -56,7 +56,7 @@
def __init__(self, root, callback=None, realfs=True, cached=False):
self.audited = set()
- self.auditeddir = set()
+ self.auditeddir = dict()
self.root = root
self._realfs = realfs
self._cached = cached
@@ -118,10 +118,11 @@
for i in range(len(parts)):
prefix = pycompat.ossep.join(parts[: i + 1])
if prefix in self.auditeddir:
- continue
- res = self._checkfs_exists(prefix, path)
- if self._cached:
- self.auditeddir.add(prefix)
+ res = self.auditeddir[prefix]
+ else:
+ res = self._checkfs_exists(prefix, path)
+ if self._cached:
+ self.auditeddir[prefix] = res
if not res:
break