~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

  • Committer: Andrew Bennetts
  • Date: 2008-05-21 11:53:44 UTC
  • mto: (3452.2.9 inter-remote-pack)
  • mto: This revision was merged to the branch mainline in revision 3511.
  • Revision ID: andrew.bennetts@canonical.com-20080521115344-oofrx0k7yht4564t
Avoid necessarily calling get_parent_map when pushing.

Show diffs side-by-side

added added

removed removed

Lines of Context:
42
42
from bzrlib.pack import ContainerPushParser
43
43
from bzrlib.smart import client, vfs
44
44
from bzrlib.revision import ensure_null, NULL_REVISION
45
 
from bzrlib.trace import mutter, note, warning
 
45
from bzrlib.trace import mutter, mutter_callsite, note, warning
46
46
 
47
47
# Note: RemoteBzrDirFormat is in bzrdir.py
48
48
 
258
258
                'Does not support nested trees', target_format)
259
259
 
260
260
 
 
261
class RemoteGraph(object):
 
262
 
 
263
    def __init__(self, real_graph, remote_repo):
 
264
        self._real_graph = real_graph
 
265
        self._remote_repo = remote_repo
 
266
 
 
267
    def heads(self, keys):
 
268
        client = self._remote_repo._client
 
269
        path = self._remote_repo.bzrdir._path_for_remote_call(client)
 
270
        return set(client.call('Repository.graph_heads', path, *keys))
 
271
 
 
272
    def find_lca(self, *revisions):
 
273
        return self._real_graph.find_lca(*revisions)
 
274
 
 
275
    def find_difference(self, left_revision, right_revision):
 
276
        return self._real_graph.find_difference(left_revision, right_revision)
 
277
 
 
278
    def find_unique_ancestors(self, unique_revision, common_revisions):
 
279
        return self._real_graph.find_unique_ancestors(
 
280
            unique_revision, common_revisions)
 
281
 
 
282
    def find_unique_lca(self, left_revision, right_revision,
 
283
                        count_steps=False):
 
284
        return self._real_graph.find_unique_lca(
 
285
            left_revision, right_revision, count_steps=count_steps)
 
286
        
 
287
    def get_parents(self, revisions):
 
288
        return self._real_graph.get_parents(revisions)
 
289
 
 
290
    def get_parent_map(self, revisions):
 
291
        return self._real_graph.get_parent_map(revisions)
 
292
 
 
293
    def is_ancestor(self, candidate_ancestor, candidate_descendant):
 
294
        return self._real_graph.is_ancestor(
 
295
            candidate_ancestor, candidate_descendant)
 
296
 
 
297
    def iter_ancestry(self, revision_ids):
 
298
        return self._real_graph.iter_ancestry(revision_ids)
 
299
 
 
300
    def iter_topo_order(self, revisions):
 
301
        return self._real_graph.iter_topo_order(revisions)
 
302
 
 
303
    def _make_breadth_first_searcher(self, revisions):
 
304
        return self._real_graph._make_breadth_first_searcher(revisions)
 
305
 
 
306
 
261
307
class RemoteRepository(object):
262
308
    """Repository accessed over rpc.
263
309
 
433
479
            self.bzrdir.transport.base):
434
480
            parents_provider = graph._StackedParentsProvider(
435
481
                [parents_provider, other_repository._make_parents_provider()])
436
 
        return graph.Graph(parents_provider)
 
482
        real_graph = graph.Graph(parents_provider)
 
483
        return RemoteGraph(real_graph, self)
437
484
 
438
485
    def gather_stats(self, revid=None, committers=None):
439
486
        """See Repository.gather_stats()."""
809
856
 
810
857
    def get_parent_map(self, keys):
811
858
        """See bzrlib.Graph.get_parent_map()."""
 
859
#        mutter_callsite(None, "get_parent_map called with %d keys", len(keys))
 
860
#        import pdb;pdb.set_trace()
812
861
        # Hack to build up the caching logic.
813
862
        ancestry = self._parents_map
814
863
        if ancestry is None:
825
874
                        len(parent_map))
826
875
            ancestry.update(parent_map)
827
876
        present_keys = [k for k in keys if k in ancestry]
828
 
        if 'hpss' in debug.debug_flags:
 
877
        if 'hpss' in debug.debug_flags and False:
829
878
            if self._requested_parents is not None and len(ancestry) != 0:
830
879
                self._requested_parents.update(present_keys)
831
880
                mutter('Current RemoteRepository graph hit rate: %d%%',
1225
1274
        # And the parent's __init__ doesn't do much anyway.
1226
1275
        self._revision_id_to_revno_cache = None
1227
1276
        self._revision_history_cache = None
 
1277
        self._last_revision_info_cache = None
1228
1278
        self.bzrdir = remote_bzrdir
1229
1279
        if _client is not None:
1230
1280
            self._client = _client
1281
1331
            if self._lock_mode == 'r':
1282
1332
                self._real_branch.lock_read()
1283
1333
 
 
1334
    def _clear_cached_state(self):
 
1335
        super(RemoteBranch, self)._clear_cached_state()
 
1336
        self._last_revision_info_cache = None
 
1337
        
1284
1338
    @property
1285
1339
    def control_files(self):
1286
1340
        # Defer actually creating RemoteBranchLockableFiles until its needed,
1434
1488
 
1435
1489
    def last_revision_info(self):
1436
1490
        """See Branch.last_revision_info()."""
 
1491
        if self._last_revision_info_cache is None:
 
1492
            self._last_revision_info_cache = self._last_revision_info()
 
1493
        return self._last_revision_info_cache
 
1494
    
 
1495
    def _last_revision_info(self):
1437
1496
        path = self.bzrdir._path_for_remote_call(self._client)
1438
1497
        response = self._client.call('Branch.last_revision_info', path)
1439
1498
        if response[0] != 'ok':
1454
1513
            return []
1455
1514
        return result
1456
1515
 
 
1516
    def _set_last_revision(self, revision_id):
 
1517
        path = self.bzrdir._path_for_remote_call(self._client)
 
1518
        self._clear_cached_state()
 
1519
        try:
 
1520
            response = self._client.call('Branch.set_last_revision',
 
1521
                path, self._lock_token, self._repo_lock_token, revision_id)
 
1522
        except errors.ErrorFromSmartServer, err:
 
1523
            if err.error_verb == 'NoSuchRevision':
 
1524
                raise NoSuchRevision(self, revision_id)
 
1525
            raise
 
1526
        if response != ('ok',):
 
1527
            raise errors.UnexpectedSmartServerResponse(response)
 
1528
 
1457
1529
    @needs_write_lock
1458
1530
    def set_revision_history(self, rev_history):
1459
1531
        # Send just the tip revision of the history; the server will generate
1460
1532
        # the full history from that.  If the revision doesn't exist in this
1461
1533
        # branch, NoSuchRevision will be raised.
1462
 
        path = self.bzrdir._path_for_remote_call(self._client)
1463
1534
        if rev_history == []:
1464
1535
            rev_id = 'null:'
1465
1536
        else:
1466
1537
            rev_id = rev_history[-1]
1467
 
        self._clear_cached_state()
1468
 
        try:
1469
 
            response = self._client.call('Branch.set_last_revision',
1470
 
                path, self._lock_token, self._repo_lock_token, rev_id)
1471
 
        except errors.ErrorFromSmartServer, err:
1472
 
            if err.error_verb == 'NoSuchRevision':
1473
 
                raise NoSuchRevision(self, rev_id)
1474
 
            raise
1475
 
        if response != ('ok',):
1476
 
            raise errors.UnexpectedSmartServerResponse(response)
 
1538
        self._set_last_revision(rev_id)
1477
1539
        self._cache_revision_history(rev_history)
1478
1540
 
1479
1541
    def get_parent(self):
1528
1590
        except errors.UnknownSmartMethod:
1529
1591
            self._ensure_real()
1530
1592
            self._clear_cached_state()
1531
 
            return self._real_branch.set_last_revision_info(revno, revision_id)
 
1593
            self._real_branch.set_last_revision_info(revno, revision_id)
 
1594
            self._last_revision_info_cache = revno, revision_id
 
1595
            return
1532
1596
        except errors.ErrorFromSmartServer, err:
1533
1597
            if err.error_verb == 'NoSuchRevision':
1534
1598
                raise NoSuchRevision(self, err.error_args[0])
1535
1599
            raise
1536
1600
        if response == ('ok',):
1537
1601
            self._clear_cached_state()
 
1602
            self._last_revision_info_cache = revno, revision_id
1538
1603
        else:
1539
1604
            raise errors.UnexpectedSmartServerResponse(response)
1540
1605
 
1541
1606
    def generate_revision_history(self, revision_id, last_rev=None,
1542
1607
                                  other_branch=None):
1543
 
        self._ensure_real()
1544
 
        return self._real_branch.generate_revision_history(
1545
 
            revision_id, last_rev=last_rev, other_branch=other_branch)
 
1608
#        self._ensure_real()
 
1609
#        return self._real_branch.generate_revision_history(
 
1610
#            revision_id, last_rev=last_rev, other_branch=other_branch)
 
1611
        self._set_last_revision(revision_id)
 
1612
        return # XXX
 
1613
        if last_rev is None and other_branch is None:
 
1614
            self._set_last_revision(revision_id)
 
1615
        else:
 
1616
            self._ensure_real()
 
1617
            return self._real_branch.generate_revision_history(
 
1618
                revision_id, last_rev=last_rev, other_branch=other_branch)
1546
1619
 
1547
1620
    @property
1548
1621
    def tags(self):
1554
1627
        return self._real_branch.set_push_location(location)
1555
1628
 
1556
1629
    def update_revisions(self, other, stop_revision=None, overwrite=False):
 
1630
        mutter('RemoteBranch.update_revisions(%r, %s, %r)', 
 
1631
               other, stop_revision, overwrite)
 
1632
        if overwrite:
 
1633
            self._ensure_real()
 
1634
            return self._real_branch.update_revisions(
 
1635
                other, stop_revision=stop_revision, overwrite=True)
 
1636
        from bzrlib import revision as _mod_revision
 
1637
        other.lock_read()
 
1638
        try:
 
1639
            other_last_revno, other_last_revision = other.last_revision_info()
 
1640
            if stop_revision is None:
 
1641
                stop_revision = other_last_revision
 
1642
                if _mod_revision.is_null(stop_revision):
 
1643
                    # if there are no commits, we're done.
 
1644
                    return
 
1645
            # whats the current last revision, before we fetch [and change it
 
1646
            # possibly]
 
1647
            last_rev = _mod_revision.ensure_null(self.last_revision())
 
1648
            # we fetch here so that we don't process data twice in the common
 
1649
            # case of having something to pull, and so that the check for 
 
1650
            # already merged can operate on the just fetched graph, which will
 
1651
            # be cached in memory.
 
1652
            mutter('about to fetch %s from %r', stop_revision, other)
 
1653
            self.fetch(other, stop_revision)
 
1654
            # Check to see if one is an ancestor of the other
 
1655
            heads = self.repository.get_graph().heads([stop_revision,
 
1656
                                                       last_rev])
 
1657
            if heads == set([last_rev]):
 
1658
                # The current revision is a decendent of the target,
 
1659
                # nothing to do
 
1660
                return
 
1661
            elif heads == set([stop_revision, last_rev]):
 
1662
                # These branches have diverged
 
1663
                raise errors.DivergedBranches(self, other)
 
1664
            elif heads != set([stop_revision]):
 
1665
                raise AssertionError("invalid heads: %r" % heads)
 
1666
            if other_last_revision == stop_revision:
 
1667
                self.set_last_revision_info(other_last_revno,
 
1668
                                            other_last_revision)
 
1669
            else:
 
1670
                self._set_last_revision(stop_revision)
 
1671
#                # TODO: jam 2007-11-29 Is there a way to determine the
 
1672
#                #       revno without searching all of history??
 
1673
#                self.generate_revision_history(stop_revision,
 
1674
#                    last_rev=last_rev, other_branch=other)
 
1675
        finally:
 
1676
            other.unlock()
 
1677
        
 
1678
        return
 
1679
        # XXX
1557
1680
        self._ensure_real()
1558
1681
        return self._real_branch.update_revisions(
1559
1682
            other, stop_revision=stop_revision, overwrite=overwrite)