From patchwork Tue Nov 4 14:20:48 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [5,of,5] changegroup: introduce cg2packer/unpacker From: Pierre-Yves David X-Patchwork-Id: 6563 Message-Id: To: mercurial-devel@selenic.com Cc: Sune Foldager Date: Tue, 04 Nov 2014 14:20:48 +0000 # HG changeset patch # User Sune Foldager # Date 1413549671 -7200 # Fri Oct 17 14:41:11 2014 +0200 # Node ID d86e8a57e2070d2213d80d26b2000d3a626d157c # Parent 7407e3ea154921922956cbaf2e7ff0d89d48634c changegroup: introduce cg2packer/unpacker cg2 supports generaldelta in changegroups, to be used in bundle2. Since generaldelta is handled directly in cg2, reordering is switched off by default. diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py --- a/mercurial/changegroup.py +++ b/mercurial/changegroup.py @@ -11,10 +11,11 @@ from node import nullrev, nullid, hex, s import mdiff, util, dagutil import struct, os, bz2, zlib, tempfile import discovery, error, phases, branchmap _CHANGEGROUPV1_DELTA_HEADER = "20s20s20s20s" +_CHANGEGROUPV2_DELTA_HEADER = "20s20s20s20s20s" def readexactly(stream, n): '''read n bytes from stream.read and abort if less was available''' s = stream.read(n) if len(s) < n: @@ -213,10 +214,19 @@ class cg1unpacker(object): next = pos + 2**20 yield chunk[pos:next] pos = next yield closechunk() +class cg2unpacker(cg1unpacker): + deltaheader = _CHANGEGROUPV2_DELTA_HEADER + deltaheadersize = struct.calcsize(deltaheader) + + def _deltaheader(self, headertuple, prevnode): + node, p1, p2, deltabase, cs = headertuple + return node, p1, p2, deltabase, cs + + class headerlessfixup(object): def __init__(self, fh, h): self._h = h self._fh = fh def read(self, n): @@ -408,14 +418,17 @@ class cg1packer(object): yield self.fileheader(fname) for chunk in self.group(filenodes, filerevlog, lookupfilelog, reorder=reorder): yield chunk + def deltaparent(self, revlog, rev, p1, p2, prev): + return prev + def revchunk(self, revlog, rev, prev, linknode): node = revlog.node(rev) p1, p2 = revlog.parentrevs(rev) - base = prev + base = self.deltaparent(revlog, rev, p1, p2, prev) prefix = '' if base == nullrev: delta = revlog.revision(node) prefix = mdiff.trivialdiffheader(len(delta)) @@ -431,11 +444,33 @@ class cg1packer(object): yield delta def builddeltaheader(self, node, p1n, p2n, basenode, linknode): # do nothing with basenode, it is implicitly the previous one in HG10 return struct.pack(self.deltaheader, node, p1n, p2n, linknode) -packermap = {'01': (cg1packer, cg1unpacker)} +class cg2packer(cg1packer): + + deltaheader = _CHANGEGROUPV2_DELTA_HEADER + + def group(self, nodelist, revlog, lookup, units=None, reorder=None): + if (revlog._generaldelta and reorder is not True): + reorder = False + return cg1packer.group(self, nodelist, revlog, lookup, + units=units, reorder=reorder) + + def deltaparent(self, revlog, rev, p1, p2, prev): + dp = revlog.deltaparent(rev) + # avoid storing full revisions; pick prev in those cases + # also pick prev when we can't be sure remote has dp + if dp == nullrev or (dp != p1 and dp != p2 and dp != prev): + return prev + return dp + + def builddeltaheader(self, node, p1n, p2n, basenode, linknode): + return struct.pack(self.deltaheader, node, p1n, p2n, basenode, linknode) + +packermap = {'01': (cg1packer, cg1unpacker), + '02': (cg2packer, cg2unpacker)} def _changegroupinfo(repo, nodes, source): if repo.ui.verbose or source == 'bundle': repo.ui.status(_("%d changesets found\n") % len(nodes)) if repo.ui.debugflag: