~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-09-05 21:25:48 UTC
  • mfrom: (3692.1.6 objectnotlocked)
  • Revision ID: pqm@pqm.ubuntu.com-20080905212548-ig8wqqpv4vb8b2v4
(spiv) Fix bug #237067 by having RemoteBranch properly lock its
        RemoteRepository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
356
356
 
357
357
        Used before calls to self._real_repository.
358
358
        """
359
 
        if not self._real_repository:
 
359
        if self._real_repository is None:
360
360
            self.bzrdir._ensure_real()
361
 
            #self._real_repository = self.bzrdir._real_bzrdir.open_repository()
362
 
            self._set_real_repository(self.bzrdir._real_bzrdir.open_repository())
 
361
            self._set_real_repository(
 
362
                self.bzrdir._real_bzrdir.open_repository())
363
363
 
364
364
    def _translate_error(self, err, **context):
365
365
        self.bzrdir._translate_error(err, repository=self, **context)
549
549
        else:
550
550
            raise errors.UnexpectedSmartServerResponse(response)
551
551
 
552
 
    def lock_write(self, token=None):
 
552
    def lock_write(self, token=None, _skip_rpc=False):
553
553
        if not self._lock_mode:
554
 
            self._lock_token = self._remote_lock_write(token)
 
554
            if _skip_rpc:
 
555
                if self._lock_token is not None:
 
556
                    if token != self._lock_token:
 
557
                        raise TokenMismatch(token, self._lock_token)
 
558
                self._lock_token = token
 
559
            else:
 
560
                self._lock_token = self._remote_lock_write(token)
555
561
            # if self._lock_token is None, then this is something like packs or
556
562
            # svn where we don't get to lock the repo, or a weave style repository
557
563
            # where we cannot lock it over the wire and attempts to do so will
589
595
        :param repository: The repository to fallback to for non-hpss
590
596
            implemented operations.
591
597
        """
 
598
        if self._real_repository is not None:
 
599
            raise AssertionError('_real_repository is already set')
592
600
        if isinstance(repository, RemoteRepository):
593
601
            raise AssertionError()
594
602
        self._real_repository = repository
703
711
        # FIXME: It ought to be possible to call this without immediately
704
712
        # triggering _ensure_real.  For now it's the easiest thing to do.
705
713
        self._ensure_real()
706
 
        builder = self._real_repository.get_commit_builder(branch, parents,
 
714
        real_repo = self._real_repository
 
715
        builder = real_repo.get_commit_builder(branch, parents,
707
716
                config, timestamp=timestamp, timezone=timezone,
708
717
                committer=committer, revprops=revprops, revision_id=revision_id)
709
718
        return builder
1301
1310
                    'to use vfs implementation')
1302
1311
            self.bzrdir._ensure_real()
1303
1312
            self._real_branch = self.bzrdir._real_bzrdir.open_branch()
1304
 
            # Give the remote repository the matching real repo.
1305
 
            real_repo = self._real_branch.repository
1306
 
            if isinstance(real_repo, RemoteRepository):
1307
 
                real_repo._ensure_real()
1308
 
                real_repo = real_repo._real_repository
1309
 
            self.repository._set_real_repository(real_repo)
1310
 
            # Give the branch the remote repository to let fast-pathing happen.
 
1313
            if self.repository._real_repository is None:
 
1314
                # Give the remote repository the matching real repo.
 
1315
                real_repo = self._real_branch.repository
 
1316
                if isinstance(real_repo, RemoteRepository):
 
1317
                    real_repo._ensure_real()
 
1318
                    real_repo = real_repo._real_repository
 
1319
                self.repository._set_real_repository(real_repo)
 
1320
            # Give the real branch the remote repository to let fast-pathing
 
1321
            # happen.
1311
1322
            self._real_branch.repository = self.repository
1312
 
            # XXX: deal with _lock_mode == 'w'
1313
1323
            if self._lock_mode == 'r':
1314
1324
                self._real_branch.lock_read()
 
1325
            elif self._lock_mode == 'w':
 
1326
                self._real_branch.lock_write(token=self._lock_token)
1315
1327
 
1316
1328
    def _translate_error(self, err, **context):
1317
1329
        self.repository._translate_error(err, branch=self, **context)
1365
1377
        return self._real_branch.get_stacked_on_url()
1366
1378
 
1367
1379
    def lock_read(self):
 
1380
        self.repository.lock_read()
1368
1381
        if not self._lock_mode:
1369
1382
            self._lock_mode = 'r'
1370
1383
            self._lock_count = 1
1393
1406
            
1394
1407
    def lock_write(self, token=None):
1395
1408
        if not self._lock_mode:
 
1409
            # Lock the branch and repo in one remote call.
1396
1410
            remote_tokens = self._remote_lock_write(token)
1397
1411
            self._lock_token, self._repo_lock_token = remote_tokens
1398
1412
            if not self._lock_token:
1399
1413
                raise SmartProtocolError('Remote server did not return a token!')
1400
 
            # TODO: We really, really, really don't want to call _ensure_real
1401
 
            # here, but it's the easiest way to ensure coherency between the
1402
 
            # state of the RemoteBranch and RemoteRepository objects and the
1403
 
            # physical locks.  If we don't materialise the real objects here,
1404
 
            # then getting everything in the right state later is complex, so
1405
 
            # for now we just do it the lazy way.
1406
 
            #   -- Andrew Bennetts, 2007-02-22.
1407
 
            self._ensure_real()
 
1414
            # Tell the self.repository object that it is locked.
 
1415
            self.repository.lock_write(
 
1416
                self._repo_lock_token, _skip_rpc=True)
 
1417
 
1408
1418
            if self._real_branch is not None:
1409
 
                self._real_branch.repository.lock_write(
1410
 
                    token=self._repo_lock_token)
1411
 
                try:
1412
 
                    self._real_branch.lock_write(token=self._lock_token)
1413
 
                finally:
1414
 
                    self._real_branch.repository.unlock()
 
1419
                self._real_branch.lock_write(token=self._lock_token)
1415
1420
            if token is not None:
1416
1421
                self._leave_lock = True
1417
1422
            else:
1418
 
                # XXX: this case seems to be unreachable; token cannot be None.
1419
1423
                self._leave_lock = False
1420
1424
            self._lock_mode = 'w'
1421
1425
            self._lock_count = 1
1423
1427
            raise errors.ReadOnlyTransaction
1424
1428
        else:
1425
1429
            if token is not None:
1426
 
                # A token was given to lock_write, and we're relocking, so check
1427
 
                # that the given token actually matches the one we already have.
 
1430
                # A token was given to lock_write, and we're relocking, so
 
1431
                # check that the given token actually matches the one we
 
1432
                # already have.
1428
1433
                if token != self._lock_token:
1429
1434
                    raise errors.TokenMismatch(token, self._lock_token)
1430
1435
            self._lock_count += 1
 
1436
            # Re-lock the repository too.
 
1437
            self.repository.lock_write(self._repo_lock_token)
1431
1438
        return self._lock_token or None
1432
1439
 
1433
1440
    def _unlock(self, branch_token, repo_token):
1442
1449
        raise errors.UnexpectedSmartServerResponse(response)
1443
1450
 
1444
1451
    def unlock(self):
1445
 
        self._lock_count -= 1
1446
 
        if not self._lock_count:
1447
 
            self._clear_cached_state()
1448
 
            mode = self._lock_mode
1449
 
            self._lock_mode = None
1450
 
            if self._real_branch is not None:
1451
 
                if (not self._leave_lock and mode == 'w' and
1452
 
                    self._repo_lock_token):
1453
 
                    # If this RemoteBranch will remove the physical lock for the
1454
 
                    # repository, make sure the _real_branch doesn't do it
1455
 
                    # first.  (Because the _real_branch's repository is set to
1456
 
                    # be the RemoteRepository.)
1457
 
                    self._real_branch.repository.leave_lock_in_place()
1458
 
                self._real_branch.unlock()
1459
 
            if mode != 'w':
1460
 
                # Only write-locked branched need to make a remote method call
1461
 
                # to perfom the unlock.
1462
 
                return
1463
 
            if not self._lock_token:
1464
 
                raise AssertionError('Locked, but no token!')
1465
 
            branch_token = self._lock_token
1466
 
            repo_token = self._repo_lock_token
1467
 
            self._lock_token = None
1468
 
            self._repo_lock_token = None
1469
 
            if not self._leave_lock:
1470
 
                self._unlock(branch_token, repo_token)
 
1452
        try:
 
1453
            self._lock_count -= 1
 
1454
            if not self._lock_count:
 
1455
                self._clear_cached_state()
 
1456
                mode = self._lock_mode
 
1457
                self._lock_mode = None
 
1458
                if self._real_branch is not None:
 
1459
                    if (not self._leave_lock and mode == 'w' and
 
1460
                        self._repo_lock_token):
 
1461
                        # If this RemoteBranch will remove the physical lock
 
1462
                        # for the repository, make sure the _real_branch
 
1463
                        # doesn't do it first.  (Because the _real_branch's
 
1464
                        # repository is set to be the RemoteRepository.)
 
1465
                        self._real_branch.repository.leave_lock_in_place()
 
1466
                    self._real_branch.unlock()
 
1467
                if mode != 'w':
 
1468
                    # Only write-locked branched need to make a remote method
 
1469
                    # call to perfom the unlock.
 
1470
                    return
 
1471
                if not self._lock_token:
 
1472
                    raise AssertionError('Locked, but no token!')
 
1473
                branch_token = self._lock_token
 
1474
                repo_token = self._repo_lock_token
 
1475
                self._lock_token = None
 
1476
                self._repo_lock_token = None
 
1477
                if not self._leave_lock:
 
1478
                    self._unlock(branch_token, repo_token)
 
1479
        finally:
 
1480
            self.repository.unlock()
1471
1481
 
1472
1482
    def break_lock(self):
1473
1483
        self._ensure_real()
1518
1528
            raise errors.UnexpectedSmartServerResponse(response)
1519
1529
        new_revno, new_revision_id = response[1:]
1520
1530
        self._last_revision_info_cache = new_revno, new_revision_id
1521
 
        self._real_branch._last_revision_info_cache = new_revno, new_revision_id
 
1531
        if self._real_branch is not None:
 
1532
            cache = new_revno, new_revision_id
 
1533
            self._real_branch._last_revision_info_cache = cache
1522
1534
 
1523
1535
    def _set_last_revision(self, revision_id):
1524
1536
        path = self.bzrdir._path_for_remote_call(self._client)