Patchwork [5,of,5] changegroup: introduce cg2packer/unpacker

login
register
mail settings
Submitter Pierre-Yves David
Date Nov. 4, 2014, 2:20 p.m.
Message ID <d86e8a57e2070d2213d8.1415110848@marginatus.alto.octopoid.net>
Download mbox | patch
Permalink /patch/6563/
State Accepted
Headers show

Comments

Pierre-Yves David - Nov. 4, 2014, 2:20 p.m.
# HG changeset patch
# User Sune Foldager <cryo@cyanite.org>
# 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.
Matt Mackall - Nov. 4, 2014, 10:52 p.m.
On Tue, 2014-11-04 at 14:20 +0000, Pierre-Yves David wrote:
> # HG changeset patch
> # User Sune Foldager <cryo@cyanite.org>
> # Date 1413549671 -7200
> #      Fri Oct 17 14:41:11 2014 +0200
> # Node ID d86e8a57e2070d2213d80d26b2000d3a626d157c
> # Parent  7407e3ea154921922956cbaf2e7ff0d89d48634c
> changegroup: introduce cg2packer/unpacker

These are queued for default, thanks.

Patch

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: