~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/lockable_files.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2011-08-17 08:40:16 UTC
  • mfrom: (5642.4.6 712474-module-available)
  • Revision ID: pqm@pqm.ubuntu.com-20110817084016-600z65qzqmmt44w7
(vila) ModuleAvailableFeature don't try to imported already imported
 modules. (Vincent Ladeuil)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2008, 2009 Canonical Ltd
 
1
# Copyright (C) 2005-2011 Canonical Ltd
2
2
#
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
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
from cStringIO import StringIO
18
 
 
19
17
from bzrlib.lazy_import import lazy_import
20
18
lazy_import(globals(), """
21
 
import codecs
22
19
import warnings
23
20
 
24
21
from bzrlib import (
34
31
from bzrlib.decorators import (
35
32
    only_raises,
36
33
    )
37
 
from bzrlib.symbol_versioning import (
38
 
    deprecated_in,
39
 
    deprecated_method,
40
 
    )
41
 
 
42
 
 
43
 
# XXX: The tracking here of lock counts and whether the lock is held is
44
 
# somewhat redundant with what's done in LockDir; the main difference is that
45
 
# LockableFiles permits reentrancy.
46
 
 
47
 
class _LockWarner(object):
48
 
    """Hold a counter for a lock and warn if GCed while the count is >= 1.
49
 
 
50
 
    This is separate from LockableFiles because putting a __del__ on
51
 
    LockableFiles can result in uncollectable cycles.
52
 
    """
53
 
 
54
 
    def __init__(self, repr):
55
 
        self.lock_count = 0
56
 
        self.repr = repr
57
 
 
58
 
    def __del__(self):
59
 
        if self.lock_count >= 1:
60
 
            # There should have been a try/finally to unlock this.
61
 
            warnings.warn("%r was gc'd while locked" % self.repr)
62
34
 
63
35
 
64
36
class LockableFiles(object):
75
47
    This class is now deprecated; code should move to using the Transport
76
48
    directly for file operations and using the lock or CountedLock for
77
49
    locking.
78
 
    
 
50
 
79
51
    :ivar _lock: The real underlying lock (e.g. a LockDir)
80
 
    :ivar _counted_lock: A lock decorated with a semaphore, so that it 
81
 
        can be re-entered.
 
52
    :ivar _lock_count: If _lock_mode is true, a positive count of the number
 
53
        of times the lock has been taken (and not yet released) *by this
 
54
        process*, through this particular object instance.
 
55
    :ivar _lock_mode: None, or 'r' or 'w'
82
56
    """
83
57
 
84
 
    # _lock_mode: None, or 'r' or 'w'
85
 
 
86
 
    # _lock_count: If _lock_mode is true, a positive count of the number of
87
 
    # times the lock has been taken *by this process*.
88
 
 
89
58
    def __init__(self, transport, lock_name, lock_class):
90
59
        """Create a LockableFiles group
91
60
 
99
68
        self.lock_name = lock_name
100
69
        self._transaction = None
101
70
        self._lock_mode = None
102
 
        self._lock_warner = _LockWarner(repr(self))
 
71
        self._lock_count = 0
103
72
        self._find_modes()
104
73
        esc_name = self._escape(lock_name)
105
74
        self._lock = lock_class(transport, esc_name,
118
87
    def __repr__(self):
119
88
        return '%s(%r)' % (self.__class__.__name__,
120
89
                           self._transport)
 
90
 
121
91
    def __str__(self):
122
92
        return 'LockableFiles(%s, %s)' % (self.lock_name, self._transport.base)
123
93
 
181
151
        some other way, and need to synchronise this object's state with that
182
152
        fact.
183
153
        """
184
 
        # TODO: Upgrade locking to support using a Transport,
185
 
        # and potentially a remote locking protocol
186
154
        if self._lock_mode:
187
 
            if self._lock_mode != 'w' or not self.get_transaction().writeable():
 
155
            if (self._lock_mode != 'w'
 
156
                or not self.get_transaction().writeable()):
188
157
                raise errors.ReadOnlyError(self)
189
158
            self._lock.validate_token(token)
190
 
            self._lock_warner.lock_count += 1
 
159
            self._lock_count += 1
191
160
            return self._token_from_lock
192
161
        else:
193
162
            token_from_lock = self._lock.lock_write(token=token)
194
163
            #traceback.print_stack()
195
164
            self._lock_mode = 'w'
196
 
            self._lock_warner.lock_count = 1
 
165
            self._lock_count = 1
197
166
            self._set_write_transaction()
198
167
            self._token_from_lock = token_from_lock
199
168
            return token_from_lock
202
171
        if self._lock_mode:
203
172
            if self._lock_mode not in ('r', 'w'):
204
173
                raise ValueError("invalid lock mode %r" % (self._lock_mode,))
205
 
            self._lock_warner.lock_count += 1
 
174
            self._lock_count += 1
206
175
        else:
207
176
            self._lock.lock_read()
208
177
            #traceback.print_stack()
209
178
            self._lock_mode = 'r'
210
 
            self._lock_warner.lock_count = 1
 
179
            self._lock_count = 1
211
180
            self._set_read_transaction()
212
181
 
213
182
    def _set_read_transaction(self):
224
193
    def unlock(self):
225
194
        if not self._lock_mode:
226
195
            return lock.cant_unlock_not_held(self)
227
 
        if self._lock_warner.lock_count > 1:
228
 
            self._lock_warner.lock_count -= 1
 
196
        if self._lock_count > 1:
 
197
            self._lock_count -= 1
229
198
        else:
230
199
            #traceback.print_stack()
231
200
            self._finish_transaction()
232
201
            try:
233
202
                self._lock.unlock()
234
203
            finally:
235
 
                self._lock_mode = self._lock_warner.lock_count = None
236
 
 
237
 
    @property
238
 
    def _lock_count(self):
239
 
        return self._lock_warner.lock_count
 
204
                self._lock_mode = self._lock_count = None
240
205
 
241
206
    def is_locked(self):
242
207
        """Return true if this LockableFiles group is locked"""
243
 
        return self._lock_warner.lock_count >= 1
 
208
        return self._lock_count >= 1
244
209
 
245
210
    def get_physical_lock_status(self):
246
211
        """Return physical lock status.
332
297
    def validate_token(self, token):
333
298
        if token is not None:
334
299
            raise errors.TokenLockingNotSupported(self)
335