# HG changeset patch # User Durham Goode # Date 2017-09-20 16:22:22 # Node ID 1db9abf407c5a3fc57c45c7c1aa9613289709a05 # Parent 4f969b9e0cf5d4f2cfb7392cef7f43b74d17c5e4 revlog: add revmap back to revlog.addgroup The recent c8b6ed51386b patch removed the linkmapper argument from addgroup, as part of trying to make addgroup more agnostic from the changegroup format. It turns out that the changegroup can't resolve linkrevs while iterating over the deltas, because applying the deltas might affect the linkrev resolution. For example, when applying a series of changelog entries, the linkmapper just returns len(cl). If we're iterating over the deltas without applying them to the changelog, this results in incorrect linkrevs. This was caught by the hgsql extension, which reads the revisions before applying them. The fix is to return linknodes as part of the delta iterator, and let the consumer choose what to do. Differential Revision: https://phab.mercurial-scm.org/D730 diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py --- a/mercurial/changegroup.py +++ b/mercurial/changegroup.py @@ -245,8 +245,8 @@ class cg1unpacker(object): # no new manifest will be created and the manifest group will # be empty during the pull self.manifestheader() - deltas = self.deltaiter(revmap) - repo.manifestlog._revlog.addgroup(deltas, trp) + deltas = self.deltaiter() + repo.manifestlog._revlog.addgroup(deltas, revmap, trp) repo.ui.progress(_('manifests'), None) self.callback = None @@ -308,8 +308,8 @@ class cg1unpacker(object): efiles.update(cl.readfiles(node)) self.changelogheader() - deltas = self.deltaiter(csmap) - cgnodes = cl.addgroup(deltas, trp, addrevisioncb=onchangelog) + deltas = self.deltaiter() + cgnodes = cl.addgroup(deltas, csmap, trp, addrevisioncb=onchangelog) efiles = len(efiles) if not cgnodes: @@ -430,7 +430,7 @@ class cg1unpacker(object): ret = deltaheads + 1 return ret - def deltaiter(self, linkmapper): + def deltaiter(self): """ returns an iterator of the deltas in this changegroup @@ -446,10 +446,9 @@ class cg1unpacker(object): delta = chunkdata['delta'] flags = chunkdata['flags'] - link = linkmapper(cs) chain = node - yield (node, p1, p2, link, deltabase, delta, flags) + yield (node, p1, p2, cs, deltabase, delta, flags) class cg2unpacker(cg1unpacker): """Unpacker for cg2 streams. @@ -491,8 +490,8 @@ class cg3unpacker(cg2unpacker): d = chunkdata["filename"] repo.ui.debug("adding %s revisions\n" % d) dirlog = repo.manifestlog._revlog.dirlog(d) - deltas = self.deltaiter(revmap) - if not dirlog.addgroup(deltas, trp): + deltas = self.deltaiter() + if not dirlog.addgroup(deltas, revmap, trp): raise error.Abort(_("received dir revlog group is empty")) class headerlessfixup(object): @@ -983,8 +982,8 @@ def _addchangegroupfiles(repo, source, r fl = repo.file(f) o = len(fl) try: - deltas = source.deltaiter(revmap) - if not fl.addgroup(deltas, trp): + deltas = source.deltaiter() + if not fl.addgroup(deltas, revmap, trp): raise error.Abort(_("received file revlog group is empty")) except error.CensoredBaseError as e: raise error.Abort(_("received delta base is censored: %s") % e) diff --git a/mercurial/revlog.py b/mercurial/revlog.py --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -1910,7 +1910,7 @@ class revlog(object): ifh.write(data[1]) self.checkinlinesize(transaction, ifh) - def addgroup(self, deltas, transaction, addrevisioncb=None): + def addgroup(self, deltas, linkmapper, transaction, addrevisioncb=None): """ add a delta group @@ -1944,7 +1944,8 @@ class revlog(object): try: # loop through our set of deltas for data in deltas: - node, p1, p2, link, deltabase, delta, flags = data + node, p1, p2, linknode, deltabase, delta, flags = data + link = linkmapper(linknode) flags = flags or REVIDX_DEFAULT_FLAGS nodes.append(node) diff --git a/tests/test-revlog-raw.py b/tests/test-revlog-raw.py --- a/tests/test-revlog-raw.py +++ b/tests/test-revlog-raw.py @@ -119,7 +119,7 @@ def addgroupcopy(rlog, tr, destname=b'_d 'deltabase': rlog.node(deltaparent), 'delta': rlog.revdiff(deltaparent, r)} - def deltaiter(self, linkmapper): + def deltaiter(self): chain = None for chunkdata in iter(lambda: self.deltachunk(chain), {}): node = chunkdata['node'] @@ -130,17 +130,16 @@ def addgroupcopy(rlog, tr, destname=b'_d delta = chunkdata['delta'] flags = chunkdata['flags'] - link = linkmapper(cs) chain = node - yield (node, p1, p2, link, deltabase, delta, flags) + yield (node, p1, p2, cs, deltabase, delta, flags) def linkmap(lnode): return rlog.rev(lnode) dlog = newrevlog(destname, recreate=True) - dummydeltas = dummychangegroup().deltaiter(linkmap) - dlog.addgroup(dummydeltas, tr) + dummydeltas = dummychangegroup().deltaiter() + dlog.addgroup(dummydeltas, linkmap, tr) return dlog def lowlevelcopy(rlog, tr, destname=b'_destrevlog.i'):