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;