OPTIM: ssl: implement dynamic record size adjustment
By having the stream interface pass the CF_STREAMER flag to the
snd_buf() primitive, we're able to tell the send layer whether
we're sending large chunks or small ones.
We use this information in SSL to adjust the max record dynamically.
This results in small chunks respecting tune.ssl.maxrecord at the
beginning of a transfer or for small transfers, with an automatic
switch to full records if the exchanges last long. This allows the
receiver to parse HTML contents on the fly without having to retrieve
16kB of data, which is even more important with small initcwnd since
the receiver does not need to wait for round trips to start fetching
new objects. However, sending large files still produces large chunks.
For example, with tune.ssl.maxrecord = 2859, we see 5 write(2885)
sent in two segments each and 6 write(16421).
This idea was first proposed on the haproxy mailing list by Ilya Grigorik.
diff --git a/include/types/connection.h b/include/types/connection.h
index f8e526a..5341a86 100644
--- a/include/types/connection.h
+++ b/include/types/connection.h
@@ -180,6 +180,7 @@
/* flags that can be passed to xprt->snd_buf() */
enum {
CO_SFL_MSG_MORE = 0x0001, /* More data to come afterwards */
+ CO_SFL_STREAMER = 0x0002, /* Producer is continuously streaming data */
};
/* xprt_ops describes transport-layer operations for a connection. They
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 19505e5..5ac2b06 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -1528,7 +1528,8 @@
while (buf->o) {
try = bo_contig_data(buf);
- if (global.tune.ssl_max_record && try > global.tune.ssl_max_record)
+ if (!(flags & CO_SFL_STREAMER) &&
+ global.tune.ssl_max_record && try > global.tune.ssl_max_record)
try = global.tune.ssl_max_record;
ret = SSL_write(conn->xprt_ctx, bo_ptr(buf), try);
diff --git a/src/stream_interface.c b/src/stream_interface.c
index 967f645..b3364a3 100644
--- a/src/stream_interface.c
+++ b/src/stream_interface.c
@@ -701,6 +701,9 @@
((chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) == CF_SHUTW_NOW))
send_flag |= CO_SFL_MSG_MORE;
+ if (chn->flags & CF_STREAMER)
+ send_flag |= CO_SFL_STREAMER;
+
ret = conn->xprt->snd_buf(conn, chn->buf, send_flag);
if (ret > 0) {
chn->flags |= CF_WRITE_PARTIAL;