diff mercurial/bundle2.py @ 23067:420a051616ce stable

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.
author Pierre-Yves David <pierre-yves.david@fb.com>
date Wed, 15 Oct 2014 03:52:20 -0700
parents ad144882318d
children e53f6b72a0e4
line wrap: on
line diff
--- a/mercurial/bundle2.py	Tue Oct 14 10:47:47 2014 -0700
+++ b/mercurial/bundle2.py	Wed Oct 15 03:52:20 2014 -0700
@@ -145,6 +145,7 @@
 preserve.
 """
 
+import sys
 import util
 import struct
 import urllib
@@ -673,9 +674,22 @@
         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