~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/lockdir.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-09-13 07:59:39 UTC
  • mfrom: (5418.1.1 merge-2.2-into-devel)
  • Revision ID: pqm@pqm.ubuntu.com-20100913075939-nh4c1k7rkuxle7zk
(spiv) Merge lp:bzr/2.2, including fixes for #619872, #631350,
        #633745.

Show diffs side-by-side

added added

removed removed

Lines of Context:
120
120
        LockBreakMismatch,
121
121
        LockBroken,
122
122
        LockContention,
 
123
        LockCorrupt,
123
124
        LockFailed,
124
125
        LockNotHeld,
125
126
        NoSuchFile,
348
349
        it possibly being still active.
349
350
        """
350
351
        self._check_not_locked()
351
 
        holder_info = self.peek()
 
352
        try:
 
353
            holder_info = self.peek()
 
354
        except LockCorrupt, e:
 
355
            # The lock info is corrupt.
 
356
            if bzrlib.ui.ui_factory.get_boolean("Break (corrupt %r)" % (self,)):
 
357
                self.force_break_corrupt(e.file_data)
 
358
            return
352
359
        if holder_info is not None:
353
360
            lock_info = '\n'.join(self._format_lock_info(holder_info))
354
361
            if bzrlib.ui.ui_factory.get_boolean("Break %s" % lock_info):
395
402
        for hook in self.hooks['lock_broken']:
396
403
            hook(result)
397
404
 
 
405
    def force_break_corrupt(self, corrupt_info_lines):
 
406
        """Release a lock that has been corrupted.
 
407
        
 
408
        This is very similar to force_break, it except it doesn't assume that
 
409
        self.peek() can work.
 
410
        
 
411
        :param corrupt_info_lines: the lines of the corrupted info file, used
 
412
            to check that the lock hasn't changed between reading the (corrupt)
 
413
            info file and calling force_break_corrupt.
 
414
        """
 
415
        # XXX: this copes with unparseable info files, but what about missing
 
416
        # info files?  Or missing lock dirs?
 
417
        self._check_not_locked()
 
418
        tmpname = '%s/broken.%s.tmp' % (self.path, rand_chars(20))
 
419
        self.transport.rename(self._held_dir, tmpname)
 
420
        # check that we actually broke the right lock, not someone else;
 
421
        # there's a small race window between checking it and doing the
 
422
        # rename.
 
423
        broken_info_path = tmpname + self.__INFO_NAME
 
424
        f = self.transport.get(broken_info_path)
 
425
        broken_lines = f.readlines()
 
426
        if broken_lines != corrupt_info_lines:
 
427
            raise LockBreakMismatch(self, broken_lines, corrupt_info_lines)
 
428
        self.transport.delete(broken_info_path)
 
429
        self.transport.rmdir(tmpname)
 
430
        result = lock.LockResult(self.transport.abspath(self.path))
 
431
        for hook in self.hooks['lock_broken']:
 
432
            hook(result)
 
433
 
398
434
    def _check_not_locked(self):
399
435
        """If the lock is held by this instance, raise an error."""
400
436
        if self._lock_held:
459
495
        return s.to_string()
460
496
 
461
497
    def _parse_info(self, info_bytes):
462
 
        stanza = rio.read_stanza(osutils.split_lines(info_bytes))
 
498
        lines = osutils.split_lines(info_bytes)
 
499
        try:
 
500
            stanza = rio.read_stanza(lines)
 
501
        except ValueError, e:
 
502
            mutter('Corrupt lock info file: %r', lines)
 
503
            raise LockCorrupt("could not parse lock info file: " + str(e),
 
504
                              lines)
463
505
        if stanza is None:
464
506
            # see bug 185013; we fairly often end up with the info file being
465
507
            # empty after an interruption; we could log a message here but