/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: Robert Collins
  • Date: 2006-03-03 02:09:49 UTC
  • mto: (1594.2.4 integration)
  • mto: This revision was merged to the branch mainline in revision 1596.
  • Revision ID: robertc@robertcollins.net-20060303020949-0ddc6f33d0a43943
Smoke test for RevisionStore factories creating revision stores.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
from cStringIO import StringIO
18
18
import codecs
19
 
#import traceback
20
19
 
21
20
import bzrlib
22
21
from bzrlib.decorators import *
24
23
from bzrlib.errors import LockError, ReadOnlyError
25
24
from bzrlib.osutils import file_iterator, safe_unicode
26
25
from bzrlib.symbol_versioning import *
27
 
from bzrlib.trace import mutter, note
 
26
from bzrlib.symbol_versioning import deprecated_method, zero_eight
 
27
from bzrlib.trace import mutter
28
28
import bzrlib.transactions as transactions
29
29
 
30
 
# XXX: The tracking here of lock counts and whether the lock is held is
31
 
# somewhat redundant with what's done in LockDir; the main difference is that
32
 
# LockableFiles permits reentrancy.
33
30
 
34
31
class LockableFiles(object):
35
 
    """Object representing a set of related files locked within the same scope.
36
 
 
37
 
    These files are used by a WorkingTree, Repository or Branch, and should
38
 
    generally only be touched by that object.
39
 
 
40
 
    LockableFiles also provides some policy on top of Transport for encoding
41
 
    control files as utf-8.
42
 
 
43
 
    LockableFiles manage a lock count and can be locked repeatedly by
44
 
    a single caller.  (The underlying lock implementation generally does not
45
 
    support this.)
46
 
 
47
 
    Instances of this class are often called control_files.
48
 
    
49
 
    This object builds on top of a Transport, which is used to actually write
50
 
    the files to disk, and an OSLock or LockDir, which controls how access to
51
 
    the files is controlled.  The particular type of locking used is set when
52
 
    the object is constructed.  In older formats OSLocks are used everywhere.
53
 
    in newer formats a LockDir is used for Repositories and Branches, and 
54
 
    OSLocks for the local filesystem.
 
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.
55
44
    """
56
45
 
57
 
    # _lock_mode: None, or 'r' or 'w'
58
 
 
59
 
    # _lock_count: If _lock_mode is true, a positive count of the number of
60
 
    # times the lock has been taken *by this process*.   
61
 
    
 
46
    _lock_mode = None
 
47
    _lock_count = None
 
48
    _lock = None
62
49
    # If set to False (by a plugin, etc) BzrBranch will not set the
63
50
    # mode on created files or directories
64
51
    _set_file_mode = True
65
52
    _set_dir_mode = True
66
53
 
67
 
    def __init__(self, transport, lock_name, lock_class):
68
 
        """Create a LockableFiles group
69
 
 
70
 
        :param transport: Transport pointing to the directory holding the 
71
 
            control files and lock.
72
 
        :param lock_name: Name of the lock guarding these files.
73
 
        :param lock_class: Class of lock strategy to use: typically
74
 
            either LockDir or TransportLock.
75
 
        """
 
54
    def __init__(self, transport, lock_name):
76
55
        object.__init__(self)
77
56
        self._transport = transport
78
57
        self.lock_name = lock_name
79
58
        self._transaction = None
80
59
        self._find_modes()
81
 
        self._lock_mode = None
82
 
        self._lock_count = 0
83
 
        esc_name = self._escape(lock_name)
84
 
        self._lock = lock_class(transport, esc_name,
85
 
                                file_modebits=self._file_mode,
86
 
                                dir_modebits=self._dir_mode)
87
 
 
88
 
    def create_lock(self):
89
 
        """Create the lock.
90
 
 
91
 
        This should normally be called only when the LockableFiles directory
92
 
        is first created on disk.
93
 
        """
94
 
        self._lock.create()
95
 
 
96
 
    def __repr__(self):
97
 
        return '%s(%r)' % (self.__class__.__name__,
98
 
                           self._transport)
99
 
    def __str__(self):
100
 
        return 'LockableFiles(%s, %s)' % (self.lock_name, self._transport.base)
101
60
 
102
61
    def __del__(self):
103
 
        if self.is_locked():
 
62
        if self._lock_mode or self._lock:
104
63
            # XXX: This should show something every time, and be suitable for
105
64
            # headless operation and embedding
106
65
            from warnings import warn
149
108
        """
150
109
 
151
110
        relpath = self._escape(file_or_path)
152
 
        # TODO: codecs.open() buffers linewise, so it was overloaded with
 
111
        #TODO: codecs.open() buffers linewise, so it was overloaded with
153
112
        # a much larger buffer, do we need to do the same for getreader/getwriter?
154
113
        if mode == 'rb': 
155
114
            return self.get(relpath)
207
166
        # TODO: Upgrade locking to support using a Transport,
208
167
        # and potentially a remote locking protocol
209
168
        if self._lock_mode:
210
 
            if self._lock_mode != 'w' or not self.get_transaction().writeable():
 
169
            if self._lock_mode != 'w':
211
170
                raise ReadOnlyError(self)
212
171
            self._lock_count += 1
213
172
        else:
214
 
            self._lock.lock_write()
215
 
            #note('write locking %s', self)
216
 
            #traceback.print_stack()
 
173
            self._lock = self._transport.lock_write(
 
174
                    self._escape(self.lock_name))
217
175
            self._lock_mode = 'w'
218
176
            self._lock_count = 1
219
 
            self._set_transaction(transactions.WriteTransaction())
 
177
            self._set_transaction(transactions.PassThroughTransaction())
220
178
 
221
179
    def lock_read(self):
222
180
        # mutter("lock read: %s (%s)", self, self._lock_count)
225
183
                   "invalid lock mode %r" % self._lock_mode
226
184
            self._lock_count += 1
227
185
        else:
228
 
            self._lock.lock_read()
229
 
            #note('read locking %s', self)
230
 
            #traceback.print_stack()
 
186
            self._lock = self._transport.lock_read(
 
187
                    self._escape(self.lock_name))
231
188
            self._lock_mode = 'r'
232
189
            self._lock_count = 1
233
190
            self._set_transaction(transactions.ReadOnlyTransaction())
237
194
    def unlock(self):
238
195
        # mutter("unlock: %s (%s)", self, self._lock_count)
239
196
        if not self._lock_mode:
240
 
            raise errors.LockNotHeld(self)
 
197
            raise errors.BranchNotLocked(self)
241
198
        if self._lock_count > 1:
242
199
            self._lock_count -= 1
243
200
        else:
244
 
            #note('unlocking %s', self)
245
 
            #traceback.print_stack()
246
201
            self._finish_transaction()
247
202
            self._lock.unlock()
 
203
            self._lock = None
248
204
            self._lock_mode = self._lock_count = None
249
205
 
250
 
    def is_locked(self):
251
 
        """Return true if this LockableFiles group is locked"""
252
 
        return self._lock_count >= 1
253
 
 
254
206
    def get_transaction(self):
255
207
        """Return the current active transaction.
256
208
 
277
229
        transaction = self._transaction
278
230
        self._transaction = None
279
231
        transaction.finish()
280
 
 
281
 
 
282
 
class TransportLock(object):
283
 
    """Locking method which uses transport-dependent locks.
284
 
 
285
 
    On the local filesystem these transform into OS-managed locks.
286
 
 
287
 
    These do not guard against concurrent access via different
288
 
    transports.
289
 
 
290
 
    This is suitable for use only in WorkingTrees (which are at present
291
 
    always local).
292
 
    """
293
 
    def __init__(self, transport, escaped_name, file_modebits, dir_modebits):
294
 
        self._transport = transport
295
 
        self._escaped_name = escaped_name
296
 
        self._file_modebits = file_modebits
297
 
        self._dir_modebits = dir_modebits
298
 
 
299
 
    def lock_write(self):
300
 
        self._lock = self._transport.lock_write(self._escaped_name)
301
 
 
302
 
    def lock_read(self):
303
 
        self._lock = self._transport.lock_read(self._escaped_name)
304
 
 
305
 
    def unlock(self):
306
 
        self._lock.unlock()
307
 
        self._lock = None
308
 
 
309
 
    def create(self):
310
 
        """Create lock mechanism"""
311
 
        # for old-style locks, create the file now
312
 
        self._transport.put(self._escaped_name, StringIO(), 
313
 
                            mode=self._file_modebits)