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
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.
54
56
it is taken in read mode.
56
58
if self._lock_mode:
59
assert self._lock_mode in ('r', 'w'), \
60
"invalid lock mode %r" % self._lock_mode
57
61
self._lock_count += 1
63
assert self._lock_count == 0
59
64
self._real_lock.lock_read()
60
65
self._lock_count = 1
61
66
self._lock_mode = 'r'
63
def lock_write(self, token=None):
64
69
"""Acquire the lock in write mode.
66
71
If the lock was originally acquired in read mode this will fail.
68
:param token: If non-None, reacquire the lock using this token.
70
73
if self._lock_count == 0:
71
return_token = self._real_lock.lock_write(token)
74
assert self._lock_mode is None
75
self._real_lock.lock_write()
72
76
self._lock_mode = 'w'
75
77
elif self._lock_mode != 'w':
76
raise errors.ReadOnlyError(self)
78
self._real_lock.validate_token(token)
78
raise ReadOnlyError(self)
83
82
if self._lock_count == 0:
84
raise errors.LockNotHeld(self)
83
raise LockError("%s not locked" % (self,))
85
84
elif self._lock_count == 1:
86
# these are decremented first; if we fail to unlock the most
87
# reasonable assumption is that we still don't have the lock
85
self._real_lock.unlock()
89
86
self._lock_mode = None
91
self._real_lock.unlock()