Rev 6148: Start working on exposing timeout as a configuration item. in http://bazaar.launchpad.net/~jameinel/bzr/drop-idle-connections-824797

John Arbash Meinel john at arbash-meinel.com
Thu Sep 15 09:50:37 UTC 2011


At http://bazaar.launchpad.net/~jameinel/bzr/drop-idle-connections-824797

------------------------------------------------------------
revno: 6148
revision-id: john at arbash-meinel.com-20110915095023-wquhin2e0uh1nq1e
parent: john at arbash-meinel.com-20110915093339-v21h0ca9uu1yhfwj
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: drop-idle-connections-824797
timestamp: Thu 2011-09-15 11:50:23 +0200
message:
  Start working on exposing timeout as a configuration item.
-------------- next part --------------
=== modified file 'bzrlib/config.py'
--- a/bzrlib/config.py	2011-09-09 14:17:34 +0000
+++ b/bzrlib/config.py	2011-09-15 09:50:23 +0000
@@ -2568,6 +2568,12 @@
 lost if the machine crashes.  See also dirstate.fdatasync.
 '''))
 
+option_registry.register(
+    Option('serve.client_timeout',
+           default=300, from_unicode=int_from_store,
+           help="If we wait for a new request from a client for more than"
+                " X seconds, consider the client idle, and hangup."))
+
 
 class Section(object):
     """A section defines a dict of option name => value.

=== modified file 'bzrlib/smart/medium.py'
--- a/bzrlib/smart/medium.py	2011-09-14 13:47:07 +0000
+++ b/bzrlib/smart/medium.py	2011-09-15 09:50:23 +0000
@@ -48,7 +48,7 @@
 from bzrlib.smart import client, protocol, request, vfs
 from bzrlib.transport import ssh
 """)
-from bzrlib import osutils
+from bzrlib import config, osutils
 
 # Throughout this module buffer size parameters are either limited to be at
 # most _MAX_READ_SIZE, or are ignored and _MAX_READ_SIZE is used instead.
@@ -204,12 +204,10 @@
         the stream.  See also the _push_back method.
     """
 
-    # Default timeout is 300s before closing the client connection
-    _stream_medium_timeout = 300
-    # Poll every X seconds to see if anything new has happened.
-    _stream_medium_fast_timeout = 1.0
+    _DEFAULT_CLIENT_TIMEOUT = float(config.option_registry.get(
+        'serve.client_timeout').default)
 
-    def __init__(self, backing_transport, root_client_path='/'):
+    def __init__(self, backing_transport, root_client_path='/', timeout=None):
         """Construct new server.
 
         :param backing_transport: Transport for the directory served.
@@ -218,6 +216,10 @@
         self.backing_transport = backing_transport
         self.root_client_path = root_client_path
         self.finished = False
+        if timeout is None:
+            timeout = self._DEFAULT_CLIENT_TIMEOUT
+        self._client_timeout = timeout
+        self._client_poll_timeout = min(timeout / 10.0, 1.0)
         SmartMedium.__init__(self)
 
     def serve(self):
@@ -266,7 +268,7 @@
 
         :returns: a SmartServerRequestProtocol.
         """
-        if self._wait_for_bytes_with_timeout(self._stream_medium_timeout):
+        if self._wait_for_bytes_with_timeout(self._client_timeout):
             # TODO: We would like to have a nicer message than this. However,
             #       we don't have any context available to us about who is
             #       connecting for us to give a more useful message. :(
@@ -274,7 +276,7 @@
             #       from)
             raise errors.ConnectionTimeout(
                 'disconnecting client after %.1f seconds'
-                % (self._stream_medium_timeout))
+                % (self._client_timeout))
         bytes = self._get_line()
         protocol_factory, unused_bytes = _get_protocol_factory_for_bytes(bytes)
         protocol = protocol_factory(
@@ -287,7 +289,7 @@
         # Use local variables to handle when the interpreter is shutting down
         try:
             if (timeout_seconds is None
-                or timeout_seconds <= self._stream_medium_fast_timeout):
+                or timeout_seconds <= self._client_poll_timeout):
                 rs, _, _ = select.select([fd], [], [], timeout_seconds)
             else:
                 # It looks like during the test suite, we close the server-side
@@ -303,7 +305,7 @@
                 rs = []
                 while not rs and time.time() < t_end:
                     rs, _, _ = select.select([fd], [], [],
-                                             self._stream_medium_fast_timeout)
+                                             self._client_poll_timeout)
         except (select.error, socket.error) as e:
             err = getattr(e, 'errno', None)
             if err is None:
@@ -347,14 +349,16 @@
 
 class SmartServerSocketStreamMedium(SmartServerStreamMedium):
 
-    def __init__(self, sock, backing_transport, root_client_path='/'):
+    def __init__(self, sock, backing_transport, root_client_path='/',
+                 timeout=None):
         """Constructor.
 
         :param sock: the socket the server will read from.  It will be put
             into blocking mode.
         """
         SmartServerStreamMedium.__init__(
-            self, backing_transport, root_client_path=root_client_path)
+            self, backing_transport, root_client_path=root_client_path,
+            timeout=timeout)
         sock.setblocking(True)
         self.socket = sock
 
@@ -409,14 +413,15 @@
 
 class SmartServerPipeStreamMedium(SmartServerStreamMedium):
 
-    def __init__(self, in_file, out_file, backing_transport):
+    def __init__(self, in_file, out_file, backing_transport, timeout=None):
         """Construct new server.
 
         :param in_file: Python file from which requests can be read.
         :param out_file: Python file to write responses.
         :param backing_transport: Transport for the directory served.
         """
-        SmartServerStreamMedium.__init__(self, backing_transport)
+        SmartServerStreamMedium.__init__(self, backing_transport,
+            timeout=timeout)
         if sys.platform == 'win32':
             # force binary mode for files
             import msvcrt

=== modified file 'bzrlib/smart/server.py'
--- a/bzrlib/smart/server.py	2011-07-23 16:33:38 +0000
+++ b/bzrlib/smart/server.py	2011-09-15 09:50:23 +0000
@@ -32,6 +32,7 @@
 lazy_import(globals(), """
 from bzrlib.smart import medium
 from bzrlib.transport import (
+    config,
     chroot,
     pathfilter,
     )
@@ -341,6 +342,8 @@
         self.transport = transport
 
     def _make_smart_server(self, host, port, inet):
+        c = config.GlobalStack()
+        timeout = c.get('server.client_timeout')
         if inet:
             smart_server = medium.SmartServerPipeStreamMedium(
                 sys.stdin, sys.stdout, self.transport)
@@ -380,7 +383,7 @@
 
 def serve_bzr(transport, host=None, port=None, inet=False):
     """This is the default implementation of 'bzr serve'.
-    
+
     It creates a TCP or pipe smart server on 'transport, and runs it.  The
     transport will be decorated with a chroot and pathfilter (using
     os.path.expanduser).

=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py	2011-09-13 17:43:21 +0000
+++ b/bzrlib/tests/__init__.py	2011-09-15 09:50:23 +0000
@@ -2734,9 +2734,7 @@
         self.__server = None
         self.reduceLockdirTimeout()
         self.overrideAttr(medium.SmartServerStreamMedium,
-                          '_stream_medium_timeout', 4.0)
-        self.overrideAttr(medium.SmartServerStreamMedium,
-                          '_stream_medium_fast_timeout', 0.1)
+                          '_DEFAULT_CLIENT_TIMEOUT', 4.0)
 
     def setup_smart_server_with_call_log(self):
         """Sets up a smart server as the transport server with a call log."""

=== modified file 'bzrlib/tests/test_smart_transport.py'
--- a/bzrlib/tests/test_smart_transport.py	2011-09-15 09:30:07 +0000
+++ b/bzrlib/tests/test_smart_transport.py	2011-09-15 09:50:23 +0000
@@ -975,10 +975,9 @@
     def test_socket_serve_timeout_closes_socket(self):
         server_sock, client_sock = self.portable_socket_pair()
         server = medium.SmartServerSocketStreamMedium(
-            server_sock, None)
+            server_sock, None, timeout=0.1)
         # This should timeout quickly, and then close the connection so that
         # client_sock recv doesn't block.
-        server._stream_medium_timeout = 0.1
         server.serve()
         self.assertEqual('', client_sock.recv(1))
 



More information about the bazaar-commits mailing list