~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: 2009-03-06 06:48:25 UTC
  • mfrom: (4070.8.6 debug-config)
  • Revision ID: pqm@pqm.ubuntu.com-20090306064825-kbpwggw21dygeix6
(mbp) debug_flags configuration option

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, 2006, 2008 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
12
12
#
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
16
16
 
17
17
from cStringIO import StringIO
18
18
 
22
22
import warnings
23
23
 
24
24
from bzrlib import (
25
 
    counted_lock,
26
25
    errors,
27
26
    osutils,
28
27
    transactions,
44
43
# somewhat redundant with what's done in LockDir; the main difference is that
45
44
# LockableFiles permits reentrancy.
46
45
 
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
 
 
63
 
 
64
46
class LockableFiles(object):
65
47
    """Object representing a set of related files locked within the same scope.
66
48
 
86
68
    This class is now deprecated; code should move to using the Transport
87
69
    directly for file operations and using the lock or CountedLock for
88
70
    locking.
89
 
    
90
 
    :ivar _lock: The real underlying lock (e.g. a LockDir)
91
 
    :ivar _counted_lock: A lock decorated with a semaphore, so that it 
92
 
        can be re-entered.
93
71
    """
94
72
 
95
73
    # _lock_mode: None, or 'r' or 'w'
110
88
        self.lock_name = lock_name
111
89
        self._transaction = None
112
90
        self._lock_mode = None
113
 
        self._lock_warner = _LockWarner(repr(self))
 
91
        self._lock_count = 0
114
92
        self._find_modes()
115
93
        esc_name = self._escape(lock_name)
116
94
        self._lock = lock_class(transport, esc_name,
117
95
                                file_modebits=self._file_mode,
118
96
                                dir_modebits=self._dir_mode)
119
 
        self._counted_lock = counted_lock.CountedLock(self._lock)
120
97
 
121
98
    def create_lock(self):
122
99
        """Create the lock.
132
109
    def __str__(self):
133
110
        return 'LockableFiles(%s, %s)' % (self.lock_name, self._transport.base)
134
111
 
 
112
    def __del__(self):
 
113
        if self.is_locked():
 
114
            # do not automatically unlock; there should have been a
 
115
            # try/finally to unlock this.
 
116
            warnings.warn("%r was gc'd while locked" % self)
 
117
 
135
118
    def break_lock(self):
136
119
        """Break the lock of this lockable files group if it is held.
137
120
 
152
135
 
153
136
        :deprecated: Replaced by BzrDir._find_modes.
154
137
        """
155
 
        # XXX: The properties created by this can be removed or deprecated
156
 
        # once all the _get_text_store methods etc no longer use them.
157
 
        # -- mbp 20080512
158
138
        try:
159
139
            st = self._transport.stat('.')
160
140
        except errors.TransportNotPossible:
273
253
            if self._lock_mode != 'w' or not self.get_transaction().writeable():
274
254
                raise errors.ReadOnlyError(self)
275
255
            self._lock.validate_token(token)
276
 
            self._lock_warner.lock_count += 1
 
256
            self._lock_count += 1
277
257
            return self._token_from_lock
278
258
        else:
279
259
            token_from_lock = self._lock.lock_write(token=token)
280
260
            #traceback.print_stack()
281
261
            self._lock_mode = 'w'
282
 
            self._lock_warner.lock_count = 1
283
 
            self._set_write_transaction()
 
262
            self._lock_count = 1
 
263
            self._set_transaction(transactions.WriteTransaction())
284
264
            self._token_from_lock = token_from_lock
285
265
            return token_from_lock
286
266
 
288
268
        if self._lock_mode:
289
269
            if self._lock_mode not in ('r', 'w'):
290
270
                raise ValueError("invalid lock mode %r" % (self._lock_mode,))
291
 
            self._lock_warner.lock_count += 1
 
271
            self._lock_count += 1
292
272
        else:
293
273
            self._lock.lock_read()
294
274
            #traceback.print_stack()
295
275
            self._lock_mode = 'r'
296
 
            self._lock_warner.lock_count = 1
297
 
            self._set_read_transaction()
298
 
 
299
 
    def _set_read_transaction(self):
300
 
        """Setup a read transaction."""
301
 
        self._set_transaction(transactions.ReadOnlyTransaction())
302
 
        # 5K may be excessive, but hey, its a knob.
303
 
        self.get_transaction().set_cache_size(5000)
304
 
 
305
 
    def _set_write_transaction(self):
306
 
        """Setup a write transaction."""
307
 
        self._set_transaction(transactions.WriteTransaction())
 
276
            self._lock_count = 1
 
277
            self._set_transaction(transactions.ReadOnlyTransaction())
 
278
            # 5K may be excessive, but hey, its a knob.
 
279
            self.get_transaction().set_cache_size(5000)
308
280
 
309
281
    def unlock(self):
310
282
        if not self._lock_mode:
311
283
            raise errors.LockNotHeld(self)
312
 
        if self._lock_warner.lock_count > 1:
313
 
            self._lock_warner.lock_count -= 1
 
284
        if self._lock_count > 1:
 
285
            self._lock_count -= 1
314
286
        else:
315
287
            #traceback.print_stack()
316
288
            self._finish_transaction()
317
289
            try:
318
290
                self._lock.unlock()
319
291
            finally:
320
 
                self._lock_mode = self._lock_warner.lock_count = None
321
 
 
322
 
    @property
323
 
    def _lock_count(self):
324
 
        return self._lock_warner.lock_count
 
292
                self._lock_mode = self._lock_count = None
325
293
 
326
294
    def is_locked(self):
327
295
        """Return true if this LockableFiles group is locked"""
328
 
        return self._lock_warner.lock_count >= 1
 
296
        return self._lock_count >= 1
329
297
 
330
298
    def get_physical_lock_status(self):
331
299
        """Return physical lock status.