comparison mercurial/bundle2.py @ 23009:90f86ad3d4ff

bundle2: change header size and make them signed (new format) We are changing all integers that denote the size of a chunk to read to int32. There are two main motivations for that. First, we change everything to the same width (32 bits) to make it possible for a reasonably agnostic actor to forward a bundle2 without any extra processing. With this change, this could be achieved by just reading int32s and forwarding chunks of the size read. A bit a smartness would be logic to detect the end of stream but nothing too complicated. Second, we need some capacity to transmit special information during the bundle processing. For example we would like to be able to raise an exception while a part is being read if this exception happend while this part was generated. Having signed integer let us use negative numbers to trigger special events during the parsing of the bundle. The format is renamed for B2X to B2Y because this breaks binary compatibility. The B2X format support is dropped. It was experimental to allow this kind of things. All elements not directly related to the binary format remain flagged "b2x" because they are still compatible.
author Pierre-Yves David <pierre-yves.david@fb.com>
date Wed, 01 Oct 2014 23:40:23 -0500
parents d3137827016a
children 73f394f4affc
comparison
equal deleted inserted replaced
23008:d3137827016a 23009:90f86ad3d4ff
29 stream level parameters 29 stream level parameters
30 ------------------------ 30 ------------------------
31 31
32 Binary format is as follow 32 Binary format is as follow
33 33
34 :params size: (16 bits integer) 34 :params size: int32
35 35
36 The total number of Bytes used by the parameters 36 The total number of Bytes used by the parameters
37 37
38 :params value: arbitrary number of Bytes 38 :params value: arbitrary number of Bytes
39 39
62 Payload part 62 Payload part
63 ------------------------ 63 ------------------------
64 64
65 Binary format is as follow 65 Binary format is as follow
66 66
67 :header size: (16 bits inter) 67 :header size: int32
68 68
69 The total number of Bytes used by the part headers. When the header is empty 69 The total number of Bytes used by the part headers. When the header is empty
70 (size = 0) this is interpreted as the end of stream marker. 70 (size = 0) this is interpreted as the end of stream marker.
71 71
72 :header: 72 :header:
117 117
118 :payload: 118 :payload:
119 119
120 payload is a series of `<chunksize><chunkdata>`. 120 payload is a series of `<chunksize><chunkdata>`.
121 121
122 `chunksize` is a 32 bits integer, `chunkdata` are plain bytes (as much as 122 `chunksize` is an int32, `chunkdata` are plain bytes (as much as
123 `chunksize` says)` The payload part is concluded by a zero size chunk. 123 `chunksize` says)` The payload part is concluded by a zero size chunk.
124 124
125 The current implementation always produces either zero or one chunk. 125 The current implementation always produces either zero or one chunk.
126 This is an implementation limitation that will ultimately be lifted. 126 This is an implementation limitation that will ultimately be lifted.
127
128 `chunksize` can be negative to trigger special case processing. No such
129 processing is in place yet.
127 130
128 Bundle processing 131 Bundle processing
129 ============================ 132 ============================
130 133
131 Each part is processed in order using a "part handler". Handler are registered 134 Each part is processed in order using a "part handler". Handler are registered
153 from i18n import _ 156 from i18n import _
154 157
155 _pack = struct.pack 158 _pack = struct.pack
156 _unpack = struct.unpack 159 _unpack = struct.unpack
157 160
158 _magicstring = 'HG2X' 161 _magicstring = 'HG2Y'
159 162
160 _fstreamparamsize = '>H' 163 _fstreamparamsize = '>i'
161 _fpartheadersize = '>H' 164 _fpartheadersize = '>i'
162 _fparttypesize = '>B' 165 _fparttypesize = '>B'
163 _fpartid = '>I' 166 _fpartid = '>I'
164 _fpayloadsize = '>I' 167 _fpayloadsize = '>i'
165 _fpartparamcount = '>BB' 168 _fpartparamcount = '>BB'
166 169
167 preferedchunksize = 4096 170 preferedchunksize = 4096
168 171
169 def _makefpartparamsizes(nbparams): 172 def _makefpartparamsizes(nbparams):
494 if header is None: 497 if header is None:
495 header = self._readexact(4) 498 header = self._readexact(4)
496 magic, version = header[0:2], header[2:4] 499 magic, version = header[0:2], header[2:4]
497 if magic != 'HG': 500 if magic != 'HG':
498 raise util.Abort(_('not a Mercurial bundle')) 501 raise util.Abort(_('not a Mercurial bundle'))
499 if version != '2X': 502 if version != '2Y':
500 raise util.Abort(_('unknown bundle version %s') % version) 503 raise util.Abort(_('unknown bundle version %s') % version)
501 self.ui.debug('start processing of %s stream\n' % header) 504 self.ui.debug('start processing of %s stream\n' % header)
502 505
503 @util.propertycache 506 @util.propertycache
504 def params(self): 507 def params(self):
779 data = self._payloadstream.read(size) 782 data = self._payloadstream.read(size)
780 if size is None or len(data) < size: 783 if size is None or len(data) < size:
781 self.consumed = True 784 self.consumed = True
782 return data 785 return data
783 786
784 capabilities = {'HG2X': (), 787 capabilities = {'HG2Y': (),
785 'b2x:listkeys': (), 788 'b2x:listkeys': (),
786 'b2x:pushkey': (), 789 'b2x:pushkey': (),
787 'b2x:changegroup': (), 790 'b2x:changegroup': (),
788 } 791 }
789 792