~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

Implement RemoteBranch.lock_write/unlock as smart operations.

Because Branch.lock_write/unlock actually also lock/unlock the repository, I've
slightly changed lock_write's interface to accept and return 'tokens' rather
than 'token'.  i.e. a 2-tuple of (branch token, repo token), or None.

Show diffs side-by-side

added added

removed removed

Lines of Context:
426
426
        self.repository = remote_repository
427
427
        if real_branch is not None:
428
428
            self._real_branch = real_branch
 
429
            # Give the remote repository the matching real repo.
 
430
            self.repository._set_real_repository(self._real_branch.repository)
 
431
            # Give the branch the remote repository to let fast-pathing happen.
 
432
            self._real_branch.repository = self.repository
429
433
        else:
430
434
            self._real_branch = None
431
435
        # Fill out expected attributes of branch for bzrlib api users.
432
436
        self._format = RemoteBranchFormat()
433
437
        self.base = self.bzrdir.root_transport.base
434
438
        self.control_files = RemoteBranchLockableFiles(self.bzrdir, self._client)
 
439
        self._lock_mode = None
 
440
        self._lock_token = None
 
441
        self._lock_count = 0
 
442
        self._leave_lock = False
435
443
 
436
444
    def _ensure_real(self):
437
445
        """Ensure that there is a _real_branch set.
457
465
        self._ensure_real()
458
466
        return self._real_branch.lock_read()
459
467
 
460
 
    def lock_write(self, token=None):
461
 
        self._ensure_real()
462
 
        return self._real_branch.lock_write(token=token)
 
468
    def _lock_write(self, tokens):
 
469
        if tokens is None:
 
470
            branch_token = repo_token = ''
 
471
        else:
 
472
            branch_token, repo_token = tokens
 
473
        path = self.bzrdir._path_for_remote_call(self._client)
 
474
        response = self._client.call('Branch.lock_write', path, branch_token,
 
475
                                     repo_token)
 
476
        if response[0] == 'ok':
 
477
            ok, branch_token, repo_token = response
 
478
            return branch_token, repo_token
 
479
        elif response[0] == 'LockContention':
 
480
            raise errors.LockContention('(remote lock)')
 
481
        elif response[0] == 'TokenMismatch':
 
482
            raise errors.TokenMismatch(tokens, '(remote tokens)')
 
483
        else:
 
484
            assert False, 'unexpected response code %s' % (response,)
 
485
            
 
486
    def lock_write(self, tokens=None):
 
487
        if not self._lock_mode:
 
488
            remote_tokens = self._lock_write(tokens)
 
489
            self._lock_token, self._repo_lock_token = remote_tokens
 
490
            assert self._lock_token, 'Remote server did not return a token!'
 
491
            if self._real_branch is not None:
 
492
                self._real_branch.lock_write(tokens=remote_tokens)
 
493
            if tokens is not None:
 
494
                self._leave_lock = True
 
495
            else:
 
496
                # XXX: this case seems to be unreachable; tokens cannot be None.
 
497
                self._leave_lock = False
 
498
            self._lock_mode = 'w'
 
499
            self._lock_count = 1
 
500
        elif self._lock_mode == 'r':
 
501
            raise errors.ReadOnlyTransaction
 
502
        else:
 
503
            if tokens is not None:
 
504
                # Tokens were given to lock_write, and we're relocking, so check
 
505
                # that the given tokens actually match the ones we already have.
 
506
                held_tokens = (self._lock_token, self._repo_lock_token)
 
507
                if tokens != held_tokens:
 
508
                    raise errors.TokenMismatch(str(tokens), str(held_tokens))
 
509
            self._lock_count += 1
 
510
        return self._lock_token, self._repo_lock_token
 
511
 
 
512
    def _unlock(self, branch_token, repo_token):
 
513
        path = self.bzrdir._path_for_remote_call(self._client)
 
514
        response = self._client.call('Branch.unlock', path, branch_token,
 
515
                                     repo_token)
 
516
        if response == ('ok',):
 
517
            return
 
518
        elif response[0] == 'TokenMismatch':
 
519
            raise errors.TokenMismatch(token, '(remote token)')
 
520
        else:
 
521
            assert False, 'unexpected response code %s' % (response,)
463
522
 
464
523
    def unlock(self):
465
 
        self._ensure_real()
466
 
        return self._real_branch.unlock()
 
524
        self._lock_count -= 1
 
525
        if not self._lock_count:
 
526
            mode = self._lock_mode
 
527
            self._lock_mode = None
 
528
            if self._real_branch is not None:
 
529
                self._real_branch.unlock()
 
530
            if mode != 'w':
 
531
                return
 
532
            assert self._lock_token, 'Locked, but no token!'
 
533
            branch_token = self._lock_token
 
534
            repo_token = self._repo_lock_token
 
535
            self._lock_token = None
 
536
            self._repo_lock_token = None
 
537
            if not self._leave_lock:
 
538
                self._unlock(branch_token, repo_token)
467
539
 
468
540
    def break_lock(self):
469
541
        self._ensure_real()
470
542
        return self._real_branch.break_lock()
471
543
 
 
544
    def leave_lock_in_place(self):
 
545
        self._leave_lock = True
 
546
 
 
547
    def dont_leave_lock_in_place(self):
 
548
        self._leave_lock = False
 
549
 
472
550
    def last_revision_info(self):
473
551
        """See Branch.last_revision_info()."""
474
552
        path = self.bzrdir._path_for_remote_call(self._client)