~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/lockdir.py

  • Committer: Robert Collins
  • Date: 2007-05-07 16:48:14 UTC
  • mto: This revision was merged to the branch mainline in revision 2485.
  • Revision ID: robertc@robertcollins.net-20070507164814-wpagonutf4b5cf8s
Move HACKING to docs/developers/HACKING and adjust Makefile to accomodate this.

Show diffs side-by-side

added added

removed removed

Lines of Context:
118
118
from bzrlib.transport import Transport
119
119
from bzrlib.osutils import rand_chars, format_delta
120
120
from bzrlib.rio import read_stanza, Stanza
 
121
import bzrlib.ui
121
122
 
122
123
 
123
124
# XXX: At the moment there is no consideration of thread safety on LockDir
159
160
        self.transport = transport
160
161
        self.path = path
161
162
        self._lock_held = False
 
163
        self._locked_via_token = False
162
164
        self._fake_read_lock = False
163
165
        self._held_dir = path + '/held'
164
166
        self._held_info_path = self._held_dir + self.__INFO_NAME
165
167
        self._file_modebits = file_modebits
166
168
        self._dir_modebits = dir_modebits
167
 
        self.nonce = rand_chars(20)
168
169
 
169
170
        self._report_function = note
170
171
 
208
209
                # After creating the lock directory, try again
209
210
                self.transport.mkdir(tmpname)
210
211
 
 
212
            self.nonce = rand_chars(20)
211
213
            info_bytes = self._prepare_info()
212
214
            # We use put_file_non_atomic because we just created a new unique
213
215
            # directory so we don't have to worry about files existing there.
219
221
            self.transport.rename(tmpname, self._held_dir)
220
222
            self._lock_held = True
221
223
            self.confirm()
 
224
        except errors.PermissionDenied:
 
225
            raise
222
226
        except (PathError, DirectoryNotEmpty, FileExists, ResourceBusy), e:
223
227
            mutter("contention on %r: %s", self, e)
224
228
            raise LockContention(self)
231
235
            return
232
236
        if not self._lock_held:
233
237
            raise LockNotHeld(self)
234
 
        # rename before deleting, because we can't atomically remove the whole
235
 
        # tree
236
 
        tmpname = '%s/releasing.%s.tmp' % (self.path, rand_chars(20))
237
 
        # gotta own it to unlock
238
 
        self.confirm()
239
 
        self.transport.rename(self._held_dir, tmpname)
240
 
        self._lock_held = False
241
 
        self.transport.delete(tmpname + self.__INFO_NAME)
242
 
        self.transport.rmdir(tmpname)
 
238
        if self._locked_via_token:
 
239
            self._locked_via_token = False
 
240
            self._lock_held = False
 
241
        else:
 
242
            # rename before deleting, because we can't atomically remove the
 
243
            # whole tree
 
244
            tmpname = '%s/releasing.%s.tmp' % (self.path, rand_chars(20))
 
245
            # gotta own it to unlock
 
246
            self.confirm()
 
247
            self.transport.rename(self._held_dir, tmpname)
 
248
            self._lock_held = False
 
249
            self.transport.delete(tmpname + self.__INFO_NAME)
 
250
            self.transport.rmdir(tmpname)
243
251
 
244
252
    def break_lock(self):
245
253
        """Break a lock not held by this instance of LockDir.
411
419
                time.sleep(poll)
412
420
            else:
413
421
                raise LockContention(self)
414
 
 
415
 
    def lock_write(self):
416
 
        """Wait for and acquire the lock."""
417
 
        self.wait_lock()
 
422
    
 
423
    def leave_in_place(self):
 
424
        self._locked_via_token = True
 
425
 
 
426
    def dont_leave_in_place(self):
 
427
        self._locked_via_token = False
 
428
 
 
429
    def lock_write(self, token=None):
 
430
        """Wait for and acquire the lock.
 
431
        
 
432
        :param token: if this is already locked, then lock_write will fail
 
433
            unless the token matches the existing lock.
 
434
        :returns: a token if this instance supports tokens, otherwise None.
 
435
        :raises TokenLockingNotSupported: when a token is given but this
 
436
            instance doesn't support using token locks.
 
437
        :raises MismatchedToken: if the specified token doesn't match the token
 
438
            of the existing lock.
 
439
 
 
440
        A token should be passed in if you know that you have locked the object
 
441
        some other way, and need to synchronise this object's state with that
 
442
        fact.
 
443
         
 
444
        XXX: docstring duplicated from LockableFiles.lock_write.
 
445
        """
 
446
        if token is not None:
 
447
            self.validate_token(token)
 
448
            self.nonce = token
 
449
            self._lock_held = True
 
450
            self._locked_via_token = True
 
451
            return token
 
452
        else:
 
453
            self.wait_lock()
 
454
            return self.peek().get('nonce')
418
455
 
419
456
    def lock_read(self):
420
457
        """Compatibility-mode shared lock.
454
491
            'locked %s' % (format_delta(delta),),
455
492
            ]
456
493
 
 
494
    def validate_token(self, token):
 
495
        if token is not None:
 
496
            info = self.peek()
 
497
            if info is None:
 
498
                # Lock isn't held
 
499
                lock_token = None
 
500
            else:
 
501
                lock_token = info.get('nonce')
 
502
            if token != lock_token:
 
503
                raise errors.TokenMismatch(token, lock_token)
 
504