changeset 51634:3b69324d9535 stable

exchange: fix locking to actually be scoped The previous code was taking locks before entering with statements, so exception before the with statement would not release the lock (except for garbage collection). We need to move to a try except here because the logic is more complicated.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Tue, 11 Jun 2024 11:14:13 +0200
parents 429d57227e7f
children fcc149f3fdcb
files mercurial/exchange.py
diffstat 1 files changed, 40 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/exchange.py	Tue Jun 11 11:13:36 2024 +0200
+++ b/mercurial/exchange.py	Tue Jun 11 11:14:13 2024 +0200
@@ -466,42 +466,46 @@
     # get lock as we might write phase data
     wlock = lock = None
     try:
-        # bundle2 push may receive a reply bundle touching bookmarks
-        # requiring the wlock. Take it now to ensure proper ordering.
-        maypushback = pushop.ui.configbool(b'experimental', b'bundle2.pushback')
-        if (
-            (not _forcebundle1(pushop))
-            and maypushback
-            and not bookmod.bookmarksinstore(repo)
-        ):
-            wlock = pushop.repo.wlock()
-        lock = pushop.repo.lock()
-        pushop.trmanager = transactionmanager(
-            pushop.repo, b'push-response', pushop.remote.url()
-        )
-    except error.LockUnavailable as err:
-        # source repo cannot be locked.
-        # We do not abort the push, but just disable the local phase
-        # synchronisation.
-        msg = b'cannot lock source repository: %s\n' % stringutil.forcebytestr(
-            err
-        )
-        pushop.ui.debug(msg)
-
-    with wlock or util.nullcontextmanager():
-        with lock or util.nullcontextmanager():
-            with pushop.trmanager or util.nullcontextmanager():
-                pushop.repo.checkpush(pushop)
-                _checkpublish(pushop)
-                _pushdiscovery(pushop)
-                if not pushop.force:
-                    _checksubrepostate(pushop)
-                if not _forcebundle1(pushop):
-                    _pushbundle2(pushop)
-                _pushchangeset(pushop)
-                _pushsyncphase(pushop)
-                _pushobsolete(pushop)
-                _pushbookmark(pushop)
+        try:
+            # bundle2 push may receive a reply bundle touching bookmarks
+            # requiring the wlock. Take it now to ensure proper ordering.
+            maypushback = pushop.ui.configbool(
+                b'experimental',
+                b'bundle2.pushback',
+            )
+            if (
+                (not _forcebundle1(pushop))
+                and maypushback
+                and not bookmod.bookmarksinstore(repo)
+            ):
+                wlock = pushop.repo.wlock()
+            lock = pushop.repo.lock()
+            pushop.trmanager = transactionmanager(
+                pushop.repo, b'push-response', pushop.remote.url()
+            )
+        except error.LockUnavailable as err:
+            # source repo cannot be locked.
+            # We do not abort the push, but just disable the local phase
+            # synchronisation.
+            msg = b'cannot lock source repository: %s\n'
+            msg %= stringutil.forcebytestr(err)
+            pushop.ui.debug(msg)
+
+        pushop.repo.checkpush(pushop)
+        _checkpublish(pushop)
+        _pushdiscovery(pushop)
+        if not pushop.force:
+            _checksubrepostate(pushop)
+        if not _forcebundle1(pushop):
+            _pushbundle2(pushop)
+        _pushchangeset(pushop)
+        _pushsyncphase(pushop)
+        _pushobsolete(pushop)
+        _pushbookmark(pushop)
+        if pushop.trmanager is not None:
+            pushop.trmanager.close()
+    finally:
+        lockmod.release(pushop.trmanager, lock, wlock)
 
     if repo.ui.configbool(b'experimental', b'remotenames'):
         logexchange.pullremotenames(repo, remote)