From c8f1d11e803179f5df932365585d924ebbbac5ad Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 21 May 2015 14:19:09 +0530 Subject: [PATCH] Use TCP_CORK to improve throughput for large file transfers --- src/calibre/srv/http.py | 10 +++++----- src/calibre/srv/loop.py | 3 ++- src/calibre/srv/utils.py | 15 ++++++++++++++- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/calibre/srv/http.py b/src/calibre/srv/http.py index e10f4f7665..3e2a5bebcc 100644 --- a/src/calibre/srv/http.py +++ b/src/calibre/srv/http.py @@ -553,11 +553,11 @@ class HTTPPair(object): self.simple_response(httplib.PRECONDITION_FAILED) return - self.send_headers() - - if self.method != 'HEAD': - output.commit(self.conn.socket_file) - self.conn.socket_file.flush() + with self.conn.corked: + self.send_headers() + if self.method != 'HEAD': + output.commit(self.conn.socket_file) + self.conn.socket_file.flush() def send_headers(self): self.sent_headers = True diff --git a/src/calibre/srv/loop.py b/src/calibre/srv/loop.py index 6ea9983837..d3971d4a69 100644 --- a/src/calibre/srv/loop.py +++ b/src/calibre/srv/loop.py @@ -15,7 +15,7 @@ from io import DEFAULT_BUFFER_SIZE, BytesIO from calibre.srv.errors import NonHTTPConnRequest, MaxSizeExceeded from calibre.srv.http import http_communicate from calibre.srv.opts import Options -from calibre.srv.utils import socket_errors_to_ignore, socket_error_eintr, socket_errors_nonblocking +from calibre.srv.utils import socket_errors_to_ignore, socket_error_eintr, socket_errors_nonblocking, Corked from calibre.utils.socket_inheritance import set_socket_inherit from calibre.utils.logging import ThreadSafeLog @@ -330,6 +330,7 @@ class Connection(object): # {{{ def __init__(self, server_loop, socket): self.server_loop = server_loop self.socket = socket + self.corked = Corked(socket) self.socket_file = SocketFile(socket) def nonhttp_communicate(self, data): diff --git a/src/calibre/srv/utils.py b/src/calibre/srv/utils.py index 3a61cacf3b..5e984e7bbf 100644 --- a/src/calibre/srv/utils.py +++ b/src/calibre/srv/utils.py @@ -6,7 +6,7 @@ from __future__ import (unicode_literals, division, absolute_import, __license__ = 'GPL v3' __copyright__ = '2015, Kovid Goyal ' -import errno +import errno, socket from urlparse import parse_qs import repr as reprlib from email.utils import formatdate @@ -107,4 +107,17 @@ socket_errors_to_ignore = error_codes( # errors indicating a closed connection socket_errors_nonblocking = error_codes( 'EAGAIN', 'EWOULDBLOCK', 'WSAEWOULDBLOCK') +class Corked(object): + ' Context manager to turn on TCP corking. Ensures maximum throughput for large logical packets. ' + + def __init__(self, sock): + self.sock = sock if hasattr(socket, 'TCP_CORK') else None + + def __enter__(self): + if self.sock is not None: + self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_CORK, 1) + + def __exit__(self, *args): + if self.sock is not None: + self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_CORK, 0)