# HG changeset patch # User Pierre-Yves David # Date 2014-10-15 10:52:20 # Node ID 420a051616ceab0403c146040cbf8f022523f814 # Parent ad144882318db801ebdb0c5d2ccd61254a7c9e6b bundle2: transmit exception during part generation If an exception is raised during a bundle2 part payload generation it is now recorded in the bundle. If such exception occurs, we capture it, transmit an abort exception through the bundle, cleanly close the current part payload and raise it again. This allow to generate valid bundle even in case of exception so that the consumer does not wait forever for a dead producer. This also allow to raise the exception during unbundling at the exact point it happened during bundling make debugging easier. diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py --- a/mercurial/bundle2.py +++ b/mercurial/bundle2.py @@ -145,6 +145,7 @@ future, dropping the stream may become a preserve. """ +import sys import util import struct import urllib @@ -673,9 +674,22 @@ class bundlepart(object): yield _pack(_fpartheadersize, len(headerchunk)) yield headerchunk ## payload - for chunk in self._payloadchunks(): - yield _pack(_fpayloadsize, len(chunk)) - yield chunk + try: + for chunk in self._payloadchunks(): + yield _pack(_fpayloadsize, len(chunk)) + yield chunk + except Exception, exc: + # backup exception data for later + exc_info = sys.exc_info() + msg = 'unexpected error: %s' % exc + interpart = bundlepart('b2x:error:abort', [('message', msg)]) + interpart.id = 0 + yield _pack(_fpayloadsize, -1) + for chunk in interpart.getchunks(): + yield chunk + # abort current part payload + yield _pack(_fpayloadsize, 0) + raise exc_info[0], exc_info[1], exc_info[2] # end of payload yield _pack(_fpayloadsize, 0) self._generated = True diff --git a/tests/test-bundle2-format.t b/tests/test-bundle2-format.t --- a/tests/test-bundle2-format.t +++ b/tests/test-bundle2-format.t @@ -777,25 +777,22 @@ with reply Check handling of exception during generation. ---------------------------------------------- -(is currently not right) $ hg bundle2 --genraise > ../genfailed.hg2 abort: Someone set up us the bomb! [255] Should still be a valid bundle -(is currently not right) $ cat ../genfailed.hg2 HG2Y\x00\x00\x00\x00\x00\x00\x00\x11 (esc) - b2x:output\x00\x00\x00\x00\x00\x00 (no-eol) (esc) + b2x:output\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00L\x0fb2x:error:abort\x00\x00\x00\x00\x01\x00\x07-messageunexpected error: Someone set up us the bomb!\x00\x00\x00\x00\x00\x00\x00\x00 (no-eol) (esc) And its handling on the other size raise a clean exception -(is currently not right) $ cat ../genfailed.hg2 | hg unbundle2 0 unread bytes - abort: stream ended unexpectedly (got 0 bytes, expected 4) + abort: unexpected error: Someone set up us the bomb! [255]