~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: 2009-04-07 10:41:30 UTC
  • mfrom: (4230.1.2 bzr.dev)
  • Revision ID: pqm@pqm.ubuntu.com-20090407104130-ka3rxokxvi9yfbck
Include the msgeditor hooks in known_hooks.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006, 2007, 2008 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,
114
113
    )
115
114
import bzrlib.config
116
 
from bzrlib.decorators import only_raises
117
115
from bzrlib.errors import (
118
116
        DirectoryNotEmpty,
119
117
        FileExists,
151
149
# files/dirs created.
152
150
 
153
151
 
154
 
_DEFAULT_TIMEOUT_SECONDS = 30
 
152
_DEFAULT_TIMEOUT_SECONDS = 300
155
153
_DEFAULT_POLL_SECONDS = 1.0
156
154
 
157
155
 
242
240
        # incorrect.  It's possible some other servers or filesystems will
243
241
        # have a similar bug allowing someone to think they got the lock
244
242
        # when it's already held.
245
 
        #
246
 
        # See <https://bugs.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.
250
243
        info = self.peek()
251
244
        self._trace("after locking, info=%r", info)
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:
 
245
        if info['nonce'] != self.nonce:
256
246
            self._trace("rename succeeded, "
257
247
                "but lock is still held by someone else")
258
248
            raise LockContention(self)
296
286
                                            info_bytes)
297
287
        return tmpname
298
288
 
299
 
    @only_raises(LockNotHeld, LockBroken)
300
289
    def unlock(self):
301
290
        """Release a held lock
302
291
        """
304
293
            self._fake_read_lock = False
305
294
            return
306
295
        if not self._lock_held:
307
 
            return lock.cant_unlock_not_held(self)
 
296
            raise LockNotHeld(self)
308
297
        if self._locked_via_token:
309
298
            self._locked_via_token = False
310
299
            self._lock_held = False
336
325
            self._trace("... unlock succeeded after %dms",
337
326
                    (time.time() - start_time) * 1000)
338
327
            result = lock.LockResult(self.transport.abspath(self.path),
339
 
                                     old_nonce)
 
328
                old_nonce)
340
329
            for hook in self.hooks['lock_released']:
341
330
                hook(result)
342
331
 
390
379
            raise LockBreakMismatch(self, broken_info, dead_holder_info)
391
380
        self.transport.delete(broken_info_path)
392
381
        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)
397
382
 
398
383
    def _check_not_locked(self):
399
384
        """If the lock is held by this instance, raise an error."""
425
410
 
426
411
        peek() reads the info file of the lock holder, if any.
427
412
        """
428
 
        return self._parse_info(self.transport.get_bytes(path))
 
413
        return self._parse_info(self.transport.get(path))
429
414
 
430
415
    def peek(self):
431
416
        """Check if the lock is held by anyone.
432
417
 
433
 
        If it is held, this returns the lock info structure as a dict
 
418
        If it is held, this returns the lock info structure as a rio Stanza,
434
419
        which contains some information about the current lock holder.
435
420
        Otherwise returns None.
436
421
        """
447
432
        # XXX: is creating this here inefficient?
448
433
        config = bzrlib.config.GlobalConfig()
449
434
        try:
 
435
            user = config.user_email()
 
436
        except errors.NoEmailInUsername:
450
437
            user = config.username()
451
 
        except errors.NoWhoami:
452
 
            user = osutils.getuser_unicode()
453
438
        s = rio.Stanza(hostname=get_host_name(),
454
439
                   pid=str(os.getpid()),
455
440
                   start_time=str(int(time.time())),
458
443
                   )
459
444
        return s.to_string()
460
445
 
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()
 
446
    def _parse_info(self, info_file):
 
447
        return rio.read_stanza(info_file.readlines()).as_dict()
470
448
 
471
449
    def attempt_lock(self):
472
450
        """Take the lock; fail if it's already held.
539
517
                if deadline_str is None:
540
518
                    deadline_str = time.strftime('%H:%M:%S',
541
519
                                                 time.localtime(deadline))
542
 
                # As local lock urls are correct we display them.
543
 
                # We avoid displaying remote lock urls.
544
520
                lock_url = self.transport.abspath(self.path)
545
 
                if lock_url.startswith('file://'):
546
 
                    lock_url = lock_url.split('.bzr/')[0]
547
 
                else:
548
 
                    lock_url = ''
549
 
                user, hostname, pid, time_ago = formatted_info
550
 
                msg = ('%s lock %s '        # lock_url
551
 
                    'held by '              # start
552
 
                    '%s\n'                  # user
553
 
                    'at %s '                # hostname
554
 
                    '[process #%s], '       # pid
555
 
                    'acquired %s.')         # time ago
556
 
                msg_args = [start, lock_url, user, hostname, pid, time_ago]
557
 
                if timeout > 0:
558
 
                    msg += ('\nWill continue to try until %s, unless '
559
 
                        'you press Ctrl-C.')
560
 
                    msg_args.append(deadline_str)
561
 
                msg += '\nSee "bzr help break-lock" for more.'
562
 
                self._report_function(msg, *msg_args)
 
521
                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)
 
534
 
563
535
            if (max_attempts is not None) and (attempt_count >= max_attempts):
564
536
                self._trace("exceeded %d attempts")
565
537
                raise LockContention(self)
567
539
                self._trace("waiting %ss", poll)
568
540
                time.sleep(poll)
569
541
            else:
570
 
                # As timeout is always 0 for remote locks
571
 
                # this block is applicable only for local
572
 
                # lock contention
573
542
                self._trace("timeout after waiting %ss", timeout)
574
 
                raise LockContention('(local)', lock_url)
 
543
                raise LockContention(self)
575
544
 
576
545
    def leave_in_place(self):
577
546
        self._locked_via_token = True
622
591
 
623
592
    def _format_lock_info(self, info):
624
593
        """Turn the contents of peek() into something for the user"""
625
 
        start_time = info.get('start_time')
626
 
        if start_time is None:
627
 
            time_ago = '(unknown)'
628
 
        else:
629
 
            time_ago = format_delta(time.time() - int(info['start_time']))
630
 
        user = info.get('user', '<unknown>')
631
 
        hostname = info.get('hostname', '<unknown>')
632
 
        pid = info.get('pid', '<unknown>')
 
594
        lock_url = self.transport.abspath(self.path)
 
595
        delta = time.time() - int(info['start_time'])
633
596
        return [
634
 
            user,
635
 
            hostname,
636
 
            pid,
637
 
            time_ago,
 
597
            'lock %s' % (lock_url,),
 
598
            'held by %(user)s on host %(hostname)s [process #%(pid)s]' % info,
 
599
            'locked %s' % (format_delta(delta),),
638
600
            ]
639
601
 
640
602
    def validate_token(self, token):