# HG changeset patch # User Benoit Boissinot # Date 2008-10-21 15:00:35 # Node ID 9f0e52e1df77639faebde4271047da94909f3730 # Parent c2ac09f81ec930993ed1ad098085a54a35403f92 fix pull racing with push/commit (issue1320) changegroup() has a problem when nodes which does not descend from a node in 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 ), and send all the nodes not in . 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 nodes are sent (instead of the of the missing nodes). diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -1578,6 +1578,20 @@ class localrepository(repo.repository): the linkrev. """ + if extranodes is None: + # can we go through the fast path ? + heads.sort() + allheads = self.heads() + allheads.sort() + if heads == allheads: + common = [] + # parents of bases are known from both sides + for n in bases: + for p in self.changelog.parents(n): + if p != nullid: + common.append(p) + return self._changegroup(common, source) + self.hook('preoutgoing', throw=True, source=source) # Set up some initial variables @@ -1854,16 +1868,22 @@ class localrepository(repo.repository): return util.chunkbuffer(gengroup()) def changegroup(self, basenodes, source): + # to avoid a race we use changegroupsubset() (issue1320) + return self.changegroupsubset(basenodes, self.heads(), source) + + def _changegroup(self, common, source): """Generate a changegroup of all nodes that we have that a recipient doesn't. This is much easier than the previous function as we can assume that - the recipient has any changenode we aren't sending them.""" + the recipient has any changenode we aren't sending them. + + common is the set of common nodes between remote and self""" self.hook('preoutgoing', throw=True, source=source) cl = self.changelog - nodes = cl.nodesbetween(basenodes, None)[0] + nodes = cl.findmissing(common) revset = dict.fromkeys([cl.rev(n) for n in nodes]) self.changegroupinfo(nodes, source) diff --git a/mercurial/revlog.py b/mercurial/revlog.py --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -590,6 +590,46 @@ class revlog(object): yield i break + def findmissing(self, common=None, heads=None): + ''' + returns the topologically sorted list of nodes from the set: + missing = (ancestors(heads) \ ancestors(common)) + + where ancestors() is the set of ancestors from heads, heads included + + if heads is None, the heads of the revlog are used + if common is None, nullid is assumed to be a common node + ''' + if common is None: + common = [nullid] + if heads is None: + heads = self.heads() + + common = [self.rev(n) for n in common] + heads = [self.rev(n) for n in heads] + + # we want the ancestors, but inclusive + has = dict.fromkeys(self.ancestors(*common)) + has[nullrev] = None + for r in common: + has[r] = None + + # take all ancestors from heads that aren't in has + missing = {} + visit = [r for r in heads if r not in has] + while visit: + r = visit.pop(0) + if r in missing: + continue + else: + missing[r] = None + for p in self.parentrevs(r): + if p not in has: + visit.append(p) + missing = missing.keys() + missing.sort() + return [self.node(r) for r in missing] + def nodesbetween(self, roots=None, heads=None): """Return a tuple containing three elements. Elements 1 and 2 contain a final list bases and heads after all the unreachable ones have been diff --git a/tests/test-clone-cgi.out b/tests/test-clone-cgi.out --- a/tests/test-clone-cgi.out +++ b/tests/test-clone-cgi.out @@ -2,4 +2,4 @@ adding a % try hgweb request 0 -54086fe9a47b47d83204f38bda0b90c2 page1 +1f424bb22ec05c3c6bc866b6e67efe43 page1 diff --git a/tests/test-fetch.out b/tests/test-fetch.out --- a/tests/test-fetch.out +++ b/tests/test-fetch.out @@ -100,7 +100,7 @@ searching for changes adding changesets adding manifests adding file changes -added 1 changesets with 1 changes to 1 files +added 1 changesets with 1 changes to 2 files % parent should be 2 (no automatic update) 2 diff --git a/tests/test-hgweb-commands.out b/tests/test-hgweb-commands.out index 577476c62c1b24cbd56fff71bd689ca53504026b..14bc4c0b7206ed7e9237068423388639b6f4e81a GIT binary patch literal 22828 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