comparison mercurial/wireprotoframing.py @ 37722:89a16704114c

wireprotov2: define response data as CBOR Previously, response data was defined as a stream of bytes. We had the option to declare it as CBOR using a frame flag. We've converged all wire protocol commands exposed on version 2 to CBOR. I think consistency is important. The overhead to encoding things with CBOR is minimal. Even a very large bytestring can be efficiently encoded using an indefinite length bytestring. Now, there are limitations with consumers not being able to efficiently stream large CBOR values. But these feel like solvable problems. This commit removes the "is CBOR" frame flag from command response frames and defines the frame as always consisting of a stream of CBOR values. The framing protocol media type has been bumped to reflect this BC change. Differential Revision: https://phab.mercurial-scm.org/D3382
author Gregory Szorc <gregory.szorc@gmail.com>
date Sat, 14 Apr 2018 12:07:31 -0700
parents e6870bca1f47
children e8fba6d578f0
comparison
equal deleted inserted replaced
37721:f7673845b167 37722:89a16704114c
79 b'eos': FLAG_COMMAND_DATA_EOS, 79 b'eos': FLAG_COMMAND_DATA_EOS,
80 } 80 }
81 81
82 FLAG_BYTES_RESPONSE_CONTINUATION = 0x01 82 FLAG_BYTES_RESPONSE_CONTINUATION = 0x01
83 FLAG_BYTES_RESPONSE_EOS = 0x02 83 FLAG_BYTES_RESPONSE_EOS = 0x02
84 FLAG_BYTES_RESPONSE_CBOR = 0x04
85 84
86 FLAGS_BYTES_RESPONSE = { 85 FLAGS_BYTES_RESPONSE = {
87 b'continuation': FLAG_BYTES_RESPONSE_CONTINUATION, 86 b'continuation': FLAG_BYTES_RESPONSE_CONTINUATION,
88 b'eos': FLAG_BYTES_RESPONSE_EOS, 87 b'eos': FLAG_BYTES_RESPONSE_EOS,
89 b'cbor': FLAG_BYTES_RESPONSE_CBOR,
90 } 88 }
91 89
92 FLAG_ERROR_RESPONSE_PROTOCOL = 0x01 90 FLAG_ERROR_RESPONSE_PROTOCOL = 0x01
93 FLAG_ERROR_RESPONSE_APPLICATION = 0x02 91 FLAG_ERROR_RESPONSE_APPLICATION = 0x02
94 92
348 payload=data) 346 payload=data)
349 347
350 if done: 348 if done:
351 break 349 break
352 350
353 def createbytesresponseframesfrombytes(stream, requestid, data, iscbor=False, 351 def createbytesresponseframesfrombytes(stream, requestid, data,
354 maxframesize=DEFAULT_MAX_FRAME_SIZE): 352 maxframesize=DEFAULT_MAX_FRAME_SIZE):
355 """Create a raw frame to send a bytes response from static bytes input. 353 """Create a raw frame to send a bytes response from static bytes input.
356 354
357 Returns a generator of bytearrays. 355 Returns a generator of bytearrays.
358 """ 356 """
359 357
360 # Simple case of a single frame. 358 # Simple case of a single frame.
361 if len(data) <= maxframesize: 359 if len(data) <= maxframesize:
362 flags = FLAG_BYTES_RESPONSE_EOS 360 flags = FLAG_BYTES_RESPONSE_EOS
363 if iscbor:
364 flags |= FLAG_BYTES_RESPONSE_CBOR
365
366 yield stream.makeframe(requestid=requestid, 361 yield stream.makeframe(requestid=requestid,
367 typeid=FRAME_TYPE_BYTES_RESPONSE, 362 typeid=FRAME_TYPE_BYTES_RESPONSE,
368 flags=flags, 363 flags=flags,
369 payload=data) 364 payload=data)
370 return 365 return
377 372
378 if done: 373 if done:
379 flags = FLAG_BYTES_RESPONSE_EOS 374 flags = FLAG_BYTES_RESPONSE_EOS
380 else: 375 else:
381 flags = FLAG_BYTES_RESPONSE_CONTINUATION 376 flags = FLAG_BYTES_RESPONSE_CONTINUATION
382
383 if iscbor:
384 flags |= FLAG_BYTES_RESPONSE_CBOR
385 377
386 yield stream.makeframe(requestid=requestid, 378 yield stream.makeframe(requestid=requestid,
387 typeid=FRAME_TYPE_BYTES_RESPONSE, 379 typeid=FRAME_TYPE_BYTES_RESPONSE,
388 flags=flags, 380 flags=flags,
389 payload=chunk) 381 payload=chunk)
614 if not meth: 606 if not meth:
615 raise error.ProgrammingError('unhandled state: %s' % self._state) 607 raise error.ProgrammingError('unhandled state: %s' % self._state)
616 608
617 return meth(frame) 609 return meth(frame)
618 610
619 def onbytesresponseready(self, stream, requestid, data, iscbor=False): 611 def onbytesresponseready(self, stream, requestid, data):
620 """Signal that a bytes response is ready to be sent to the client. 612 """Signal that a bytes response is ready to be sent to the client.
621 613
622 The raw bytes response is passed as an argument. 614 The raw bytes response is passed as an argument.
623 """ 615 """
624 ensureserverstream(stream) 616 ensureserverstream(stream)
625 617
626 def sendframes(): 618 def sendframes():
627 for frame in createbytesresponseframesfrombytes(stream, requestid, 619 for frame in createbytesresponseframesfrombytes(stream, requestid,
628 data, 620 data):
629 iscbor=iscbor):
630 yield frame 621 yield frame
631 622
632 self._activecommands.remove(requestid) 623 self._activecommands.remove(requestid)
633 624
634 result = sendframes() 625 result = sendframes()
1065 1056
1066 return 'responsedata', { 1057 return 'responsedata', {
1067 'request': request, 1058 'request': request,
1068 'expectmore': frame.flags & FLAG_BYTES_RESPONSE_CONTINUATION, 1059 'expectmore': frame.flags & FLAG_BYTES_RESPONSE_CONTINUATION,
1069 'eos': frame.flags & FLAG_BYTES_RESPONSE_EOS, 1060 'eos': frame.flags & FLAG_BYTES_RESPONSE_EOS,
1070 'cbor': frame.flags & FLAG_BYTES_RESPONSE_CBOR,
1071 'data': frame.payload, 1061 'data': frame.payload,
1072 } 1062 }