1
# Copyright (C) 2005, 2006, 2008, 2009 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2008 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
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
17
17
from cStringIO import StringIO
44
43
# somewhat redundant with what's done in LockDir; the main difference is that
45
44
# LockableFiles permits reentrancy.
47
class _LockWarner(object):
48
"""Hold a counter for a lock and warn if GCed while the count is >= 1.
50
This is separate from LockableFiles because putting a __del__ on
51
LockableFiles can result in uncollectable cycles.
54
def __init__(self, repr):
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)
64
46
class LockableFiles(object):
65
47
"""Object representing a set of related files locked within the same scope.
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
90
:ivar _lock: The real underlying lock (e.g. a LockDir)
91
:ivar _counted_lock: A lock decorated with a semaphore, so that it
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))
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)
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)
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)
135
118
def break_lock(self):
136
119
"""Break the lock of this lockable files group if it is held.
153
136
:deprecated: Replaced by BzrDir._find_modes.
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.
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
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()
263
self._set_transaction(transactions.WriteTransaction())
284
264
self._token_from_lock = token_from_lock
285
265
return token_from_lock
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
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()
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)
305
def _set_write_transaction(self):
306
"""Setup a write transaction."""
307
self._set_transaction(transactions.WriteTransaction())
277
self._set_transaction(transactions.ReadOnlyTransaction())
278
# 5K may be excessive, but hey, its a knob.
279
self.get_transaction().set_cache_size(5000)
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
315
287
#traceback.print_stack()
316
288
self._finish_transaction()
318
290
self._lock.unlock()
320
self._lock_mode = self._lock_warner.lock_count = None
323
def _lock_count(self):
324
return self._lock_warner.lock_count
292
self._lock_mode = self._lock_count = None
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
330
298
def get_physical_lock_status(self):
331
299
"""Return physical lock status.