Rev 4896: Finally, we have something that can at least handle simple reconnects. in http://bazaar.launchpad.net/~jameinel/bzr/2.1-client-reconnect-819604

John Arbash Meinel john at arbash-meinel.com
Mon Oct 3 12:34:10 UTC 2011


At http://bazaar.launchpad.net/~jameinel/bzr/2.1-client-reconnect-819604

------------------------------------------------------------
revno: 4896
revision-id: john at arbash-meinel.com-20111003123350-4n1hi64h03sy9cri
parent: john at arbash-meinel.com-20111003120203-i5jnh9c0vic0a3ty
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: 2.1-client-reconnect-819604
timestamp: Mon 2011-10-03 14:33:50 +0200
message:
  Finally, we have something that can at least handle simple reconnects.
  
  I've tested that it works to 'bzr branch qbzr' locally, and interrupt the server
  with SIGHUP during the streaming-of-content phase. After which the next request
  notices that the ssh process is no longer talking to us, and we reconnect to
  make the next request.
  
  That all works well. Though if I SIGHUP during get_parent_map_rpc, I've seen it
  fail during the 'read_response' rather than the write phase.
  
  But a decent first step.
-------------- next part --------------
=== modified file 'bzrlib/smart/client.py'
--- a/bzrlib/smart/client.py	2011-10-03 11:49:17 +0000
+++ b/bzrlib/smart/client.py	2011-10-03 12:33:50 +0000
@@ -40,10 +40,8 @@
     def __repr__(self):
         return '%s(%r)' % (self.__class__.__name__, self._medium)
 
-    def _send_request_no_retry(self, protocol_version, method, args, body=None,
+    def _send_request_no_retry(self, encoder, method, args, body=None,
                                readv_body=None, body_stream=None):
-        encoder, response_handler = self._construct_protocol(
-            protocol_version)
         encoder.set_headers(self._headers)
         if body is not None:
             if readv_body is not None:
@@ -62,25 +60,33 @@
             encoder.call_with_body_stream((method, ) + args, body_stream)
         else:
             encoder.call(method, *args)
-        return response_handler
 
     def _send_request(self, protocol_version, method, args, body=None,
                       readv_body=None, body_stream=None):
+        encoder, response_handler = self._construct_protocol(
+            protocol_version)
         try:
-            response_handler = self._send_request_no_retry(protocol_version,
-                method, args, body=body, readv_body=readv_body,
-                body_stream=body_stream)
+            self._send_request_no_retry(encoder, method, args, body=body,
+                readv_body=readv_body, body_stream=body_stream)
         except errors.ConnectionReset, e:
             # If we fail during the _send_request_no_retry phase, then we can
             # be confident that the server did not get our request, because we
             # haven't started waiting for the reply yet. So try the request
             # again. We only issue a single retry, because if the connection
             # really is down, there is no reason to loop endlessly.
+            # XXX: If body_stream is not None, then we probably have a problem
+            #      here, because the body stream is partially consumed.
+            if body_stream is not None:
+                raise
             trace.log_exception_quietly()
             trace.warning('ConnectionReset calling %s, retrying' % (method,))
-            response_handler = self._send_request_no_retry(protocol_version,
-                method, args, body=body, readv_body=readv_body,
-                body_stream=body_stream)
+            self._medium.reset()
+            # encoder._medium_request.finished_writing()
+            # encoder._medium_request.finished_reading()
+            encoder, response_handler = self._construct_protocol(
+                protocol_version)
+            self._send_request_no_retry(encoder, method, args, body=body,
+                readv_body=readv_body, body_stream=body_stream)
         return response_handler
 
     def _run_call_hooks(self, method, args, body, readv_body):

=== modified file 'bzrlib/smart/medium.py'
--- a/bzrlib/smart/medium.py	2011-10-03 12:02:03 +0000
+++ b/bzrlib/smart/medium.py	2011-10-03 12:33:50 +0000
@@ -712,6 +712,17 @@
         """
         return SmartClientStreamMediumRequest(self)
 
+    def reset(self):
+        """We have been disconnected, reset current state.
+
+        This resets things like _current_request and connected state.
+        """
+        # TODO: Arguably if self._current_request is not None, we could call
+        #       self._current_request.finished_writing()/finished_reading(),
+        #       etc.
+        self.disconnect()
+        self._current_request = None
+
 
 class SmartSimplePipesClientMedium(SmartClientStreamMedium):
     """A client medium using simple pipes.



More information about the bazaar-commits mailing list