Mercurial > hg
comparison mercurial/bundle2.py @ 20876:ddd56f3eb786
bundle2: support for bundling and unbundling payload
We add the ability to bundle and unbundle a payload in parts. The payload is the
actual binary data of the part. It is used to convey all the applicative data.
For now we stick to very simple implementation with all the data fit in single
chunk. This open the door to some bundle2 testing usage. This will be improved before
bundle2 get used for real. We need to be able to stream the payload in multiple
part to exchange any changegroup efficiently. This simple version will do for
now.
Bundling and unbundling are done in the same changeset because the test for
parts is less modular. However, the result is not too complex.
author | Pierre-Yves David <pierre-yves.david@fb.com> |
---|---|
date | Wed, 19 Mar 2014 23:36:15 -0700 |
parents | 9a75d2559cff |
children | 9e9e3a4e9261 |
comparison
equal
deleted
inserted
replaced
20875:cc62c9d6887a | 20876:ddd56f3eb786 |
---|---|
87 :typename: alphanumerical part name | 87 :typename: alphanumerical part name |
88 :option: we do not support option yet this denoted by two 16 bites zero. | 88 :option: we do not support option yet this denoted by two 16 bites zero. |
89 | 89 |
90 :payload: | 90 :payload: |
91 | 91 |
92 The current payload is a 32bit integer with a value of 0. This is | 92 payload is a series of `<chunksize><chunkdata>`. |
93 considered an "empty" payload. | 93 |
94 `chunksize` is a 32 bits integer, `chunkdata` are plain bytes (as much as | |
95 `chunksize` says)` The payload part is concluded by a zero size chunk. | |
96 | |
97 The current implementation always produces either zero or one chunk. | |
98 This is an implementation limitation that will ultimatly be lifted. | |
94 """ | 99 """ |
95 | 100 |
96 import util | 101 import util |
97 import struct | 102 import struct |
98 import urllib | 103 import urllib |
107 _magicstring = 'HG20' | 112 _magicstring = 'HG20' |
108 | 113 |
109 _fstreamparamsize = '>H' | 114 _fstreamparamsize = '>H' |
110 _fpartheadersize = '>H' | 115 _fpartheadersize = '>H' |
111 _fparttypesize = '>B' | 116 _fparttypesize = '>B' |
117 _fpayloadsize = '>I' | |
112 | 118 |
113 class bundle20(object): | 119 class bundle20(object): |
114 """represent an outgoing bundle2 container | 120 """represent an outgoing bundle2 container |
115 | 121 |
116 Use the `addparam` method to add stream level parameter. and `addpart` to | 122 Use the `addparam` method to add stream level parameter. and `addpart` to |
255 self._offset = offset + size | 261 self._offset = offset + size |
256 return data | 262 return data |
257 typesize = _unpack(_fparttypesize, fromheader(1))[0] | 263 typesize = _unpack(_fparttypesize, fromheader(1))[0] |
258 parttype = fromheader(typesize) | 264 parttype = fromheader(typesize) |
259 self.ui.debug('part type: "%s"\n' % parttype) | 265 self.ui.debug('part type: "%s"\n' % parttype) |
260 current = part(parttype) | |
261 assert fromheader(2) == '\0\0' # no option for now | 266 assert fromheader(2) == '\0\0' # no option for now |
262 del self._offset # clean up layer, nobody saw anything. | 267 del self._offset # clean up layer, nobody saw anything. |
263 self.ui.debug('part parameters: 0\n') | 268 self.ui.debug('part parameters: 0\n') |
264 assert self._readexact(4) == '\0\0\0\0' #empty payload | 269 payload = [] |
265 self.ui.debug('payload chunk size: 0\n') | 270 payloadsize = self._unpack(_fpayloadsize)[0] |
271 self.ui.debug('payload chunk size: %i\n' % payloadsize) | |
272 while payloadsize: | |
273 payload.append(self._readexact(payloadsize)) | |
274 payloadsize = self._unpack(_fpayloadsize)[0] | |
275 self.ui.debug('payload chunk size: %i\n' % payloadsize) | |
276 payload = ''.join(payload) | |
277 current = part(parttype, data=payload) | |
266 return current | 278 return current |
267 | 279 |
268 | 280 |
269 class part(object): | 281 class part(object): |
270 """A bundle2 part contains application level payload | 282 """A bundle2 part contains application level payload |
284 '\0\0', # No option support for now. | 296 '\0\0', # No option support for now. |
285 ] | 297 ] |
286 headerchunk = ''.join(header) | 298 headerchunk = ''.join(header) |
287 yield _pack(_fpartheadersize, len(headerchunk)) | 299 yield _pack(_fpartheadersize, len(headerchunk)) |
288 yield headerchunk | 300 yield headerchunk |
289 # force empty part for now | 301 # we only support fixed size data now. |
290 yield '\0\0\0\0' | 302 # This will be improved in the future. |
291 | 303 if len(self.data): |
292 | 304 yield _pack(_fpayloadsize, len(self.data)) |
305 yield self.data | |
306 # end of payload | |
307 yield _pack(_fpayloadsize, 0) | |
308 | |
309 |