/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/lockable_files.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2006-03-06 07:44:17 UTC
  • mfrom: (1553.5.64 bzr.mbp.locks)
  • Revision ID: pqm@pqm.ubuntu.com-20060306074417-344f1d83d99b9730
Integrate LockDirs into new format, etc

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
28
 
 
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.
30
32
 
31
33
class LockableFiles(object):
32
 
    """Object representing a set of files locked within the same scope
33
 
 
34
 
    _lock_mode
35
 
        None, or 'r' or 'w'
36
 
 
37
 
    _lock_count
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 
40
 
        read locks.
41
 
 
42
 
    _lock
43
 
        Lock object from bzrlib.lock.
 
34
    """Object representing a set of related files locked within the same scope.
 
35
 
 
36
    These files are used by a WorkingTree, Repository or Branch, and should
 
37
    generally only be touched by that object.
 
38
 
 
39
    LockableFiles also provides some policy on top of Transport for encoding
 
40
    control files as utf-8.
 
41
 
 
42
    LockableFiles manage a lock count and can be locked repeatedly by
 
43
    a single caller.  (The underlying lock implementation generally does not
 
44
    support this.)
 
45
 
 
46
    Instances of this class are often called control_files.
 
47
    
 
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.
44
54
    """
45
55
 
46
 
    _lock_mode = None
47
 
    _lock_count = None
48
 
    _lock = None
 
56
    # _lock_mode: None, or 'r' or 'w'
 
57
 
 
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*.   
 
60
    
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
53
65
 
54
 
    def __init__(self, transport, lock_name):
 
66
    def __init__(self, transport, lock_name, lock_class):
 
67
        """Create a LockableFiles group
 
68
 
 
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.
 
74
        """
55
75
        object.__init__(self)
56
76
        self._transport = transport
57
77
        self.lock_name = lock_name
58
78
        self._transaction = None
59
79
        self._find_modes()
60
 
 
61
 
    def __del__(self):
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)
67
 
            self._lock.unlock()
 
80
        self._lock_mode = None
 
81
        self._lock_count = 0
 
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)
 
86
 
 
87
    def create_lock(self):
 
88
        """Create the lock.
 
89
 
 
90
        This should normally be called only when the LockableFiles directory
 
91
        is first created on disk.
 
92
        """
 
93
        self._lock.create()
 
94
 
 
95
    def __repr__(self):
 
96
        return '%s(%r)' % (self.__class__.__name__,
 
97
                           self._transport)
68
98
 
69
99
    def _escape(self, file_or_path):
70
100
        if not isinstance(file_or_path, basestring):
108
138
        """
109
139
 
110
140
        relpath = self._escape(file_or_path)
111
 
        #TODO: codecs.open() buffers linewise, so it was overloaded with
 
141
        # TODO: codecs.open() buffers linewise, so it was overloaded with
112
142
        # a much larger buffer, do we need to do the same for getreader/getwriter?
113
143
        if mode == 'rb': 
114
144
            return self.get(relpath)
170
200
                raise ReadOnlyError(self)
171
201
            self._lock_count += 1
172
202
        else:
173
 
            self._lock = self._transport.lock_write(
174
 
                    self._escape(self.lock_name))
 
203
            self._lock.lock_write()
175
204
            self._lock_mode = 'w'
176
205
            self._lock_count = 1
177
206
            self._set_transaction(transactions.PassThroughTransaction())
183
212
                   "invalid lock mode %r" % self._lock_mode
184
213
            self._lock_count += 1
185
214
        else:
186
 
            self._lock = self._transport.lock_read(
187
 
                    self._escape(self.lock_name))
 
215
            self._lock.lock_read()
188
216
            self._lock_mode = 'r'
189
217
            self._lock_count = 1
190
218
            self._set_transaction(transactions.ReadOnlyTransaction())
194
222
    def unlock(self):
195
223
        # mutter("unlock: %s (%s)", self, self._lock_count)
196
224
        if not self._lock_mode:
197
 
            raise errors.BranchNotLocked(self)
 
225
            raise errors.LockNotHeld(self)
198
226
        if self._lock_count > 1:
199
227
            self._lock_count -= 1
200
228
        else:
201
229
            self._finish_transaction()
202
230
            self._lock.unlock()
203
 
            self._lock = None
204
231
            self._lock_mode = self._lock_count = None
205
232
 
 
233
    def is_locked(self):
 
234
        """Return true if this LockableFiles group is locked"""
 
235
        return self._lock_count >= 1
 
236
 
206
237
    def get_transaction(self):
207
238
        """Return the current active transaction.
208
239
 
229
260
        transaction = self._transaction
230
261
        self._transaction = None
231
262
        transaction.finish()
 
263
 
 
264
 
 
265
class TransportLock(object):
 
266
    """Locking method which uses transport-dependent locks.
 
267
 
 
268
    On the local filesystem these transform into OS-managed locks.
 
269
 
 
270
    These do not guard against concurrent access via different
 
271
    transports.
 
272
 
 
273
    This is suitable for use only in WorkingTrees (which are at present
 
274
    always local).
 
275
    """
 
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
 
281
 
 
282
    def lock_write(self):
 
283
        self._lock = self._transport.lock_write(self._escaped_name)
 
284
 
 
285
    def lock_read(self):
 
286
        self._lock = self._transport.lock_read(self._escaped_name)
 
287
 
 
288
    def unlock(self):
 
289
        self._lock.unlock()
 
290
        self._lock = None
 
291
 
 
292
    def create(self):
 
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)