Patchwork [4,of,6,RFC] lock: add multilock class

login
register
mail settings
Submitter Angel Ezquerra
Date Dec. 24, 2014, 12:05 p.m.
Message ID <a0853216165f7995f5b8.1419422727@108.1.168.192.in-addr.arpa>
Download mbox | patch
Permalink /patch/7229/
State Superseded
Headers show

Comments

Angel Ezquerra - Dec. 24, 2014, 12:05 p.m.
# HG changeset patch
# User Angel Ezquerra <angel.ezquerra@gmail.com>
# Date 1419377089 -3600
#      Wed Dec 24 00:24:49 2014 +0100
# Node ID a0853216165f7995f5b81b44c188d4c7f5661c02
# Parent  3df32d91a2d02d2f7144529e242d4f92544f4a28
lock: add multilock class

This new multilock class is a lock container that behaves as a single lock.
This will be useful to implement full shared repositories.

The multilock releases its locks in the reverse order that it locks them, which
is in the same order that they are passed to the multilock constructor.

Patch

diff --git a/mercurial/lock.py b/mercurial/lock.py
--- a/mercurial/lock.py
+++ b/mercurial/lock.py
@@ -9,7 +9,18 @@ 
 import errno, os, socket, time
 import warnings
 
-class lock(object):
+class abstractlock(object):
+    '''define that interface that all lock classes must follow'''
+    def lock(self):
+        raise NotImplementedError('abstract method')
+    def trylock(self):
+        raise NotImplementedError('abstract method')
+    def testlock(self):
+        raise NotImplementedError('abstract method')
+    def release(self):
+        raise NotImplementedError('abstract method')
+
+class lock(abstractlock):
     '''An advisory lock held by one process to control access to a set
     of files.  Non-cooperating processes or incorrectly written scripts
     can ignore Mercurial's locking scheme and stomp all over the
@@ -150,6 +161,41 @@ 
             for callback in self.postrelease:
                 callback()
 
+class multilock(abstractlock):
+    """a group of locks that behave as one"""
+    def __init__(self, *locks):
+        self.locks = locks
+
+    def __del__(self):
+        for l in reversed(self.locks):
+            del l
+        self.locks = []
+
+    def lock(self):
+        for l in self.locks:
+            l.lock()
+
+    def trylock(self):
+        for l in self.locks:
+            l.trylock()
+
+    def testlock(self):
+        """return id of first valid lock, else None"""
+        for l in self.locks:
+            res = l.testlock()
+            if res is not None:
+                return res
+        return None
+
+    def release(self):
+        """release all locks executing their callback functions if any"""
+        for l in reversed(self.locks):
+            l.release()
+
+    @property
+    def held(self):
+        return max([l.held for l in self.locks])
+
 def release(*locks):
     for lock in locks:
         if lock is not None: