/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
3474.1.2 by Martin Pool
CountedLock.unlock should raise LockNotHeld if appropriate
1
# Copyright (C) 2007, 2008 Canonical Ltd
2475.4.1 by Martin Pool
Start adding CountedLock class to partially replace LockableFiles
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2475.4.1 by Martin Pool
Start adding CountedLock class to partially replace LockableFiles
16
6379.6.7 by Jelmer Vernooij
Move importing from future until after doc string, otherwise the doc string will disappear.
17
"""Counted lock class"""
18
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
19
from . import (
3474.1.2 by Martin Pool
CountedLock.unlock should raise LockNotHeld if appropriate
20
    errors,
2475.4.1 by Martin Pool
Start adding CountedLock class to partially replace LockableFiles
21
    )
22
23
24
class CountedLock(object):
25
    """Decorator around a lock that makes it reentrant.
26
27
    This can be used with any object that provides a basic Lock interface,
28
    including LockDirs and OS file locks.
3407.2.19 by Martin Pool
CountedLock should manage lock tokens
29
7195.5.1 by Martin
Fix remaining whitespace lint in codebase
30
    :ivar _token: While a write lock is held, this is the token
3407.2.19 by Martin Pool
CountedLock should manage lock tokens
31
        for it.
2475.4.1 by Martin Pool
Start adding CountedLock class to partially replace LockableFiles
32
    """
33
34
    def __init__(self, real_lock):
35
        self._real_lock = real_lock
36
        self._lock_mode = None
37
        self._lock_count = 0
38
3474.1.2 by Martin Pool
CountedLock.unlock should raise LockNotHeld if appropriate
39
    def __repr__(self):
40
        return "%s(%r)" % (self.__class__.__name__,
7143.15.2 by Jelmer Vernooij
Run autopep8.
41
                           self._real_lock)
3474.1.2 by Martin Pool
CountedLock.unlock should raise LockNotHeld if appropriate
42
2475.4.1 by Martin Pool
Start adding CountedLock class to partially replace LockableFiles
43
    def break_lock(self):
44
        self._real_lock.break_lock()
45
        self._lock_mode = None
46
        self._lock_count = 0
47
4570.3.5 by Martin Pool
Add CountedLock.get_physical_lock_status
48
    def get_physical_lock_status(self):
49
        """Return physical lock status.
50
51
        Returns true if a lock is held on the transport. If no lock is held, or
52
        the underlying locking mechanism does not support querying lock
53
        status, false is returned.
54
        """
55
        try:
56
            return self._real_lock.peek() is not None
57
        except NotImplementedError:
58
            return False
59
2475.4.1 by Martin Pool
Start adding CountedLock class to partially replace LockableFiles
60
    def is_locked(self):
61
        return self._lock_mode is not None
62
63
    def lock_read(self):
64
        """Acquire the lock in read mode.
65
66
        If the lock is already held in either read or write mode this
67
        increments the count and succeeds.  If the lock is not already held,
68
        it is taken in read mode.
69
        """
70
        if self._lock_mode:
71
            self._lock_count += 1
72
        else:
73
            self._real_lock.lock_read()
74
            self._lock_count = 1
75
            self._lock_mode = 'r'
76
3407.2.20 by Martin Pool
Add lock token support to CountedLock
77
    def lock_write(self, token=None):
2475.4.1 by Martin Pool
Start adding CountedLock class to partially replace LockableFiles
78
        """Acquire the lock in write mode.
79
80
        If the lock was originally acquired in read mode this will fail.
3407.2.19 by Martin Pool
CountedLock should manage lock tokens
81
7195.5.1 by Martin
Fix remaining whitespace lint in codebase
82
        :param token: If given and the lock is already held,
3407.2.20 by Martin Pool
Add lock token support to CountedLock
83
            then validate that we already hold the real
84
            lock with this token.
85
3407.2.19 by Martin Pool
CountedLock should manage lock tokens
86
        :returns: The token from the underlying lock.
2475.4.1 by Martin Pool
Start adding CountedLock class to partially replace LockableFiles
87
        """
88
        if self._lock_count == 0:
3407.2.20 by Martin Pool
Add lock token support to CountedLock
89
            self._token = self._real_lock.lock_write(token=token)
2475.4.1 by Martin Pool
Start adding CountedLock class to partially replace LockableFiles
90
            self._lock_mode = 'w'
3474.1.3 by Martin Pool
CountedLock now handles and tests lock tokens
91
            self._lock_count += 1
3468.3.2 by Martin Pool
merge trunk
92
            return self._token
2475.4.1 by Martin Pool
Start adding CountedLock class to partially replace LockableFiles
93
        elif self._lock_mode != 'w':
3474.1.2 by Martin Pool
CountedLock.unlock should raise LockNotHeld if appropriate
94
            raise errors.ReadOnlyError(self)
3474.1.3 by Martin Pool
CountedLock now handles and tests lock tokens
95
        else:
96
            self._real_lock.validate_token(token)
97
            self._lock_count += 1
3468.3.4 by Martin Pool
CountedLock.lock_write should return existing known token
98
            return self._token
2475.4.1 by Martin Pool
Start adding CountedLock class to partially replace LockableFiles
99
100
    def unlock(self):
101
        if self._lock_count == 0:
3474.1.3 by Martin Pool
CountedLock now handles and tests lock tokens
102
            raise errors.LockNotHeld(self)
2475.4.1 by Martin Pool
Start adding CountedLock class to partially replace LockableFiles
103
        elif self._lock_count == 1:
3474.1.3 by Martin Pool
CountedLock now handles and tests lock tokens
104
            # these are decremented first; if we fail to unlock the most
105
            # reasonable assumption is that we still don't have the lock
106
            # anymore
107
            self._lock_mode = None
108
            self._lock_count -= 1
2475.4.1 by Martin Pool
Start adding CountedLock class to partially replace LockableFiles
109
            self._real_lock.unlock()
3474.1.3 by Martin Pool
CountedLock now handles and tests lock tokens
110
        else:
111
            self._lock_count -= 1