23
23
from bzrlib.errors import LockError, ReadOnlyError
24
24
from bzrlib.osutils import file_iterator, safe_unicode
25
25
from bzrlib.symbol_versioning import *
26
from bzrlib.symbol_versioning import deprecated_method, zero_eight
27
26
from bzrlib.trace import mutter
28
27
import bzrlib.transactions as transactions
29
# XXX: The tracking here of lock counts and whether the lock is held is
30
# somewhat redundant with what's done in LockDir; the main difference is that
31
# LockableFiles permits reentrancy.
31
33
class LockableFiles(object):
32
"""Object representing a set of files locked within the same scope
38
If _lock_mode is true, a positive count of the number of times the
39
lock has been taken *by this process*. Others may have compatible
43
Lock object from bzrlib.lock.
34
"""Object representing a set of related files locked within the same scope.
36
These files are used by a WorkingTree, Repository or Branch, and should
37
generally only be touched by that object.
39
LockableFiles also provides some policy on top of Transport for encoding
40
control files as utf-8.
42
LockableFiles manage a lock count and can be locked repeatedly by
43
a single caller. (The underlying lock implementation generally does not
46
Instances of this class are often called control_files.
48
This object builds on top of a Transport, which is used to actually write
49
the files to disk, and an OSLock or LockDir, which controls how access to
50
the files is controlled. The particular type of locking used is set when
51
the object is constructed. In older formats OSLocks are used everywhere.
52
in newer formats a LockDir is used for Repositories and Branches, and
53
OSLocks for the local filesystem.
56
# _lock_mode: None, or 'r' or 'w'
58
# _lock_count: If _lock_mode is true, a positive count of the number of
59
# times the lock has been taken *by this process*.
49
61
# If set to False (by a plugin, etc) BzrBranch will not set the
50
62
# mode on created files or directories
51
63
_set_file_mode = True
52
64
_set_dir_mode = True
54
def __init__(self, transport, lock_name):
66
def __init__(self, transport, lock_name, lock_class):
67
"""Create a LockableFiles group
69
:param transport: Transport pointing to the directory holding the
70
control files and lock.
71
:param lock_name: Name of the lock guarding these files.
72
:param lock_class: Class of lock strategy to use: typically
73
either LockDir or TransportLock.
55
75
object.__init__(self)
56
76
self._transport = transport
57
77
self.lock_name = lock_name
58
78
self._transaction = None
62
if self._lock_mode or self._lock:
63
# XXX: This should show something every time, and be suitable for
64
# headless operation and embedding
65
from warnings import warn
66
warn("file group %r was not explicitly unlocked" % self)
80
self._lock_mode = None
82
esc_name = self._escape(lock_name)
83
self._lock = lock_class(transport, esc_name,
84
file_modebits=self._file_mode,
85
dir_modebits=self._dir_mode)
87
def create_lock(self):
90
This should normally be called only when the LockableFiles directory
91
is first created on disk.
96
return '%s(%r)' % (self.__class__.__name__,
69
99
def _escape(self, file_or_path):
70
100
if not isinstance(file_or_path, basestring):
229
260
transaction = self._transaction
230
261
self._transaction = None
231
262
transaction.finish()
265
class TransportLock(object):
266
"""Locking method which uses transport-dependent locks.
268
On the local filesystem these transform into OS-managed locks.
270
These do not guard against concurrent access via different
273
This is suitable for use only in WorkingTrees (which are at present
276
def __init__(self, transport, escaped_name, file_modebits, dir_modebits):
277
self._transport = transport
278
self._escaped_name = escaped_name
279
self._file_modebits = file_modebits
280
self._dir_modebits = dir_modebits
282
def lock_write(self):
283
self._lock = self._transport.lock_write(self._escaped_name)
286
self._lock = self._transport.lock_read(self._escaped_name)
293
"""Create lock mechanism"""
294
# for old-style locks, create the file now
295
self._transport.put(self._escaped_name, StringIO(),
296
mode=self._file_modebits)