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):
57
56
it is taken in read mode.
59
58
if self._lock_mode:
59
assert self._lock_mode in ('r', 'w'), \
60
"invalid lock mode %r" % self._lock_mode
60
61
self._lock_count += 1
63
assert self._lock_count == 0
62
64
self._real_lock.lock_read()
63
65
self._lock_count = 1
64
66
self._lock_mode = 'r'
66
def lock_write(self, token=None):
67
69
"""Acquire the lock in write mode.
69
71
If the lock was originally acquired in read mode this will fail.
71
:param token: If given and the lock is already held,
72
then validate that we already hold the real
75
:returns: The token from the underlying lock.
77
73
if self._lock_count == 0:
78
self._token = self._real_lock.lock_write(token=token)
74
assert self._lock_mode is None
75
self._real_lock.lock_write()
79
76
self._lock_mode = 'w'
82
77
elif self._lock_mode != 'w':
83
raise errors.ReadOnlyError(self)
85
self._real_lock.validate_token(token)
78
raise ReadOnlyError(self)
90
82
if self._lock_count == 0:
91
raise errors.LockNotHeld(self)
83
raise LockError("%s not locked" % (self,))
92
84
elif self._lock_count == 1:
93
# these are decremented first; if we fail to unlock the most
94
# reasonable assumption is that we still don't have the lock
85
self._real_lock.unlock()
96
86
self._lock_mode = None
98
self._real_lock.unlock()
100
self._lock_count -= 1