Rev 3479: (mbp) CountedLock support for lock tokens in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Fri Jun 6 08:08:16 BST 2008


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 3479
revision-id:pqm at pqm.ubuntu.com-20080606070807-q0ro9i4kgllr5mbu
parent: pqm at pqm.ubuntu.com-20080605215009-3svreze778r0n4xv
parent: mbp at sourcefrog.net-20080605092259-keruhi6qrgf9ikax
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Fri 2008-06-06 08:08:07 +0100
message:
  (mbp) CountedLock support for lock tokens
modified:
  bzrlib/counted_lock.py         counted_lock.py-20070502135927-7dk86io3ok7ctx6k-1
  bzrlib/tests/test_counted_lock.py test_counted_lock.py-20070502135927-7dk86io3ok7ctx6k-2
  bzrlib/tests/test_lockable_files.py test_lockable_files.py-20051225183927-365c7fd99591caf1
    ------------------------------------------------------------
    revno: 3474.1.3
    revision-id:mbp at sourcefrog.net-20080605092259-keruhi6qrgf9ikax
    parent: mbp at sourcefrog.net-20080605075929-j5pet0dpcnj32r7x
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: countedlock
    timestamp: Thu 2008-06-05 19:22:59 +1000
    message:
      CountedLock now handles and tests lock tokens
    modified:
      bzrlib/counted_lock.py         counted_lock.py-20070502135927-7dk86io3ok7ctx6k-1
      bzrlib/tests/test_counted_lock.py test_counted_lock.py-20070502135927-7dk86io3ok7ctx6k-2
    ------------------------------------------------------------
    revno: 3474.1.2
    revision-id:mbp at sourcefrog.net-20080605075929-j5pet0dpcnj32r7x
    parent: mbp at sourcefrog.net-20080605064944-ky99sgxq3cg5gr38
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: countedlock
    timestamp: Thu 2008-06-05 17:59:29 +1000
    message:
      CountedLock.unlock should raise LockNotHeld if appropriate
    modified:
      bzrlib/counted_lock.py         counted_lock.py-20070502135927-7dk86io3ok7ctx6k-1
      bzrlib/tests/test_counted_lock.py test_counted_lock.py-20070502135927-7dk86io3ok7ctx6k-2
    ------------------------------------------------------------
    revno: 3474.1.1
    revision-id:mbp at sourcefrog.net-20080605064944-ky99sgxq3cg5gr38
    parent: pqm at pqm.ubuntu.com-20080605040505-i9kqxg2fps2qjdi0
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: countedlock
    timestamp: Thu 2008-06-05 16:49:44 +1000
    message:
      Better reporting of inapplicable lockable_files tests
    modified:
      bzrlib/tests/test_lockable_files.py test_lockable_files.py-20051225183927-365c7fd99591caf1
=== modified file 'bzrlib/counted_lock.py'
--- a/bzrlib/counted_lock.py	2008-04-24 07:22:53 +0000
+++ b/bzrlib/counted_lock.py	2008-06-05 09:22:59 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2007 Canonical Ltd
+# Copyright (C) 2007, 2008 Canonical Ltd
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -17,17 +17,11 @@
 """Counted lock class"""
 
 
-from bzrlib.errors import (
-    LockError,
-    ReadOnlyError,
+from bzrlib import (
+    errors,
     )
 
 
-# TODO: Pass through lock tokens on lock_write and read, and return them...
-#
-# TODO: Allow upgrading read locks to write?  Conceptually difficult.
-
-
 class CountedLock(object):
     """Decorator around a lock that makes it reentrant.
 
@@ -40,6 +34,10 @@
         self._lock_mode = None
         self._lock_count = 0
 
+    def __repr__(self):
+        return "%s(%r)" % (self.__class__.__name__,
+            self._real_lock)
+
     def break_lock(self):
         self._real_lock.break_lock()
         self._lock_mode = None
@@ -62,22 +60,34 @@
             self._lock_count = 1
             self._lock_mode = 'r'
 
-    def lock_write(self):
+    def lock_write(self, token=None):
         """Acquire the lock in write mode.
 
         If the lock was originally acquired in read mode this will fail.
+
+        :param token: If non-None, reacquire the lock using this token.
         """
         if self._lock_count == 0:
-            self._real_lock.lock_write()
+            return_token = self._real_lock.lock_write(token)
             self._lock_mode = 'w'
+            self._lock_count += 1
+            return return_token
         elif self._lock_mode != 'w':
-            raise ReadOnlyError(self)
-        self._lock_count += 1
+            raise errors.ReadOnlyError(self)
+        else:
+            self._real_lock.validate_token(token)
+            self._lock_count += 1
+            return token
 
     def unlock(self):
         if self._lock_count == 0:
-            raise LockError("%s not locked" % (self,))
+            raise errors.LockNotHeld(self)
         elif self._lock_count == 1:
+            # these are decremented first; if we fail to unlock the most
+            # reasonable assumption is that we still don't have the lock
+            # anymore
+            self._lock_mode = None
+            self._lock_count -= 1
             self._real_lock.unlock()
-            self._lock_mode = None
-        self._lock_count -= 1
+        else:
+            self._lock_count -= 1

=== modified file 'bzrlib/tests/test_counted_lock.py'
--- a/bzrlib/tests/test_counted_lock.py	2007-05-02 14:00:53 +0000
+++ b/bzrlib/tests/test_counted_lock.py	2008-06-05 09:22:59 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2007 Canonical Ltd
+# Copyright (C) 2007, 2008 Canonical Ltd
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -19,7 +19,9 @@
 from bzrlib.counted_lock import CountedLock
 from bzrlib.errors import (
     LockError,
+    LockNotHeld,
     ReadOnlyError,
+    TokenMismatch,
     )
 from bzrlib.tests import TestCase
 
@@ -39,10 +41,13 @@
         self._lock_mode = 'r'
         self._calls.append('lock_read')
 
-    def lock_write(self):
+    def lock_write(self, token=None):
+        if token not in (None, 'token'):
+            raise TokenMismatch(token, 'token')
         self._assert_not_locked()
         self._lock_mode = 'w'
         self._calls.append('lock_write')
+        return 'token'
 
     def unlock(self):
         self._assert_locked()
@@ -62,6 +67,15 @@
             raise LockError("%s is already locked in mode %r" %
                 (self, self._lock_mode))
 
+    def validate_token(self, token):
+        if token == 'token':
+            # already held by this caller
+            return 'token'
+        elif token is None:
+            return
+        else:
+            raise TokenMismatch(token, 'token')
+
 
 class TestDummyLock(TestCase):
 
@@ -131,7 +145,7 @@
     def test_unlock_not_locked(self):
         real_lock = DummyLock()
         l = CountedLock(real_lock)
-        self.assertRaises(LockError, l.unlock)
+        self.assertRaises(LockNotHeld, l.unlock)
 
     def test_read_lock_while_write_locked(self):
         real_lock = DummyLock()

=== modified file 'bzrlib/tests/test_lockable_files.py'
--- a/bzrlib/tests/test_lockable_files.py	2008-05-12 02:29:34 +0000
+++ b/bzrlib/tests/test_lockable_files.py	2008-06-05 06:49:44 +0000
@@ -27,7 +27,10 @@
 from bzrlib.symbol_versioning import (
     deprecated_in,
     )
-from bzrlib.tests import TestCaseInTempDir
+from bzrlib.tests import (
+    TestCaseInTempDir,
+    TestNotApplicable,
+    )
 from bzrlib.tests.test_smart import TestCaseWithSmartMedium
 from bzrlib.tests.test_transactions import DummyWeave
 from bzrlib.transactions import (PassThroughTransaction,
@@ -154,7 +157,7 @@
         except NotImplementedError:
             # this lock cannot be broken
             self.lockable.unlock()
-            return
+            raise TestNotApplicable("%r is not breakable" % (self.lockable,))
         l2 = self.get_lockable()
         orig_factory = bzrlib.ui.ui_factory
         # silent ui - no need for stdout
@@ -177,7 +180,7 @@
             if token is not None:
                 # This test does not apply, because this lockable supports
                 # tokens.
-                return
+                raise TestNotApplicable("%r uses tokens" % (self.lockable,))
             self.assertRaises(errors.TokenLockingNotSupported,
                               self.lockable.lock_write, token='token')
         finally:
@@ -371,7 +374,10 @@
         super(TestLockableFiles_TransportLock, self).tearDown()
         # free the subtransport so that we do not get a 5 second
         # timeout due to the SFTP connection cache.
-        del self.sub_transport
+        try:
+            del self.sub_transport
+        except AttributeError:
+            pass
 
     def get_lockable(self):
         return LockableFiles(self.sub_transport, 'my-lock', TransportLock)




More information about the bazaar-commits mailing list