changeset 50187:f18e4608bb61

narrow: delegate the dirstate's narrow spec writing to the transaction This make it more transactional and will help us to simplify their backup. The implementation is not great, but it keep the patch simple as this is not the time for a larger refactoring yet.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Thu, 23 Feb 2023 03:25:44 +0100
parents 8bc14ac53a41
children 39256bee2ed9
files mercurial/localrepo.py mercurial/narrowspec.py
diffstat 2 files changed, 38 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/localrepo.py	Thu Feb 23 04:15:16 2023 +0100
+++ b/mercurial/localrepo.py	Thu Feb 23 03:25:44 2023 +0100
@@ -1470,6 +1470,7 @@
         self._postdsstatus = []
 
         self._pending_narrow_pats = None
+        self._pending_narrow_pats_dirstate = None
 
         # generic mapping between names and nodes
         self.names = namespaces.namespaces()
--- a/mercurial/narrowspec.py	Thu Feb 23 04:15:16 2023 +0100
+++ b/mercurial/narrowspec.py	Thu Feb 23 03:25:44 2023 +0100
@@ -212,8 +212,34 @@
 
 
 def copytoworkingcopy(repo):
+    repo = repo.unfiltered()
+    tr = repo.currenttransaction()
     spec = format(*repo.narrowpats)
-    repo.vfs.write(DIRSTATE_FILENAME, spec)
+    if tr is None:
+        repo.vfs.write(DIRSTATE_FILENAME, spec)
+    else:
+
+        reporef = weakref.ref(repo)
+
+        def clean_pending(tr):
+            r = reporef()
+            if r is not None:
+                r._pending_narrow_pats_dirstate = None
+
+        tr.addpostclose(b'narrow-spec-dirstate', clean_pending)
+        tr.addabort(b'narrow-spec-dirstate', clean_pending)
+        repo._pending_narrow_pats_dirstate = repo.narrowpats
+
+        def write_spec(f):
+            f.write(spec)
+
+        tr.addfilegenerator(
+            # XXX think about order at some point
+            b"narrow-spec-dirstate",
+            (DIRSTATE_FILENAME,),
+            write_spec,
+            location=b'plain',
+        )
 
 
 def savebackup(repo, backupname):
@@ -328,8 +354,10 @@
     if getattr(repo, '_updatingnarrowspec', False):
         return
     storespec = repo.narrowpats
-    wcspec = repo.vfs.tryread(DIRSTATE_FILENAME)
-    wcspec = parseconfig(repo.ui, wcspec)
+    wcspec = repo._pending_narrow_pats_dirstate
+    if wcspec is None:
+        oldspec = repo.vfs.tryread(DIRSTATE_FILENAME)
+        wcspec = parseconfig(repo.ui, oldspec)
     if wcspec != storespec:
         raise error.StateError(
             _(b"working copy's narrowspec is stale"),
@@ -343,11 +371,15 @@
     When assumeclean=True, files that are not known to be clean will also
     be deleted. It is then up to the caller to make sure they are clean.
     """
-    oldspec = repo.vfs.tryread(DIRSTATE_FILENAME)
+    old = repo._pending_narrow_pats_dirstate
+    if old is None:
+        oldspec = repo.vfs.tryread(DIRSTATE_FILENAME)
+        oldincludes, oldexcludes = parseconfig(repo.ui, oldspec)
+    else:
+        oldincludes, oldexcludes = old
     newincludes, newexcludes = repo.narrowpats
     repo._updatingnarrowspec = True
 
-    oldincludes, oldexcludes = parseconfig(repo.ui, oldspec)
     oldmatch = match(repo.root, include=oldincludes, exclude=oldexcludes)
     newmatch = match(repo.root, include=newincludes, exclude=newexcludes)
     addedmatch = matchmod.differencematcher(newmatch, oldmatch)