~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/lockdir.py

  • Committer: Martin Pool
  • Date: 2010-09-10 06:28:51 UTC
  • mfrom: (5417 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5426.
  • Revision ID: mbp@sourcefrog.net-20100910062851-rkz84bk48nnza0cn
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
120
120
        LockBreakMismatch,
121
121
        LockBroken,
122
122
        LockContention,
123
 
        LockCorrupt,
124
123
        LockFailed,
125
124
        LockNotHeld,
126
125
        NoSuchFile,
347
346
        This is a UI centric function: it uses the bzrlib.ui.ui_factory to
348
347
        prompt for input if a lock is detected and there is any doubt about
349
348
        it possibly being still active.
350
 
 
351
 
        :returns: LockResult for the broken lock.
352
349
        """
353
350
        self._check_not_locked()
354
 
        try:
355
 
            holder_info = self.peek()
356
 
        except LockCorrupt, e:
357
 
            # The lock info is corrupt.
358
 
            if bzrlib.ui.ui_factory.get_boolean("Break (corrupt %r)" % (self,)):
359
 
                self.force_break_corrupt(e.file_data)
360
 
            return
 
351
        holder_info = self.peek()
361
352
        if holder_info is not None:
362
353
            lock_info = '\n'.join(self._format_lock_info(holder_info))
363
354
            if bzrlib.ui.ui_factory.confirm_action(
364
355
                "Break %(lock_info)s", 'bzrlib.lockdir.break', 
365
356
                dict(lock_info=lock_info)):
366
 
                result = self.force_break(holder_info)
367
 
                bzrlib.ui.ui_factory.show_message(
368
 
                    "Broke lock %s" % result.lock_url)
 
357
                self.force_break(holder_info)
369
358
 
370
359
    def force_break(self, dead_holder_info):
371
360
        """Release a lock held by another process.
382
371
        After the lock is broken it will not be held by any process.
383
372
        It is possible that another process may sneak in and take the
384
373
        lock before the breaking process acquires it.
385
 
 
386
 
        :returns: LockResult for the broken lock.
387
374
        """
388
375
        if not isinstance(dead_holder_info, dict):
389
376
            raise ValueError("dead_holder_info: %r" % dead_holder_info)
409
396
                                 current_info.get('nonce'))
410
397
        for hook in self.hooks['lock_broken']:
411
398
            hook(result)
412
 
        return result
413
 
 
414
 
    def force_break_corrupt(self, corrupt_info_lines):
415
 
        """Release a lock that has been corrupted.
416
 
        
417
 
        This is very similar to force_break, it except it doesn't assume that
418
 
        self.peek() can work.
419
 
        
420
 
        :param corrupt_info_lines: the lines of the corrupted info file, used
421
 
            to check that the lock hasn't changed between reading the (corrupt)
422
 
            info file and calling force_break_corrupt.
423
 
        """
424
 
        # XXX: this copes with unparseable info files, but what about missing
425
 
        # info files?  Or missing lock dirs?
426
 
        self._check_not_locked()
427
 
        tmpname = '%s/broken.%s.tmp' % (self.path, rand_chars(20))
428
 
        self.transport.rename(self._held_dir, tmpname)
429
 
        # check that we actually broke the right lock, not someone else;
430
 
        # there's a small race window between checking it and doing the
431
 
        # rename.
432
 
        broken_info_path = tmpname + self.__INFO_NAME
433
 
        f = self.transport.get(broken_info_path)
434
 
        broken_lines = f.readlines()
435
 
        if broken_lines != corrupt_info_lines:
436
 
            raise LockBreakMismatch(self, broken_lines, corrupt_info_lines)
437
 
        self.transport.delete(broken_info_path)
438
 
        self.transport.rmdir(tmpname)
439
 
        result = lock.LockResult(self.transport.abspath(self.path))
440
 
        for hook in self.hooks['lock_broken']:
441
 
            hook(result)
442
399
 
443
400
    def _check_not_locked(self):
444
401
        """If the lock is held by this instance, raise an error."""
504
461
        return s.to_string()
505
462
 
506
463
    def _parse_info(self, info_bytes):
507
 
        lines = osutils.split_lines(info_bytes)
508
 
        try:
509
 
            stanza = rio.read_stanza(lines)
510
 
        except ValueError, e:
511
 
            mutter('Corrupt lock info file: %r', lines)
512
 
            raise LockCorrupt("could not parse lock info file: " + str(e),
513
 
                              lines)
 
464
        stanza = rio.read_stanza(osutils.split_lines(info_bytes))
514
465
        if stanza is None:
515
466
            # see bug 185013; we fairly often end up with the info file being
516
467
            # empty after an interruption; we could log a message here but