~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/lockable_files.py

  • Committer: Patch Queue Manager
  • Date: 2014-05-08 02:56:29 UTC
  • mfrom: (6596.1.1 bzr)
  • Revision ID: pqm@pqm.ubuntu.com-20140508025629-de62pqrditrp349y
(richard-wilbur) Jelmer: Don't pass blob to file.writelines(),
 but rather to file.write(). (Dimitri John Ledkov)

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 __future__ import absolute_import
 
18
 
17
19
from bzrlib.lazy_import import lazy_import
18
20
lazy_import(globals(), """
19
 
import codecs
20
21
import warnings
21
22
 
22
23
from bzrlib import (
34
35
    )
35
36
 
36
37
 
37
 
# XXX: The tracking here of lock counts and whether the lock is held is
38
 
# somewhat redundant with what's done in LockDir; the main difference is that
39
 
# LockableFiles permits reentrancy.
40
 
 
41
 
class _LockWarner(object):
42
 
    """Hold a counter for a lock and warn if GCed while the count is >= 1.
43
 
 
44
 
    This is separate from LockableFiles because putting a __del__ on
45
 
    LockableFiles can result in uncollectable cycles.
46
 
    """
47
 
 
48
 
    def __init__(self, repr):
49
 
        self.lock_count = 0
50
 
        self.repr = repr
51
 
 
52
 
    def __del__(self):
53
 
        if self.lock_count >= 1:
54
 
            # There should have been a try/finally to unlock this.
55
 
            warnings.warn("%r was gc'd while locked" % self.repr)
56
 
 
57
 
 
58
38
class LockableFiles(object):
59
39
    """Object representing a set of related files locked within the same scope.
60
40
 
69
49
    This class is now deprecated; code should move to using the Transport
70
50
    directly for file operations and using the lock or CountedLock for
71
51
    locking.
72
 
    
 
52
 
73
53
    :ivar _lock: The real underlying lock (e.g. a LockDir)
74
 
    :ivar _counted_lock: A lock decorated with a semaphore, so that it 
75
 
        can be re-entered.
 
54
    :ivar _lock_count: If _lock_mode is true, a positive count of the number
 
55
        of times the lock has been taken (and not yet released) *by this
 
56
        process*, through this particular object instance.
 
57
    :ivar _lock_mode: None, or 'r' or 'w'
76
58
    """
77
59
 
78
 
    # _lock_mode: None, or 'r' or 'w'
79
 
 
80
 
    # _lock_count: If _lock_mode is true, a positive count of the number of
81
 
    # times the lock has been taken *by this process*.
82
 
 
83
60
    def __init__(self, transport, lock_name, lock_class):
84
61
        """Create a LockableFiles group
85
62
 
93
70
        self.lock_name = lock_name
94
71
        self._transaction = None
95
72
        self._lock_mode = None
96
 
        self._lock_warner = _LockWarner(repr(self))
 
73
        self._lock_count = 0
97
74
        self._find_modes()
98
75
        esc_name = self._escape(lock_name)
99
76
        self._lock = lock_class(transport, esc_name,
112
89
    def __repr__(self):
113
90
        return '%s(%r)' % (self.__class__.__name__,
114
91
                           self._transport)
 
92
 
115
93
    def __str__(self):
116
94
        return 'LockableFiles(%s, %s)' % (self.lock_name, self._transport.base)
117
95
 
175
153
        some other way, and need to synchronise this object's state with that
176
154
        fact.
177
155
        """
178
 
        # TODO: Upgrade locking to support using a Transport,
179
 
        # and potentially a remote locking protocol
180
156
        if self._lock_mode:
181
 
            if self._lock_mode != 'w' or not self.get_transaction().writeable():
 
157
            if (self._lock_mode != 'w'
 
158
                or not self.get_transaction().writeable()):
182
159
                raise errors.ReadOnlyError(self)
183
160
            self._lock.validate_token(token)
184
 
            self._lock_warner.lock_count += 1
 
161
            self._lock_count += 1
185
162
            return self._token_from_lock
186
163
        else:
187
164
            token_from_lock = self._lock.lock_write(token=token)
188
165
            #traceback.print_stack()
189
166
            self._lock_mode = 'w'
190
 
            self._lock_warner.lock_count = 1
 
167
            self._lock_count = 1
191
168
            self._set_write_transaction()
192
169
            self._token_from_lock = token_from_lock
193
170
            return token_from_lock
196
173
        if self._lock_mode:
197
174
            if self._lock_mode not in ('r', 'w'):
198
175
                raise ValueError("invalid lock mode %r" % (self._lock_mode,))
199
 
            self._lock_warner.lock_count += 1
 
176
            self._lock_count += 1
200
177
        else:
201
178
            self._lock.lock_read()
202
179
            #traceback.print_stack()
203
180
            self._lock_mode = 'r'
204
 
            self._lock_warner.lock_count = 1
 
181
            self._lock_count = 1
205
182
            self._set_read_transaction()
206
183
 
207
184
    def _set_read_transaction(self):
218
195
    def unlock(self):
219
196
        if not self._lock_mode:
220
197
            return lock.cant_unlock_not_held(self)
221
 
        if self._lock_warner.lock_count > 1:
222
 
            self._lock_warner.lock_count -= 1
 
198
        if self._lock_count > 1:
 
199
            self._lock_count -= 1
223
200
        else:
224
201
            #traceback.print_stack()
225
202
            self._finish_transaction()
226
203
            try:
227
204
                self._lock.unlock()
228
205
            finally:
229
 
                self._lock_mode = self._lock_warner.lock_count = None
230
 
 
231
 
    @property
232
 
    def _lock_count(self):
233
 
        return self._lock_warner.lock_count
 
206
                self._lock_mode = self._lock_count = None
234
207
 
235
208
    def is_locked(self):
236
209
        """Return true if this LockableFiles group is locked"""
237
 
        return self._lock_warner.lock_count >= 1
 
210
        return self._lock_count >= 1
238
211
 
239
212
    def get_physical_lock_status(self):
240
213
        """Return physical lock status.
326
299
    def validate_token(self, token):
327
300
        if token is not None:
328
301
            raise errors.TokenLockingNotSupported(self)
329