Rev 3332: * ``LockDir`` lock acquisition and release now trigger hooks allowing in http://people.ubuntu.com/~robertc/baz2.0/physicallock.hooks
Robert Collins
robertc at robertcollins.net
Fri Apr 4 03:15:28 BST 2008
At http://people.ubuntu.com/~robertc/baz2.0/physicallock.hooks
------------------------------------------------------------
revno: 3332
revision-id: robertc at robertcollins.net-20080404021333-13wfvylrgmvcp3gz
parent: pqm at pqm.ubuntu.com-20080403080121-tbx3clqp8wqe776c
committer: Robert Collins <robertc at robertcollins.net>
branch nick: PhysicalLock.hooks
timestamp: Fri 2008-04-04 13:13:33 +1100
message:
* ``LockDir`` lock acquisition and release now trigger hooks allowing
introspection of locking activity. (Robert Collins)
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/help_topics/en/hooks.txt hooks.txt-20070830033044-xxu2rced13f72dka-1
bzrlib/lock.py lock.py-20050527050856-ec090bb51bc03349
bzrlib/lockdir.py lockdir.py-20060220222025-98258adf27fbdda3
bzrlib/tests/test_lockdir.py test_lockdir.py-20060220222025-33d4221569a3d600
=== modified file 'NEWS'
--- a/NEWS 2008-04-03 08:01:21 +0000
+++ b/NEWS 2008-04-04 02:13:33 +0000
@@ -44,6 +44,9 @@
by forcing it to recv 64k at a time when reading lines in HTTP headers,
rather than just 1 byte at a time. (Andrew Bennetts)
+ * ``LockDir`` lock acquisition and release now trigger hooks allowing
+ introspection of locking activity. (Robert Collins)
+
* Log --short and --line are much faster when -r is not specified.
(Aaron Bentley)
=== modified file 'bzrlib/help_topics/en/hooks.txt'
--- a/bzrlib/help_topics/en/hooks.txt 2007-12-17 02:00:45 +0000
+++ b/bzrlib/help_topics/en/hooks.txt 2008-04-04 02:13:33 +0000
@@ -1,5 +1,5 @@
-Hooks
-=====
+Branch Hooks
+============
post_push
---------
@@ -85,6 +85,23 @@
The hook signature is (branch, revision_history), and the branch will be
write-locked.
+
+PhysicalLock hooks
+==================
+
+These are hooked into via bzrlib.lock.hooks.
+
+acquired
+--------
+
+Called with a LockResult object when a lock has been successfully acquired.
+
+released
+--------
+
+Called with a LockResult object when a lock has been successfully released.
+
+
See also `Using hooks`_ in the User Guide.
.. _Using hooks: ../user-guide/index.html#using-hooks
=== modified file 'bzrlib/lock.py'
--- a/bzrlib/lock.py 2007-10-03 08:06:44 +0000
+++ b/bzrlib/lock.py 2008-04-04 02:13:33 +0000
@@ -42,6 +42,40 @@
osutils,
trace,
)
+from bzrlib.hooks import Hooks
+
+
+class PhysicalLockHooks(Hooks):
+ """hooks for physical lock activity."""
+
+ def __init__(self):
+ """Create the default hooks.
+
+ There are no default hooks present.
+ """
+ Hooks.__init__(self)
+ # Introduced in 1.4:
+ # invoked when a physical lock has been successfully acquired.
+ self['acquired'] = []
+ # Introduced in 1.5:
+ # invoked when a physical lock has been successfully released.
+ self['released'] = []
+
+
+# The hooks instance clients should register against. Do *NOT* import this
+# symbol, always reference it through lock.hooks.
+hooks = PhysicalLockHooks()
+
+
+class LockResult(object):
+
+ def __init__(self, lock, details=None):
+ """Create a lock result for lock with optional details about the lock."""
+ self.lock = lock
+ self.details = details
+
+ def __eq__(self, other):
+ return self.lock == other.lock and self.details == other.details
class _OSLock(object):
=== modified file 'bzrlib/lockdir.py'
--- a/bzrlib/lockdir.py 2007-10-03 08:06:44 +0000
+++ b/bzrlib/lockdir.py 2008-04-04 02:13:33 +0000
@@ -110,6 +110,7 @@
from bzrlib import (
debug,
errors,
+ lock,
)
import bzrlib.config
from bzrlib.errors import (
@@ -298,6 +299,7 @@
self._locked_via_token = False
self._lock_held = False
else:
+ old_nonce = self.nonce
# rename before deleting, because we can't atomically remove the
# whole tree
start_time = time.time()
@@ -323,6 +325,9 @@
self.transport.delete_tree(tmpname)
self._trace("... unlock succeeded after %dms",
(time.time() - start_time) * 1000)
+ result = lock.LockResult(self, old_nonce)
+ for hook in lock.hooks['released']:
+ hook(result)
def break_lock(self):
"""Break a lock not held by this instance of LockDir.
@@ -455,7 +460,11 @@
"""
if self._fake_read_lock:
raise LockContention(self)
- return self._attempt_lock()
+ result = self._attempt_lock()
+ hook_result = lock.LockResult(self, result)
+ for hook in lock.hooks['acquired']:
+ hook(hook_result)
+ return result
def wait_lock(self, timeout=None, poll=None, max_attempts=None):
"""Wait a certain period for a lock.
=== modified file 'bzrlib/tests/test_lockdir.py'
--- a/bzrlib/tests/test_lockdir.py 2007-12-17 15:17:28 +0000
+++ b/bzrlib/tests/test_lockdir.py 2008-04-04 02:13:33 +0000
@@ -25,6 +25,7 @@
from bzrlib import (
config,
errors,
+ lock,
osutils,
tests,
transport,
@@ -645,3 +646,68 @@
self.assertRaises(errors.LockContention, ld2.attempt_lock)
# no kibble
check_dir(['held'])
+
+ def record_hook(self, result):
+ self._calls.append(result)
+
+ def reset_hooks(self):
+ self._old_hooks = lock.hooks
+ self.addCleanup(self.restore_hooks)
+ lock.hooks = lock.PhysicalLockHooks()
+
+ def restore_hooks(self):
+ lock.hooks = self._old_hooks
+
+ def test_PhysicalLock_dot_acquired_success(self):
+ # the PhysicalLock.acquired hook fires when a lock is acquired.
+ self._calls = []
+ self.reset_hooks()
+ lock.hooks.install_hook('acquired', self.record_hook)
+ ld = self.get_lock()
+ ld.create()
+ self.assertEqual([], self._calls)
+ result = ld.attempt_lock()
+ self.assertEqual([lock.LockResult(ld, result)], self._calls)
+ ld.unlock()
+ self.assertEqual([lock.LockResult(ld, result)], self._calls)
+
+ def test_PhysicalLock_dot_acquired_fail(self):
+ # the PhysicalLock.acquired hook does not fire on failure.
+ self._calls = []
+ self.reset_hooks()
+ ld = self.get_lock()
+ ld.create()
+ ld2 = self.get_lock()
+ ld2.attempt_lock()
+ # install a lock hook now, when the disk lock is locked
+ lock.hooks.install_hook('acquired', self.record_hook)
+ self.assertRaises(errors.LockContention, ld.attempt_lock)
+ self.assertEqual([], self._calls)
+ ld2.unlock()
+ self.assertEqual([], self._calls)
+
+ def test_PhysicalLock_dot_released_success(self):
+ # the PhysicalLock.released hook fires when a lock is acquired.
+ self._calls = []
+ self.reset_hooks()
+ lock.hooks.install_hook('released', self.record_hook)
+ ld = self.get_lock()
+ ld.create()
+ self.assertEqual([], self._calls)
+ result = ld.attempt_lock()
+ self.assertEqual([], self._calls)
+ ld.unlock()
+ self.assertEqual([lock.LockResult(ld, result)], self._calls)
+
+ def test_PhysicalLock_dot_released_fail(self):
+ # the PhysicalLock.released hook does not fire on failure.
+ self._calls = []
+ self.reset_hooks()
+ ld = self.get_lock()
+ ld.create()
+ ld2 = self.get_lock()
+ ld.attempt_lock()
+ ld2.force_break(ld2.peek())
+ lock.hooks.install_hook('released', self.record_hook)
+ self.assertRaises(LockBroken, ld.unlock)
+ self.assertEqual([], self._calls)
More information about the bazaar-commits
mailing list