Mercurial > public > mercurial-scm > hg
comparison mercurial/localrepo.py @ 9820:0b999aec64e8
bundle: don't send too many changesets (Issue1704)
The fast path in changegroupsubset can send too many csets. This happens
because it uses the parents of all bases as common nodes and then goes
forward from this again. If a base has a parent that has another child,
which is -not- a base, then this other child will nevertheless end up in
the changegroup.
The fix is to not use findmissing(), but use nodesbetween() instead, as
do the slow path and incoming/outgoing.
The change to test-notify.out is correct, because it actually hits this
bug, as can be seen by glog'ing the two repos:
@ 22c88
|\
| o 0a184
| |
o | 0647d
|/
o cb9a9
and
o 0647d
|
@ cb9a9
It used to pull 0647d again, which is unnecessary.
author | Peter Arrenbrecht <peter.arrenbrecht@gmail.com> |
---|---|
date | Sat, 07 Nov 2009 12:28:30 +0100 |
parents | f8e1456e1c2c |
children | ea3acaae25bb d6a307719ccb |
comparison
equal
deleted
inserted
replaced
9818:72d670c43f6e | 9820:0b999aec64e8 |
---|---|
1562 self.ui.warn(_("note: unsynced remote changes!\n")) | 1562 self.ui.warn(_("note: unsynced remote changes!\n")) |
1563 | 1563 |
1564 | 1564 |
1565 if revs is None: | 1565 if revs is None: |
1566 # use the fast path, no race possible on push | 1566 # use the fast path, no race possible on push |
1567 cg = self._changegroup(common.keys(), 'push') | 1567 nodes = self.changelog.findmissing(common.keys()) |
1568 cg = self._changegroup(nodes, 'push') | |
1568 else: | 1569 else: |
1569 cg = self.changegroupsubset(update, revs, 'push') | 1570 cg = self.changegroupsubset(update, revs, 'push') |
1570 return cg, remote_heads | 1571 return cg, remote_heads |
1571 | 1572 |
1572 def push_addchangegroup(self, remote, force, revs): | 1573 def push_addchangegroup(self, remote, force, revs): |
1620 values are lists of (node, linknode) tuples, where node is a wanted | 1621 values are lists of (node, linknode) tuples, where node is a wanted |
1621 node and linknode is the changelog node that should be transmitted as | 1622 node and linknode is the changelog node that should be transmitted as |
1622 the linkrev. | 1623 the linkrev. |
1623 """ | 1624 """ |
1624 | 1625 |
1626 # Set up some initial variables | |
1627 # Make it easy to refer to self.changelog | |
1628 cl = self.changelog | |
1629 # msng is short for missing - compute the list of changesets in this | |
1630 # changegroup. | |
1631 if not bases: | |
1632 bases = [nullid] | |
1633 msng_cl_lst, bases, heads = cl.nodesbetween(bases, heads) | |
1634 | |
1625 if extranodes is None: | 1635 if extranodes is None: |
1626 # can we go through the fast path ? | 1636 # can we go through the fast path ? |
1627 heads.sort() | 1637 heads.sort() |
1628 allheads = self.heads() | 1638 allheads = self.heads() |
1629 allheads.sort() | 1639 allheads.sort() |
1630 if heads == allheads: | 1640 if heads == allheads: |
1631 common = [] | 1641 return self._changegroup(msng_cl_lst, source) |
1632 # parents of bases are known from both sides | 1642 |
1633 for n in bases: | 1643 # slow path |
1634 for p in self.changelog.parents(n): | |
1635 if p != nullid: | |
1636 common.append(p) | |
1637 return self._changegroup(common, source) | |
1638 | |
1639 self.hook('preoutgoing', throw=True, source=source) | 1644 self.hook('preoutgoing', throw=True, source=source) |
1640 | 1645 |
1641 # Set up some initial variables | |
1642 # Make it easy to refer to self.changelog | |
1643 cl = self.changelog | |
1644 # msng is short for missing - compute the list of changesets in this | |
1645 # changegroup. | |
1646 msng_cl_lst, bases, heads = cl.nodesbetween(bases, heads) | |
1647 self.changegroupinfo(msng_cl_lst, source) | 1646 self.changegroupinfo(msng_cl_lst, source) |
1648 # Some bases may turn out to be superfluous, and some heads may be | 1647 # Some bases may turn out to be superfluous, and some heads may be |
1649 # too. nodesbetween will return the minimal set of bases and heads | 1648 # too. nodesbetween will return the minimal set of bases and heads |
1650 # necessary to re-create the changegroup. | 1649 # necessary to re-create the changegroup. |
1651 | 1650 |
1901 | 1900 |
1902 def changegroup(self, basenodes, source): | 1901 def changegroup(self, basenodes, source): |
1903 # to avoid a race we use changegroupsubset() (issue1320) | 1902 # to avoid a race we use changegroupsubset() (issue1320) |
1904 return self.changegroupsubset(basenodes, self.heads(), source) | 1903 return self.changegroupsubset(basenodes, self.heads(), source) |
1905 | 1904 |
1906 def _changegroup(self, common, source): | 1905 def _changegroup(self, nodes, source): |
1907 """Compute the changegroup of all nodes that we have that a recipient | 1906 """Compute the changegroup of all nodes that we have that a recipient |
1908 doesn't. Return a chunkbuffer object whose read() method will return | 1907 doesn't. Return a chunkbuffer object whose read() method will return |
1909 successive changegroup chunks. | 1908 successive changegroup chunks. |
1910 | 1909 |
1911 This is much easier than the previous function as we can assume that | 1910 This is much easier than the previous function as we can assume that |
1912 the recipient has any changenode we aren't sending them. | 1911 the recipient has any changenode we aren't sending them. |
1913 | 1912 |
1914 common is the set of common nodes between remote and self""" | 1913 nodes is the set of nodes to send""" |
1915 | 1914 |
1916 self.hook('preoutgoing', throw=True, source=source) | 1915 self.hook('preoutgoing', throw=True, source=source) |
1917 | 1916 |
1918 cl = self.changelog | 1917 cl = self.changelog |
1919 nodes = cl.findmissing(common) | |
1920 revset = set([cl.rev(n) for n in nodes]) | 1918 revset = set([cl.rev(n) for n in nodes]) |
1921 self.changegroupinfo(nodes, source) | 1919 self.changegroupinfo(nodes, source) |
1922 | 1920 |
1923 def identity(x): | 1921 def identity(x): |
1924 return x | 1922 return x |