43
43
# somewhat redundant with what's done in LockDir; the main difference is that
44
44
# LockableFiles permits reentrancy.
46
class _LockWarner(object):
47
"""Hold a counter for a lock and warn if GCed while the count is >= 1.
49
This is separate from LockableFiles because putting a __del__ on
50
LockableFiles can result in uncollectable cycles.
53
def __init__(self, repr):
58
if self.lock_count >= 1:
59
# There should have been a try/finally to unlock this.
60
warnings.warn("%r was gc'd while locked" % self.repr)
46
63
class LockableFiles(object):
47
64
"""Object representing a set of related files locked within the same scope.
88
105
self.lock_name = lock_name
89
106
self._transaction = None
90
107
self._lock_mode = None
108
self._lock_warner = _LockWarner(repr(self))
92
109
self._find_modes()
93
110
esc_name = self._escape(lock_name)
94
111
self._lock = lock_class(transport, esc_name,
109
126
def __str__(self):
110
127
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)
118
129
def break_lock(self):
119
130
"""Break the lock of this lockable files group if it is held.
253
264
if self._lock_mode != 'w' or not self.get_transaction().writeable():
254
265
raise errors.ReadOnlyError(self)
255
266
self._lock.validate_token(token)
256
self._lock_count += 1
267
self._lock_warner.lock_count += 1
257
268
return self._token_from_lock
259
270
token_from_lock = self._lock.lock_write(token=token)
260
271
#traceback.print_stack()
261
272
self._lock_mode = 'w'
263
self._set_transaction(transactions.WriteTransaction())
273
self._lock_warner.lock_count = 1
274
self._set_write_transaction()
264
275
self._token_from_lock = token_from_lock
265
276
return token_from_lock
268
279
if self._lock_mode:
269
280
if self._lock_mode not in ('r', 'w'):
270
281
raise ValueError("invalid lock mode %r" % (self._lock_mode,))
271
self._lock_count += 1
282
self._lock_warner.lock_count += 1
273
284
self._lock.lock_read()
274
285
#traceback.print_stack()
275
286
self._lock_mode = 'r'
277
self._set_transaction(transactions.ReadOnlyTransaction())
278
# 5K may be excessive, but hey, its a knob.
279
self.get_transaction().set_cache_size(5000)
287
self._lock_warner.lock_count = 1
288
self._set_read_transaction()
290
def _set_read_transaction(self):
291
"""Setup a read transaction."""
292
self._set_transaction(transactions.ReadOnlyTransaction())
293
# 5K may be excessive, but hey, its a knob.
294
self.get_transaction().set_cache_size(5000)
296
def _set_write_transaction(self):
297
"""Setup a write transaction."""
298
self._set_transaction(transactions.WriteTransaction())
281
300
def unlock(self):
282
301
if not self._lock_mode:
283
302
raise errors.LockNotHeld(self)
284
if self._lock_count > 1:
285
self._lock_count -= 1
303
if self._lock_warner.lock_count > 1:
304
self._lock_warner.lock_count -= 1
287
306
#traceback.print_stack()
288
307
self._finish_transaction()
290
309
self._lock.unlock()
292
self._lock_mode = self._lock_count = None
311
self._lock_mode = self._lock_warner.lock_count = None
314
def _lock_count(self):
315
return self._lock_warner.lock_count
294
317
def is_locked(self):
295
318
"""Return true if this LockableFiles group is locked"""
296
return self._lock_count >= 1
319
return self._lock_warner.lock_count >= 1
298
321
def get_physical_lock_status(self):
299
322
"""Return physical lock status.