~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-05-07 11:50:28 UTC
  • mfrom: (5147.4.7 more-colo)
  • Revision ID: pqm@pqm.ubuntu.com-20100507115028-tuuxmnormm8oetw6
(vila, for jelmer) Pass the colocated branch name along in more places,
        add extra tests.

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
325
336
            self._trace("... unlock succeeded after %dms",
326
337
                    (time.time() - start_time) * 1000)
327
338
            result = lock.LockResult(self.transport.abspath(self.path),
328
 
                old_nonce)
 
339
                                     old_nonce)
329
340
            for hook in self.hooks['lock_released']:
330
341
                hook(result)
331
342
 
379
390
            raise LockBreakMismatch(self, broken_info, dead_holder_info)
380
391
        self.transport.delete(broken_info_path)
381
392
        self.transport.rmdir(tmpname)
 
393
        result = lock.LockResult(self.transport.abspath(self.path),
 
394
                                 current_info.get('nonce'))
 
395
        for hook in self.hooks['lock_broken']:
 
396
            hook(result)
382
397
 
383
398
    def _check_not_locked(self):
384
399
        """If the lock is held by this instance, raise an error."""
410
425
 
411
426
        peek() reads the info file of the lock holder, if any.
412
427
        """
413
 
        return self._parse_info(self.transport.get(path))
 
428
        return self._parse_info(self.transport.get_bytes(path))
414
429
 
415
430
    def peek(self):
416
431
        """Check if the lock is held by anyone.
417
432
 
418
 
        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
419
434
        which contains some information about the current lock holder.
420
435
        Otherwise returns None.
421
436
        """
432
447
        # XXX: is creating this here inefficient?
433
448
        config = bzrlib.config.GlobalConfig()
434
449
        try:
435
 
            user = config.user_email()
436
 
        except errors.NoEmailInUsername:
437
450
            user = config.username()
 
451
        except errors.NoWhoami:
 
452
            user = osutils.getuser_unicode()
438
453
        s = rio.Stanza(hostname=get_host_name(),
439
454
                   pid=str(os.getpid()),
440
455
                   start_time=str(int(time.time())),
443
458
                   )
444
459
        return s.to_string()
445
460
 
446
 
    def _parse_info(self, info_file):
447
 
        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()
448
470
 
449
471
    def attempt_lock(self):
450
472
        """Take the lock; fail if it's already held.
518
540
                    deadline_str = time.strftime('%H:%M:%S',
519
541
                                                 time.localtime(deadline))
520
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.
521
547
                self._report_function('%s %s\n'
522
 
                                      '%s\n' # held by
523
 
                                      '%s\n' # locked ... ago
524
 
                                      'Will continue to try until %s, unless '
525
 
                                      'you press Ctrl-C\n'
526
 
                                      'If you\'re sure that it\'s not being '
527
 
                                      'modified, use bzr break-lock %s',
528
 
                                      start,
529
 
                                      formatted_info[0],
530
 
                                      formatted_info[1],
531
 
                                      formatted_info[2],
532
 
                                      deadline_str,
533
 
                                      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
                    )
534
559
 
535
560
            if (max_attempts is not None) and (attempt_count >= max_attempts):
536
561
                self._trace("exceeded %d attempts")
592
617
    def _format_lock_info(self, info):
593
618
        """Turn the contents of peek() into something for the user"""
594
619
        lock_url = self.transport.abspath(self.path)
595
 
        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']))
596
625
        return [
597
626
            'lock %s' % (lock_url,),
598
 
            'held by %(user)s on host %(hostname)s [process #%(pid)s]' % info,
599
 
            '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,),
600
630
            ]
601
631
 
602
632
    def validate_token(self, token):