1
# Copyright (C) 2007 Canonical Ltd
1
# Copyright (C) 2007, 2008 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
"""Counted lock class"""
19
from __future__ import absolute_import
20
from bzrlib.errors import (
26
# TODO: Pass through lock tokens on lock_write and read, and return them...
28
# TODO: Allow upgrading read locks to write? Conceptually difficult.
31
26
class CountedLock(object):
32
27
"""Decorator around a lock that makes it reentrant.
34
29
This can be used with any object that provides a basic Lock interface,
35
30
including LockDirs and OS file locks.
32
:ivar _token: While a write lock is held, this is the token
38
36
def __init__(self, real_lock):
40
38
self._lock_mode = None
41
39
self._lock_count = 0
42
return "%s(%r)" % (self.__class__.__name__,
43
45
def break_lock(self):
44
46
self._real_lock.break_lock()
45
47
self._lock_mode = None
46
48
self._lock_count = 0
50
def get_physical_lock_status(self):
51
"""Return physical lock status.
53
Returns true if a lock is held on the transport. If no lock is held, or
54
the underlying locking mechanism does not support querying lock
55
status, false is returned.
58
return self._real_lock.peek() is not None
59
except NotImplementedError:
48
62
def is_locked(self):
49
63
return self._lock_mode is not None
56
70
it is taken in read mode.
58
72
if self._lock_mode:
59
assert self._lock_mode in ('r', 'w'), \
60
"invalid lock mode %r" % self._lock_mode
61
73
self._lock_count += 1
63
assert self._lock_count == 0
64
75
self._real_lock.lock_read()
65
76
self._lock_count = 1
66
77
self._lock_mode = 'r'
79
def lock_write(self, token=None):
69
80
"""Acquire the lock in write mode.
71
82
If the lock was originally acquired in read mode this will fail.
84
:param token: If given and the lock is already held,
85
then validate that we already hold the real
88
:returns: The token from the underlying lock.
73
90
if self._lock_count == 0:
74
assert self._lock_mode is None
75
self._real_lock.lock_write()
91
self._token = self._real_lock.lock_write(token=token)
76
92
self._lock_mode = 'w'
77
95
elif self._lock_mode != 'w':
78
raise ReadOnlyError(self)
96
raise errors.ReadOnlyError(self)
98
self._real_lock.validate_token(token)
82
103
if self._lock_count == 0:
83
raise LockError("%s not locked" % (self,))
104
raise errors.LockNotHeld(self)
84
105
elif self._lock_count == 1:
106
# these are decremented first; if we fail to unlock the most
107
# reasonable assumption is that we still don't have the lock
109
self._lock_mode = None
110
self._lock_count -= 1
85
111
self._real_lock.unlock()
86
self._lock_mode = None
113
self._lock_count -= 1