changeset 39052:d662959dc881

changegroup: emit revisiondelta instances from deltagroup() By abstracting the concept of a delta group away from its serialization (the changegroup format), we make it easier to establish alternate serialization formats. We also make it possible to move aspects of delta group generation into the storage layer. This will allow storage to make decisions about e.g. delta parent choices without the changegroup code needing storage APIs to determine delta parents. We're still a bit of a way from there. Future commits will work towards that world. Differential Revision: https://phab.mercurial-scm.org/D4211
author Gregory Szorc <gregory.szorc@gmail.com>
date Wed, 08 Aug 2018 14:44:48 -0700
parents c4a2d19d393a
children ad9eccedb379
files mercurial/changegroup.py
diffstat 1 files changed, 38 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/changegroup.py	Wed Aug 08 14:33:33 2018 -0700
+++ b/mercurial/changegroup.py	Wed Aug 08 14:44:48 2018 -0700
@@ -522,6 +522,15 @@
     # Iterable of chunks holding raw delta data.
     deltachunks = attr.ib()
 
+def _revisiondeltatochunks(delta, headerfn):
+    """Serialize a revisiondelta to changegroup chunks."""
+    meta = headerfn(delta)
+    l = len(meta) + sum(len(x) for x in delta.deltachunks)
+    yield chunkheader(l)
+    yield meta
+    for x in delta.deltachunks:
+        yield x
+
 def _sortnodesnormal(store, nodes, reorder):
     """Sort nodes for changegroup generation and turn into revnums."""
     # for generaldelta revlogs, we linearize the revs; this will both be
@@ -682,18 +691,12 @@
     )
 
 def deltagroup(repo, revs, store, ischangelog, lookup, deltaparentfn,
-               deltaheaderfn, units=None,
+               units=None,
                ellipses=False, clrevtolocalrev=None, fullclnodes=None,
                precomputedellipsis=None):
-    """Calculate a delta group, yielding a sequence of changegroup chunks
-    (strings).
+    """Calculate deltas for a set of revisions.
 
-    Given a list of changeset revs, return a set of deltas and
-    metadata corresponding to nodes. The first delta is
-    first parent(nodelist[0]) -> nodelist[0], the receiver is
-    guaranteed to have this parent as it has all history before
-    these changesets. In the case firstparent is nullrev the
-    changegroup starts with a full revision.
+    Is a generator of ``revisiondelta`` instances.
 
     If units is not None, progress detail will be generated, units specifies
     the type of revlog that is touched (changelog, manifest, etc.).
@@ -739,15 +742,8 @@
             delta = _revisiondeltanormal(store, curr, prev, linknode,
                                          deltaparentfn)
 
-        if not delta:
-            continue
-
-        meta = deltaheaderfn(delta)
-        l = len(meta) + sum(len(x) for x in delta.deltachunks)
-        yield chunkheader(l)
-        yield meta
-        for x in delta.deltachunks:
-            yield x
+        if delta:
+            yield delta
 
     if progress:
         progress.complete()
@@ -831,10 +827,11 @@
         self._verbosenote(_('uncompressed size of bundle content:\n'))
         size = 0
 
-        clstate, chunks = self._generatechangelog(cl, clnodes)
-        for chunk in chunks:
-            size += len(chunk)
-            yield chunk
+        clstate, deltas = self._generatechangelog(cl, clnodes)
+        for delta in deltas:
+            for chunk in _revisiondeltatochunks(delta, self._builddeltaheader):
+                size += len(chunk)
+                yield chunk
 
         close = closechunk()
         size += len(close)
@@ -875,16 +872,18 @@
             commonrevs, clrevorder, fastpathlinkrev, mfs, fnodes, source,
             clstate['clrevtomanifestrev'])
 
-        for dir, chunks in it:
+        for dir, deltas in it:
             if dir:
                 assert self.version == b'03'
                 chunk = _fileheader(dir)
                 size += len(chunk)
                 yield chunk
 
-            for chunk in chunks:
-                size += len(chunk)
-                yield chunk
+            for delta in deltas:
+                chunks = _revisiondeltatochunks(delta, self._builddeltaheader)
+                for chunk in chunks:
+                    size += len(chunk)
+                    yield chunk
 
             close = closechunk()
             size += len(close)
@@ -905,14 +904,16 @@
                                 source, mfdicts, fastpathlinkrev,
                                 fnodes, clrevs)
 
-        for path, chunks in it:
+        for path, deltas in it:
             h = _fileheader(path)
             size = len(h)
             yield h
 
-            for chunk in chunks:
-                size += len(chunk)
-                yield chunk
+            for delta in deltas:
+                chunks = _revisiondeltatochunks(delta, self._builddeltaheader)
+                for chunk in chunks:
+                    size += len(chunk)
+                    yield chunk
 
             close = closechunk()
             size += len(close)
@@ -993,7 +994,7 @@
 
         gen = deltagroup(
             self._repo, revs, cl, True, lookupcl,
-            self._deltaparentfn, self._builddeltaheader,
+            self._deltaparentfn,
             ellipses=self._ellipses,
             units=_('changesets'),
             clrevtolocalrev={},
@@ -1080,16 +1081,16 @@
                 revs = _sortnodesnormal(store, prunednodes,
                                         self._reorder)
 
-            it = deltagroup(
+            deltas = deltagroup(
                 self._repo, revs, store, False, lookupfn,
-                self._deltaparentfn, self._builddeltaheader,
+                self._deltaparentfn,
                 ellipses=self._ellipses,
                 units=_('manifests'),
                 clrevtolocalrev=clrevtolocalrev,
                 fullclnodes=self._fullclnodes,
                 precomputedellipsis=self._precomputedellipsis)
 
-            yield dir, it
+            yield dir, deltas
 
     # The 'source' parameter is useful for extensions
     def generatefiles(self, changedfiles, commonrevs, source,
@@ -1172,15 +1173,15 @@
 
                 progress.update(i + 1, item=fname)
 
-                it = deltagroup(
+                deltas = deltagroup(
                     self._repo, revs, filerevlog, False, lookupfilelog,
-                    self._deltaparentfn, self._builddeltaheader,
+                    self._deltaparentfn,
                     ellipses=self._ellipses,
                     clrevtolocalrev=clrevtolocalrev,
                     fullclnodes=self._fullclnodes,
                     precomputedellipsis=self._precomputedellipsis)
 
-                yield fname, it
+                yield fname, deltas
 
         progress.complete()