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