mercurial/lock.py
changeset 52725 0f2268783c11
parent 52645 4cb75772818d
--- a/mercurial/lock.py	Fri Dec 20 16:11:19 2024 +0100
+++ b/mercurial/lock.py	Thu Jan 30 09:23:16 2025 +0100
@@ -111,6 +111,24 @@
         raiseinterrupt(assertedsigs[0])
 
 
+def steal_lock(ui, vfs, lockname, stolen_lock, *args, **kwargs) -> lock:
+    """return a new lock that "steal" the locking made by a source lock
+
+    This is used during local clone when reloading a repository. If we could
+    remove the need for this during copy clone, we could remove this function.
+    """
+    new_lock = lock(vfs, lockname, 0, *args, dolock=False, **kwargs)
+
+    assert stolen_lock.f == new_lock.f
+    assert stolen_lock.held > 0
+    assert new_lock.held == 0
+    new_lock.held += 1
+    stolen_lock.held = None
+    if new_lock.acquirefn is not None:
+        new_lock.acquirefn()
+    return new_lock
+
+
 def trylock(ui, vfs, lockname, timeout, warntimeout, *args, **kwargs) -> lock:
     """return an acquired lock or raise an a LockHeld exception
 
@@ -240,7 +258,11 @@
         self.release(success=success)
 
     def __del__(self):
-        if self.held:
+        if self.held is None:
+            # lock has been stolen (during a local clone) and should never be
+            # touched again.
+            return
+        if self.held > 0:
             warnings.warn(
                 "use lock.release instead of del lock",
                 category=DeprecationWarning,
@@ -274,7 +296,10 @@
                 )
 
     def _trylock(self) -> None:
-        if self.held:
+        if self.held is None:
+            msg = "cannot acquire a lock after it was stolen"
+            raise error.ProgrammingError(msg)
+        if self.held > 0:
             self.held += 1
             return
         if lock._host is None:
@@ -380,6 +405,9 @@
 
         If the lock has been acquired multiple times, the actual release is
         delayed to the last release call."""
+        if self.held is None:
+            msg = "cannot release a lock after it was stolen"
+            raise error.ProgrammingError(msg)
         if self.held > 1:
             self.held -= 1
         elif self.held == 1: