sparse: take lock before writing requirements
authorPierre-Yves David <pierre-yves.david@octobus.net>
Tue, 11 Jan 2022 06:40:44 +0100
changeset 48687 a62ba3345534
parent 48686 497c2655c71e
child 48688 4c1135d15700
sparse: take lock before writing requirements with `share-safe`, we will also write file in the store. So we take the `lock` before altering the requirements. Differential Revision: https://phab.mercurial-scm.org/D11993
mercurial/sparse.py
--- a/mercurial/sparse.py	Fri Jan 07 16:30:11 2022 +0100
+++ b/mercurial/sparse.py	Tue Jan 11 06:40:44 2022 +0100
@@ -600,38 +600,41 @@
     repo, includes, excludes, profiles, force=False, removing=False
 ):
     """Update the sparse config and working directory state."""
-    raw = repo.vfs.tryread(b'sparse')
-    oldincludes, oldexcludes, oldprofiles = parseconfig(repo.ui, raw, b'sparse')
-
-    oldstatus = repo.status()
-    oldmatch = matcher(repo)
-    oldrequires = set(repo.requirements)
+    with repo.lock():
+        raw = repo.vfs.tryread(b'sparse')
+        oldincludes, oldexcludes, oldprofiles = parseconfig(
+            repo.ui, raw, b'sparse'
+        )
 
-    # TODO remove this try..except once the matcher integrates better
-    # with dirstate. We currently have to write the updated config
-    # because that will invalidate the matcher cache and force a
-    # re-read. We ideally want to update the cached matcher on the
-    # repo instance then flush the new config to disk once wdir is
-    # updated. But this requires massive rework to matcher() and its
-    # consumers.
+        oldstatus = repo.status()
+        oldmatch = matcher(repo)
+        oldrequires = set(repo.requirements)
+
+        # TODO remove this try..except once the matcher integrates better
+        # with dirstate. We currently have to write the updated config
+        # because that will invalidate the matcher cache and force a
+        # re-read. We ideally want to update the cached matcher on the
+        # repo instance then flush the new config to disk once wdir is
+        # updated. But this requires massive rework to matcher() and its
+        # consumers.
 
-    if requirements.SPARSE_REQUIREMENT in oldrequires and removing:
-        repo.requirements.discard(requirements.SPARSE_REQUIREMENT)
-        scmutil.writereporequirements(repo)
-    elif requirements.SPARSE_REQUIREMENT not in oldrequires:
-        repo.requirements.add(requirements.SPARSE_REQUIREMENT)
-        scmutil.writereporequirements(repo)
+        if requirements.SPARSE_REQUIREMENT in oldrequires and removing:
+            repo.requirements.discard(requirements.SPARSE_REQUIREMENT)
+            scmutil.writereporequirements(repo)
+        elif requirements.SPARSE_REQUIREMENT not in oldrequires:
+            repo.requirements.add(requirements.SPARSE_REQUIREMENT)
+            scmutil.writereporequirements(repo)
 
-    try:
-        writeconfig(repo, includes, excludes, profiles)
-        return refreshwdir(repo, oldstatus, oldmatch, force=force)
-    except Exception:
-        if repo.requirements != oldrequires:
-            repo.requirements.clear()
-            repo.requirements |= oldrequires
-            scmutil.writereporequirements(repo)
-        writeconfig(repo, oldincludes, oldexcludes, oldprofiles)
-        raise
+        try:
+            writeconfig(repo, includes, excludes, profiles)
+            return refreshwdir(repo, oldstatus, oldmatch, force=force)
+        except Exception:
+            if repo.requirements != oldrequires:
+                repo.requirements.clear()
+                repo.requirements |= oldrequires
+                scmutil.writereporequirements(repo)
+            writeconfig(repo, oldincludes, oldexcludes, oldprofiles)
+            raise
 
 
 def clearrules(repo, force=False):