1
# Copyright (C) 2007, 2008 Canonical Ltd
1
# Copyright (C) 2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
"""Counted lock class"""
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.
25
31
class CountedLock(object):
26
32
"""Decorator around a lock that makes it reentrant.
28
34
This can be used with any object that provides a basic Lock interface,
29
35
including LockDirs and OS file locks.
31
:ivar _token: While a write lock is held, this is the token
35
38
def __init__(self, real_lock):
37
40
self._lock_mode = None
38
41
self._lock_count = 0
41
return "%s(%r)" % (self.__class__.__name__,
44
43
def break_lock(self):
45
44
self._real_lock.break_lock()
46
45
self._lock_mode = None
47
46
self._lock_count = 0
49
def get_physical_lock_status(self):
50
"""Return physical lock status.
52
Returns true if a lock is held on the transport. If no lock is held, or
53
the underlying locking mechanism does not support querying lock
54
status, false is returned.
57
return self._real_lock.peek() is not None
58
except NotImplementedError:
61
48
def is_locked(self):
62
49
return self._lock_mode is not None
69
56
it is taken in read mode.
71
58
if self._lock_mode:
59
assert self._lock_mode in ('r', 'w'), \
60
"invalid lock mode %r" % self._lock_mode
72
61
self._lock_count += 1
63
assert self._lock_count == 0
74
64
self._real_lock.lock_read()
75
65
self._lock_count = 1
76
66
self._lock_mode = 'r'
78
def lock_write(self, token=None):
79
69
"""Acquire the lock in write mode.
81
71
If the lock was originally acquired in read mode this will fail.
83
:param token: If given and the lock is already held,
84
then validate that we already hold the real
87
:returns: The token from the underlying lock.
89
73
if self._lock_count == 0:
90
self._token = self._real_lock.lock_write(token=token)
74
assert self._lock_mode is None
75
self._real_lock.lock_write()
91
76
self._lock_mode = 'w'
94
77
elif self._lock_mode != 'w':
95
raise errors.ReadOnlyError(self)
97
self._real_lock.validate_token(token)
78
raise ReadOnlyError(self)
102
82
if self._lock_count == 0:
103
raise errors.LockNotHeld(self)
83
raise LockError("%s not locked" % (self,))
104
84
elif self._lock_count == 1:
105
# these are decremented first; if we fail to unlock the most
106
# reasonable assumption is that we still don't have the lock
85
self._real_lock.unlock()
108
86
self._lock_mode = None
109
self._lock_count -= 1
110
self._real_lock.unlock()
112
self._lock_count -= 1