From: Willy Tarreau Date: Sat, 21 Mar 2009 19:43:57 +0000 (+0100) Subject: [OPTIM] stream_sock: don't retry to read after a large read X-Git-Tag: v1.3.16~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6f4a82c7aff31d4fd29294a3294bcd5ad1201cd1;p=thirdparty%2Fhaproxy.git [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. --- diff --git a/include/common/defaults.h b/include/common/defaults.h index acba5c6eed..fb8d188bd2 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 0c3c8adb1b..d0c22bcb45 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 d5d61251b7..4a9795b357 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 ed53ca08af..a942d40817 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;