diff mercurial/exchangev2.py @ 39814:d059cb669632

wireprotov2: allow multiple fields to follow revision maps The *data wire protocol commands emit a series of CBOR values. Because revision/delta data may be large, their data is emitted outside the map as a top-level bytestring value. Before this commit, we'd emit a single optional bytestring value after the revision descriptor map. This got the job done. But it was limiting in that we could only send a single field. And, it required the consumer to know that the presence of a key in the map implied the existence of a following bytestring value. This commit changes the encoding strategy so top-level bytestring values in the stream are explicitly denoted in a "fieldsfollowing" key. This key contains an array defining what fields that follow and the expected size of each field. By defining things this way, we can easily send N bytestring values without any ambiguity about their order. In addition, clients only need to know how to parse ``fieldsfollowing`` to know if extra values are present. Because this breaks backwards compatibility, we've bumped the version number of the wire protocol version 2 API endpoint. Differential Revision: https://phab.mercurial-scm.org/D4620
author Gregory Szorc <gregory.szorc@gmail.com>
date Thu, 20 Sep 2018 12:57:23 -0700
parents aa7e312375cf
children 7a347d362a45
line wrap: on
line diff
--- a/mercurial/exchangev2.py	Mon Sep 17 11:54:00 2018 -0700
+++ b/mercurial/exchangev2.py	Thu Sep 20 12:57:23 2018 -0700
@@ -167,11 +167,16 @@
             # TODO add mechanism for extensions to examine records so they
             # can siphon off custom data fields.
 
+            extrafields = {}
+
+            for field, size in cset.get(b'fieldsfollowing', []):
+                extrafields[field] = next(objs)
+
             # Some entries might only be metadata only updates.
-            if b'revisionsize' not in cset:
+            if b'revision' not in extrafields:
                 continue
 
-            data = next(objs)
+            data = extrafields[b'revision']
 
             yield (
                 node,
@@ -227,12 +232,17 @@
         for manifest in objs:
             node = manifest[b'node']
 
-            if b'deltasize' in manifest:
+            extrafields = {}
+
+            for field, size in manifest.get(b'fieldsfollowing', []):
+                extrafields[field] = next(objs)
+
+            if b'delta' in extrafields:
                 basenode = manifest[b'deltabasenode']
-                delta = next(objs)
-            elif b'revisionsize' in manifest:
+                delta = extrafields[b'delta']
+            elif b'revision' in extrafields:
                 basenode = nullid
-                revision = next(objs)
+                revision = extrafields[b'revision']
                 delta = mdiff.trivialdiffheader(len(revision)) + revision
             else:
                 continue
@@ -331,12 +341,17 @@
         for filerevision in objs:
             node = filerevision[b'node']
 
-            if b'deltasize' in filerevision:
+            extrafields = {}
+
+            for field, size in filerevision.get(b'fieldsfollowing', []):
+                extrafields[field] = next(objs)
+
+            if b'delta' in extrafields:
                 basenode = filerevision[b'deltabasenode']
-                delta = next(objs)
-            elif b'revisionsize' in filerevision:
+                delta = extrafields[b'delta']
+            elif b'revision' in extrafields:
                 basenode = nullid
-                revision = next(objs)
+                revision = extrafields[b'revision']
                 delta = mdiff.trivialdiffheader(len(revision)) + revision
             else:
                 continue