changeset 48494:b74ee41addee stable

sparse: lock the store when updating requirements config Differential Revision: https://phab.mercurial-scm.org/D11817
author Arseniy Alekseyev <aalekseyev@janestreet.com>
date Mon, 29 Nov 2021 12:27:33 +0000
parents 50330d481640
children f447b90a4b11
files mercurial/hg.py mercurial/sparse.py tests/test-sparse-with-safe-share.t
diffstat 3 files changed, 22 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/hg.py	Tue Nov 16 17:35:57 2021 +0000
+++ b/mercurial/hg.py	Mon Nov 29 12:27:33 2021 +0000
@@ -12,6 +12,7 @@
 import os
 import shutil
 import stat
+import weakref
 
 from .i18n import _
 from .node import (
@@ -677,7 +678,7 @@
         srcpeer = source.peer()  # in case we were called with a localrepo
         branches = (None, branch or [])
         origsource = source = srcpeer.url()
-    srclock = destlock = cleandir = None
+    srclock = destlock = destwlock = cleandir = None
     destpeer = None
     try:
         revs, checkout = addbranchrevs(srcpeer, srcpeer, branches, revs)
@@ -865,6 +866,8 @@
                 requirements=dest_reqs,
             )
             destrepo = localrepo.makelocalrepository(ui, destrootpath)
+
+            destwlock = destrepo.wlock()
             destlock = destrepo.lock()
             from . import streamclone  # avoid cycle
 
@@ -873,6 +876,18 @@
             # we need to re-init the repo after manually copying the data
             # into it
             destpeer = peer(srcrepo, peeropts, dest)
+
+            # make the peer aware that is it already locked
+            #
+            # important:
+            #
+            #    We still need to release that lock at the end of the function
+            destpeer.local()._lockref = weakref.ref(destlock)
+            destpeer.local()._wlockref = weakref.ref(destwlock)
+            # dirstate also needs to be copied because `_wlockref` has a reference
+            # to it: this dirstate is saved to disk when the wlock is released
+            destpeer.local().dirstate = destrepo.dirstate
+
             srcrepo.hook(
                 b'outgoing', source=b'clone', node=srcrepo.nodeconstants.nullhex
             )
@@ -1040,6 +1055,8 @@
                     bookmarks.activate(destrepo, update)
             if destlock is not None:
                 release(destlock)
+            if destwlock is not None:
+                release(destlock)
             # here is a tiny windows were someone could end up writing the
             # repository before the cache are sure to be warm. This is "fine"
             # as the only "bad" outcome would be some slowness. That potential
@@ -1047,7 +1064,7 @@
             with destrepo.lock():
                 destrepo.updatecaches(caches=repositorymod.CACHES_POST_CLONE)
     finally:
-        release(srclock, destlock)
+        release(srclock, destlock, destwlock)
         if cleandir is not None:
             shutil.rmtree(cleandir, True)
         if srcpeer is not None:
--- a/mercurial/sparse.py	Tue Nov 16 17:35:57 2021 +0000
+++ b/mercurial/sparse.py	Mon Nov 29 12:27:33 2021 +0000
@@ -718,7 +718,7 @@
 
     The new config is written out and a working directory refresh is performed.
     """
-    with repo.wlock(), repo.dirstate.parentchange():
+    with repo.wlock(), repo.lock(), repo.dirstate.parentchange():
         raw = repo.vfs.tryread(b'sparse')
         oldinclude, oldexclude, oldprofiles = parseconfig(
             repo.ui, raw, b'sparse'
--- a/tests/test-sparse-with-safe-share.t	Tue Nov 16 17:35:57 2021 +0000
+++ b/tests/test-sparse-with-safe-share.t	Mon Nov 29 12:27:33 2021 +0000
@@ -16,10 +16,8 @@
   $ echo x > hide
   $ hg ci -Aqm 'initial'
 
-Verify basic --include
+Regression test: checks that this command correctly locks the store
+before updating the store [requirements] config.
 
   $ hg up -q 0
   $ hg debugsparse --include 'hide'
-  devel-warn: write with no lock: "requires" at: *mercurial/scmutil.py:1558 (writerequires) (glob)
-
-TODO: bug in sparse when used together with safe-share^