]> granicus.if.org Git - python/commitdiff
bpo-32410: Avoid blocking on file IO in sendfile fallback code (GH-7172)
authorYury Selivanov <yury@magic.io>
Mon, 28 May 2018 22:31:55 +0000 (18:31 -0400)
committerGitHub <noreply@github.com>
Mon, 28 May 2018 22:31:55 +0000 (18:31 -0400)
Lib/asyncio/base_events.py
Lib/asyncio/constants.py
Lib/test/test_asyncio/test_base_events.py
Lib/test/test_asyncio/test_events.py
Misc/NEWS.d/next/Library/2018-05-28-16-19-35.bpo-32410.Z1DZaF.rst [new file with mode: 0644]

index a0243f5bac9a2c37945ef1ab25bf5cefa6f8ebf1..ffd2513e33a6a07a513b80d233699734c0f6a246 100644 (file)
@@ -800,7 +800,10 @@ class BaseEventLoop(events.AbstractEventLoop):
     async def _sock_sendfile_fallback(self, sock, file, offset, count):
         if offset:
             file.seek(offset)
-        blocksize = min(count, 16384) if count else 16384
+        blocksize = (
+            min(count, constants.SENDFILE_FALLBACK_READBUFFER_SIZE)
+            if count else constants.SENDFILE_FALLBACK_READBUFFER_SIZE
+        )
         buf = bytearray(blocksize)
         total_sent = 0
         try:
@@ -810,7 +813,7 @@ class BaseEventLoop(events.AbstractEventLoop):
                     if blocksize <= 0:
                         break
                 view = memoryview(buf)[:blocksize]
-                read = file.readinto(view)
+                read = await self.run_in_executor(None, file.readinto, view)
                 if not read:
                     break  # EOF
                 await self.sock_sendall(sock, view)
index 739b0a70c13e06469fb2bdae89f2ed49599f39a4..d7ba496942896999524c370dfae9ee56a6d652a4 100644 (file)
@@ -14,6 +14,10 @@ DEBUG_STACK_DEPTH = 10
 # Number of seconds to wait for SSL handshake to complete
 SSL_HANDSHAKE_TIMEOUT = 10.0
 
+# Used in sendfile fallback code.  We use fallback for platforms
+# that don't support sendfile, or for TLS connections.
+SENDFILE_FALLBACK_READBUFFER_SIZE = 1024 * 256
+
 # The enum should be here to break circular dependencies between
 # base_events and sslproto
 class _SendfileMode(enum.Enum):
index 8566a9d5504f2b70fd3b99edc52c5cfb40675717..11e9465d392179697657fbcfe221b7f3e6849cab 100644 (file)
@@ -1818,12 +1818,15 @@ class BaseLoopSockSendfileTests(test_utils.TestCase):
 
     @classmethod
     def setUpClass(cls):
+        cls.__old_bufsize = constants.SENDFILE_FALLBACK_READBUFFER_SIZE
+        constants.SENDFILE_FALLBACK_READBUFFER_SIZE = 1024 * 16
         with open(support.TESTFN, 'wb') as fp:
             fp.write(cls.DATA)
         super().setUpClass()
 
     @classmethod
     def tearDownClass(cls):
+        constants.SENDFILE_FALLBACK_READBUFFER_SIZE = cls.__old_bufsize
         support.unlink(support.TESTFN)
         super().tearDownClass()
 
index 39d85e8df07c465eb7dc3e3d3c03409f9903db60..e7c4fa6cecec83be684fad63f2101053c1eef649 100644 (file)
@@ -2160,6 +2160,17 @@ class SockSendfileMixin(SendfileBase):
         async def wait_closed(self):
             await self.fut
 
+    @classmethod
+    def setUpClass(cls):
+        cls.__old_bufsize = constants.SENDFILE_FALLBACK_READBUFFER_SIZE
+        constants.SENDFILE_FALLBACK_READBUFFER_SIZE = 1024 * 16
+        super().setUpClass()
+
+    @classmethod
+    def tearDownClass(cls):
+        constants.SENDFILE_FALLBACK_READBUFFER_SIZE = cls.__old_bufsize
+        super().tearDownClass()
+
     def set_socket_opts(self, sock):
         # On macOS, SO_SNDBUF is reset by connect(). So this method
         # should be called after the socket is connected.
diff --git a/Misc/NEWS.d/next/Library/2018-05-28-16-19-35.bpo-32410.Z1DZaF.rst b/Misc/NEWS.d/next/Library/2018-05-28-16-19-35.bpo-32410.Z1DZaF.rst
new file mode 100644 (file)
index 0000000..2d7bb20
--- /dev/null
@@ -0,0 +1 @@
+Avoid blocking on file IO in sendfile fallback code