comparison mercurial/localrepo.py @ 7233:9f0e52e1df77

fix pull racing with push/commit (issue1320) changegroup() has a problem when nodes which does not descend from a node in <bases> are added to remote after the discovery phase. If that happens, changegroup() won't send the correct set of nodes, ie. some nodes will be missing. To correct it we have to find the set of nodes that both remote and self have (called <common>), and send all the nodes not in <common>. This fix has some overhead, in the worst case it will re-send a whole branch. A proper fix to avoid this overhead might be to change the protocol so that the <common> nodes are sent (instead of the <bases> of the missing nodes).
author Benoit Boissinot <benoit.boissinot@ens-lyon.org>
date Tue, 21 Oct 2008 17:00:35 +0200
parents 7946503ec76e
children ae70fe6143fc
comparison
equal deleted inserted replaced
7232:c2ac09f81ec9 7233:9f0e52e1df77
1575 where the keys are the filenames (or 1 for the manifest), and the 1575 where the keys are the filenames (or 1 for the manifest), and the
1576 values are lists of (node, linknode) tuples, where node is a wanted 1576 values are lists of (node, linknode) tuples, where node is a wanted
1577 node and linknode is the changelog node that should be transmitted as 1577 node and linknode is the changelog node that should be transmitted as
1578 the linkrev. 1578 the linkrev.
1579 """ 1579 """
1580
1581 if extranodes is None:
1582 # can we go through the fast path ?
1583 heads.sort()
1584 allheads = self.heads()
1585 allheads.sort()
1586 if heads == allheads:
1587 common = []
1588 # parents of bases are known from both sides
1589 for n in bases:
1590 for p in self.changelog.parents(n):
1591 if p != nullid:
1592 common.append(p)
1593 return self._changegroup(common, source)
1580 1594
1581 self.hook('preoutgoing', throw=True, source=source) 1595 self.hook('preoutgoing', throw=True, source=source)
1582 1596
1583 # Set up some initial variables 1597 # Set up some initial variables
1584 # Make it easy to refer to self.changelog 1598 # Make it easy to refer to self.changelog
1852 self.hook('outgoing', node=hex(msng_cl_lst[0]), source=source) 1866 self.hook('outgoing', node=hex(msng_cl_lst[0]), source=source)
1853 1867
1854 return util.chunkbuffer(gengroup()) 1868 return util.chunkbuffer(gengroup())
1855 1869
1856 def changegroup(self, basenodes, source): 1870 def changegroup(self, basenodes, source):
1871 # to avoid a race we use changegroupsubset() (issue1320)
1872 return self.changegroupsubset(basenodes, self.heads(), source)
1873
1874 def _changegroup(self, common, source):
1857 """Generate a changegroup of all nodes that we have that a recipient 1875 """Generate a changegroup of all nodes that we have that a recipient
1858 doesn't. 1876 doesn't.
1859 1877
1860 This is much easier than the previous function as we can assume that 1878 This is much easier than the previous function as we can assume that
1861 the recipient has any changenode we aren't sending them.""" 1879 the recipient has any changenode we aren't sending them.
1880
1881 common is the set of common nodes between remote and self"""
1862 1882
1863 self.hook('preoutgoing', throw=True, source=source) 1883 self.hook('preoutgoing', throw=True, source=source)
1864 1884
1865 cl = self.changelog 1885 cl = self.changelog
1866 nodes = cl.nodesbetween(basenodes, None)[0] 1886 nodes = cl.findmissing(common)
1867 revset = dict.fromkeys([cl.rev(n) for n in nodes]) 1887 revset = dict.fromkeys([cl.rev(n) for n in nodes])
1868 self.changegroupinfo(nodes, source) 1888 self.changegroupinfo(nodes, source)
1869 1889
1870 def identity(x): 1890 def identity(x):
1871 return x 1891 return x