[PATCH 1 of 5 STABLE] changegroup: cg3 has two empty groups *after* manifests

Martin von Zweigbergk martinvonz at google.com
Wed Jan 20 20:19:10 UTC 2016


# HG changeset patch
# User Martin von Zweigbergk <martinvonz at google.com>
# Date 1453254265 28800
#      Tue Jan 19 17:44:25 2016 -0800
# Branch stable
# Node ID 80448db8a1859f4b1f262e1ce4a062477d0053dc
# Parent  5f2a308bac94b72453e0147d59edae23509f9dd4
changegroup: cg3 has two empty groups *after* manifests

changegroup.getchunks() determines the end of the stream by looking
for an empty chunk group (two consecutive empty chunks). It ignores
empty groups in the first two groups. Changegroup 3 introduced an
empty chunk between the manifests and the files, which confuses
getchunks(). Since it comes after the first two, getchunks() will stop
there.

Fix by rewriting getchunks so it first counts two groups (empty or
not) and then keeps antostarts counting empty groups. With this counting,
changegroup 1 and 2 have exactly one empty group after the first two
groups, while changegroup 3 has two (one for directories and one for
files).

It's a little hard to test this at this point, but I have verified
that this patch fixes narrowhg (which was broken before this
patch). Also, future patches will fix "hg strip" with treemanifests,
and once that's done, getchunks() will be tested through tests of "hg
strip".

diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
--- a/mercurial/changegroup.py
+++ b/mercurial/changegroup.py
@@ -189,6 +189,8 @@
     deltaheader = _CHANGEGROUPV1_DELTA_HEADER
     deltaheadersize = struct.calcsize(deltaheader)
     version = '01'
+    _grouplistcount = 1 # One list of files after the manifests
+
     def __init__(self, fh, alg):
         if alg == 'UN':
             alg = None # get more modern without breaking too much
@@ -270,15 +272,19 @@
         """
         # an empty chunkgroup is the end of the changegroup
         # a changegroup has at least 2 chunkgroups (changelog and manifest).
-        # after that, an empty chunkgroup is the end of the changegroup
-        empty = False
+        # after that, changegroup versions 1 and 2 have a series of groups
+        # with one group per file. changegroup 3 has a series of directory
+        # manifests before the files.
         count = 0
-        while not empty or count <= 2:
+        emptycount = 0
+        while emptycount < self._grouplistcount:
             empty = True
             count += 1
             while True:
                 chunk = getchunk(self)
                 if not chunk:
+                    if empty and count > 2:
+                        emptycount += 1
                     break
                 empty = False
                 yield chunkheader(len(chunk))
@@ -515,6 +521,7 @@
     deltaheader = _CHANGEGROUPV3_DELTA_HEADER
     deltaheadersize = struct.calcsize(deltaheader)
     version = '03'
+    _grouplistcount = 2 # One list of manifests and one list of files
 
     def _deltaheader(self, headertuple, prevnode):
         node, p1, p2, deltabase, cs, flags = headertuple


More information about the Mercurial-devel mailing list