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

login
register
mail settings
Submitter Angel Ezquerra
Date Dec. 26, 2014, 11:46 a.m.
Message ID <dd180345dd166fc51d06.1419594412@108.1.168.192.in-addr.arpa>
Download mbox | patch
Permalink /patch/7245/
State Changes Requested
Headers show

Comments

Angel Ezquerra - Dec. 26, 2014, 11:46 a.m.
# HG changeset patch
# User Angel Ezquerra <angel.ezquerra@gmail.com>
# Date 1419377089 -3600
#      Wed Dec 24 00:24:49 2014 +0100
# Node ID dd180345dd166fc51d061a8041e014f320c20d6c
# Parent  f03bef0e2051c76f7dcfd5f580f58037e9dac50a
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: