merge: cache the fs checks made during [_checkunknownfiles]
authorArseniy Alekseyev <aalekseyev@janestreet.com>
Wed, 04 Jan 2023 17:14:33 +0000
changeset 49889 c7624b1ac8b4
parent 49888 76d1e9f229fe
child 49890 5f664401dd03
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
mercurial/merge.py
mercurial/pathutil.py
--- 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