~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/lockdir.py

  • Committer: Robert Collins
  • Date: 2010-05-06 23:41:35 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506234135-yivbzczw1sejxnxc
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
expected to return an object which can be used to unlock them. This reduces
duplicate code when using cleanups. The previous 'tokens's returned by
``Branch.lock_write`` and ``Repository.lock_write`` are now attributes
on the result of the lock_write. ``repository.RepositoryWriteLockResult``
and ``branch.BranchWriteLockResult`` document this. (Robert Collins)

``log._get_info_for_log_files`` now takes an add_cleanup callable.
(Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2006-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
110
110
    debug,
111
111
    errors,
112
112
    lock,
 
113
    osutils,
113
114
    )
114
115
import bzrlib.config
 
116
from bzrlib.decorators import only_raises
115
117
from bzrlib.errors import (
116
118
        DirectoryNotEmpty,
117
119
        FileExists,
240
242
        # incorrect.  It's possible some other servers or filesystems will
241
243
        # have a similar bug allowing someone to think they got the lock
242
244
        # when it's already held.
 
245
        #
 
246
        # See <https://bugs.edge.launchpad.net/bzr/+bug/498378> for one case.
 
247
        #
 
248
        # Strictly the check is unnecessary and a waste of time for most
 
249
        # people, but probably worth trapping if something is wrong.
243
250
        info = self.peek()
244
251
        self._trace("after locking, info=%r", info)
245
 
        if info['nonce'] != self.nonce:
 
252
        if info is None:
 
253
            raise LockFailed(self, "lock was renamed into place, but "
 
254
                "now is missing!")
 
255
        if info.get('nonce') != self.nonce:
246
256
            self._trace("rename succeeded, "
247
257
                "but lock is still held by someone else")
248
258
            raise LockContention(self)
286
296
                                            info_bytes)
287
297
        return tmpname
288
298
 
 
299
    @only_raises(LockNotHeld, LockBroken)
289
300
    def unlock(self):
290
301
        """Release a held lock
291
302
        """
293
304
            self._fake_read_lock = False
294
305
            return
295
306
        if not self._lock_held:
296
 
            raise LockNotHeld(self)
 
307
            return lock.cant_unlock_not_held(self)
297
308
        if self._locked_via_token:
298
309
            self._locked_via_token = False
299
310
            self._lock_held = False
414
425
 
415
426
        peek() reads the info file of the lock holder, if any.
416
427
        """
417
 
        return self._parse_info(self.transport.get(path))
 
428
        return self._parse_info(self.transport.get_bytes(path))
418
429
 
419
430
    def peek(self):
420
431
        """Check if the lock is held by anyone.
421
432
 
422
 
        If it is held, this returns the lock info structure as a rio Stanza,
 
433
        If it is held, this returns the lock info structure as a dict
423
434
        which contains some information about the current lock holder.
424
435
        Otherwise returns None.
425
436
        """
447
458
                   )
448
459
        return s.to_string()
449
460
 
450
 
    def _parse_info(self, info_file):
451
 
        return rio.read_stanza(info_file.readlines()).as_dict()
 
461
    def _parse_info(self, info_bytes):
 
462
        stanza = rio.read_stanza(osutils.split_lines(info_bytes))
 
463
        if stanza is None:
 
464
            # see bug 185013; we fairly often end up with the info file being
 
465
            # empty after an interruption; we could log a message here but
 
466
            # there may not be much we can say
 
467
            return {}
 
468
        else:
 
469
            return stanza.as_dict()
452
470
 
453
471
    def attempt_lock(self):
454
472
        """Take the lock; fail if it's already held.
522
540
                    deadline_str = time.strftime('%H:%M:%S',
523
541
                                                 time.localtime(deadline))
524
542
                lock_url = self.transport.abspath(self.path)
 
543
                # See <https://bugs.edge.launchpad.net/bzr/+bug/250451>
 
544
                # the URL here is sometimes not one that is useful to the
 
545
                # user, perhaps being wrapped in a lp-%d or chroot decorator,
 
546
                # especially if this error is issued from the server.
525
547
                self._report_function('%s %s\n'
526
 
                                      '%s\n' # held by
527
 
                                      '%s\n' # locked ... ago
528
 
                                      'Will continue to try until %s, unless '
529
 
                                      'you press Ctrl-C\n'
530
 
                                      'If you\'re sure that it\'s not being '
531
 
                                      'modified, use bzr break-lock %s',
532
 
                                      start,
533
 
                                      formatted_info[0],
534
 
                                      formatted_info[1],
535
 
                                      formatted_info[2],
536
 
                                      deadline_str,
537
 
                                      lock_url)
 
548
                    '%s\n' # held by
 
549
                    '%s\n' # locked ... ago
 
550
                    'Will continue to try until %s, unless '
 
551
                    'you press Ctrl-C.\n'
 
552
                    'See "bzr help break-lock" for more.',
 
553
                    start,
 
554
                    formatted_info[0],
 
555
                    formatted_info[1],
 
556
                    formatted_info[2],
 
557
                    deadline_str,
 
558
                    )
538
559
 
539
560
            if (max_attempts is not None) and (attempt_count >= max_attempts):
540
561
                self._trace("exceeded %d attempts")
596
617
    def _format_lock_info(self, info):
597
618
        """Turn the contents of peek() into something for the user"""
598
619
        lock_url = self.transport.abspath(self.path)
599
 
        delta = time.time() - int(info['start_time'])
 
620
        start_time = info.get('start_time')
 
621
        if start_time is None:
 
622
            time_ago = '(unknown)'
 
623
        else:
 
624
            time_ago = format_delta(time.time() - int(info['start_time']))
600
625
        return [
601
626
            'lock %s' % (lock_url,),
602
 
            'held by %(user)s on host %(hostname)s [process #%(pid)s]' % info,
603
 
            'locked %s' % (format_delta(delta),),
 
627
            'held by %s on host %s [process #%s]' %
 
628
                tuple([info.get(x, '<unknown>') for x in ['user', 'hostname', 'pid']]),
 
629
            'locked %s' % (time_ago,),
604
630
            ]
605
631
 
606
632
    def validate_token(self, token):