From 6f4a82c7aff31d4fd29294a3294bcd5ad1201cd1 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sat, 21 Mar 2009 20:43:57 +0100 Subject: [PATCH] [OPTIM] stream_sock: don't retry to read after a large read If we get very large data at once, it's almost certain that it's worthless trying to read again, because we got everything we could get. Doing this has made all -EAGAIN disappear from splice reads. The threshold has been put in the global tunable structures so that if we one day want to make it accessible from user config, it will be easy to do so. --- include/common/defaults.h | 9 +++++++++ include/types/global.h | 1 + src/haproxy.c | 3 +++ src/stream_sock.c | 32 ++++++++++++++++++++------------ 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/include/common/defaults.h b/include/common/defaults.h index acba5c6ee..fb8d188bd 100644 --- a/include/common/defaults.h +++ b/include/common/defaults.h @@ -82,6 +82,15 @@ #define MAX_READ_POLL_LOOPS 4 #endif +// minimum number of bytes read at once above which we don't try to read +// more, in order not to risk facing an EAGAIN. Most often, if we read +// at least 10 kB, we can consider that the system has tried to read a +// full buffer and got multiple segments (>1 MSS for jumbo frames, >7 MSS +// for normal frames) did not bother truncating the last segment. +#ifndef MIN_RECV_AT_ONCE_ENOUGH +#define MIN_RECV_AT_ONCE_ENOUGH (7*1448) +#endif + // same, but for writes. Generally, it's enough to write twice: one time for // first half of the buffer, and a second time for the last half after a // wrap-around. diff --git a/include/types/global.h b/include/types/global.h index 0c3c8adb1..d0c22bcb4 100644 --- a/include/types/global.h +++ b/include/types/global.h @@ -77,6 +77,7 @@ struct global { int maxpollevents; /* max number of poll events at once */ int maxaccept; /* max number of consecutive accept() */ int options; /* various tuning options */ + int recv_enough; /* how many input bytes at once are "enough" */ } tune; struct listener stats_sock; /* unix socket listener for statistics */ int stats_timeout; /* in ticks */ diff --git a/src/haproxy.c b/src/haproxy.c index d5d61251b..4a9795b35 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -592,6 +592,9 @@ void init(int argc, char **argv) global.tune.maxaccept = 100; /* accept many incoming conns at once */ } + if (global.tune.recv_enough == 0) + global.tune.recv_enough = MIN_RECV_AT_ONCE_ENOUGH; + if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) { /* command line debug mode inhibits configuration mode */ global.mode &= ~(MODE_DAEMON | MODE_QUIET); diff --git a/src/stream_sock.c b/src/stream_sock.c index ed53ca08a..a942d4081 100644 --- a/src/stream_sock.c +++ b/src/stream_sock.c @@ -197,7 +197,8 @@ static int stream_sock_splice_in(struct buffer *b, struct stream_interface *si) b->flags |= BF_READ_PARTIAL; b->flags &= ~BF_EMPTY; /* to prevent shutdowns */ - if (b->pipe->data >= SPLICE_FULL_HINT) { + if (b->pipe->data >= SPLICE_FULL_HINT || + ret >= global.tune.recv_enough) { /* We've read enough of it for this time. */ retval = 1; break; @@ -400,18 +401,25 @@ int stream_sock_read(int fd) { */ if (b->flags & BF_STREAMER) break; - } - /* generally if we read something smaller than 1 or 2 MSS, - * it means that either we have exhausted the system's - * buffers (streamer or question-response protocol) or that - * the connection will be closed. Streamers are easily - * detected so we return early. For other cases, it's still - * better to perform a last read to be sure, because it may - * save one complete poll/read/wakeup cycle in case of shutdown. - */ - if (ret < MIN_RET_FOR_READ_LOOP && b->flags & BF_STREAMER) - break; + /* generally if we read something smaller than 1 or 2 MSS, + * it means that either we have exhausted the system's + * buffers (streamer or question-response protocol) or + * that the connection will be closed. Streamers are + * easily detected so we return early. For other cases, + * it's still better to perform a last read to be sure, + * because it may save one complete poll/read/wakeup cycle + * in case of shutdown. + */ + if (ret < MIN_RET_FOR_READ_LOOP && b->flags & BF_STREAMER) + break; + + /* if we read a large block smaller than what we requested, + * it's almost certain we'll never get anything more. + */ + if (ret >= global.tune.recv_enough) + break; + } if (--read_poll <= 0) break;