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