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"""
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
25
class CountedLock(object):
32
26
"""Decorator around a lock that makes it reentrant.
34
28
This can be used with any object that provides a basic Lock interface,
35
29
including LockDirs and OS file locks.
31
:ivar _token: While a write lock is held, this is the token
38
35
def __init__(self, real_lock):
40
37
self._lock_mode = None
41
38
self._lock_count = 0
41
return "%s(%r)" % (self.__class__.__name__,
43
44
def break_lock(self):
44
45
self._real_lock.break_lock()
45
46
self._lock_mode = None
46
47
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:
48
61
def is_locked(self):
49
62
return self._lock_mode is not None
56
69
it is taken in read mode.
58
71
if self._lock_mode:
59
assert self._lock_mode in ('r', 'w'), \
60
"invalid lock mode %r" % self._lock_mode
61
72
self._lock_count += 1
63
assert self._lock_count == 0
64
74
self._real_lock.lock_read()
65
75
self._lock_count = 1
66
76
self._lock_mode = 'r'
78
def lock_write(self, token=None):
69
79
"""Acquire the lock in write mode.
71
81
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.
73
89
if self._lock_count == 0:
74
assert self._lock_mode is None
75
self._real_lock.lock_write()
90
self._token = self._real_lock.lock_write(token=token)
76
91
self._lock_mode = 'w'
77
94
elif self._lock_mode != 'w':
78
raise ReadOnlyError(self)
95
raise errors.ReadOnlyError(self)
97
self._real_lock.validate_token(token)
82
102
if self._lock_count == 0:
83
raise LockError("%s not locked" % (self,))
103
raise errors.LockNotHeld(self)
84
104
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
108
self._lock_mode = None
109
self._lock_count -= 1
85
110
self._real_lock.unlock()
86
self._lock_mode = None
112
self._lock_count -= 1