mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-22 22:31:28 +02:00
MEDIUM: checks: make tcp-check perform multiple send() at once
Now instead of seeing many send() calls from multiple "tcp-check send" rules, we fill the output buffer and try to send all only when we're not in a send state or when the output buffer is too small for sending the next message. This results in a lot less syscalls and avoids filling the network with many small packets. It will also improve the behaviour of some bogus servers which expect a complete request in the first packet.
This commit is contained in:
parent
98aec9ff47
commit
fbe0edf057
87
src/checks.c
87
src/checks.c
@ -1953,9 +1953,6 @@ static void tcpcheck_main(struct connection *conn)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* It's only the rules which will enable send/recv */
|
|
||||||
__conn_data_stop_both(conn);
|
|
||||||
|
|
||||||
/* here, we know that the connection is established */
|
/* here, we know that the connection is established */
|
||||||
if (check->result & (SRV_CHK_FAILED | SRV_CHK_PASSED)) {
|
if (check->result & (SRV_CHK_FAILED | SRV_CHK_PASSED)) {
|
||||||
goto out_end_tcpcheck;
|
goto out_end_tcpcheck;
|
||||||
@ -1981,22 +1978,38 @@ static void tcpcheck_main(struct connection *conn)
|
|||||||
cur = check->current_step;
|
cur = check->current_step;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (conn->flags & CO_FL_HANDSHAKE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* It's only the rules which will enable send/recv */
|
||||||
|
__conn_data_stop_both(conn);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
/* we must always ensure that nothing remains in the output buffer */
|
/* we have to try to flush the output buffer before reading, at the end,
|
||||||
while (check->bo->o) {
|
* or if we're about to send a string that does not fit in the remaining space.
|
||||||
conn->xprt->snd_buf(conn, check->bo, MSG_DONTWAIT | MSG_NOSIGNAL);
|
*/
|
||||||
if (conn->flags & CO_FL_ERROR) {
|
if (check->bo->o &&
|
||||||
chk_report_conn_err(conn, errno, 0);
|
(&cur->list == head ||
|
||||||
__conn_data_stop_both(conn);
|
check->current_step->action != TCPCHK_ACT_SEND ||
|
||||||
goto out_end_tcpcheck;
|
check->current_step->string_len >= buffer_total_space(check->bo))) {
|
||||||
|
|
||||||
|
if ((conn->flags & CO_FL_WAIT_WR) ||
|
||||||
|
conn->xprt->snd_buf(conn, check->bo, MSG_DONTWAIT | MSG_NOSIGNAL) <= 0) {
|
||||||
|
if (conn->flags & CO_FL_ERROR) {
|
||||||
|
chk_report_conn_err(conn, errno, 0);
|
||||||
|
__conn_data_stop_both(conn);
|
||||||
|
goto out_end_tcpcheck;
|
||||||
|
}
|
||||||
|
goto out_need_io;
|
||||||
}
|
}
|
||||||
if (conn->flags & CO_FL_WAIT_WR)
|
|
||||||
goto out_incomplete;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* did we reach the end ? */
|
/* did we reach the end ? If so, let's check that everything was sent */
|
||||||
if (&cur->list == head)
|
if (&cur->list == head) {
|
||||||
|
if (check->bo->o)
|
||||||
|
goto out_need_io;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (check->current_step->action == TCPCHK_ACT_SEND) {
|
if (check->current_step->action == TCPCHK_ACT_SEND) {
|
||||||
/* reset the read buffer */
|
/* reset the read buffer */
|
||||||
@ -2011,9 +2024,6 @@ static void tcpcheck_main(struct connection *conn)
|
|||||||
goto out_end_tcpcheck;
|
goto out_end_tcpcheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn->flags & (CO_FL_HANDSHAKE | CO_FL_WAIT_WR))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (check->current_step->string_len >= check->bo->size) {
|
if (check->current_step->string_len >= check->bo->size) {
|
||||||
chunk_printf(&trash, "tcp-check send : string too large (%d) for buffer size (%d) at step %d",
|
chunk_printf(&trash, "tcp-check send : string too large (%d) for buffer size (%d) at step %d",
|
||||||
check->current_step->string_len, check->bo->size,
|
check->current_step->string_len, check->bo->size,
|
||||||
@ -2022,6 +2032,10 @@ static void tcpcheck_main(struct connection *conn)
|
|||||||
goto out_end_tcpcheck;
|
goto out_end_tcpcheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* do not try to send if there is no space */
|
||||||
|
if (check->current_step->string_len >= buffer_total_space(check->bo))
|
||||||
|
continue;
|
||||||
|
|
||||||
bo_putblk(check->bo, check->current_step->string, check->current_step->string_len);
|
bo_putblk(check->bo, check->current_step->string, check->current_step->string_len);
|
||||||
*check->bo->p = '\0'; /* to make gdb output easier to read */
|
*check->bo->p = '\0'; /* to make gdb output easier to read */
|
||||||
|
|
||||||
@ -2033,22 +2047,22 @@ static void tcpcheck_main(struct connection *conn)
|
|||||||
if (unlikely(check->result & SRV_CHK_FAILED))
|
if (unlikely(check->result & SRV_CHK_FAILED))
|
||||||
goto out_end_tcpcheck;
|
goto out_end_tcpcheck;
|
||||||
|
|
||||||
if (conn->flags & (CO_FL_HANDSHAKE | CO_FL_WAIT_RD))
|
if ((conn->flags & CO_FL_WAIT_RD) ||
|
||||||
return;
|
conn->xprt->rcv_buf(conn, check->bi, buffer_total_space(check->bi)) <= 0) {
|
||||||
|
if (conn->flags & (CO_FL_ERROR | CO_FL_SOCK_RD_SH | CO_FL_DATA_RD_SH)) {
|
||||||
conn->xprt->rcv_buf(conn, check->bi, buffer_total_space(check->bi));
|
done = 1;
|
||||||
|
if ((conn->flags & CO_FL_ERROR) && !check->bi->i) {
|
||||||
if (conn->flags & (CO_FL_ERROR | CO_FL_SOCK_RD_SH | CO_FL_DATA_RD_SH)) {
|
/* Report network errors only if we got no other data. Otherwise
|
||||||
done = 1;
|
* we'll let the upper layers decide whether the response is OK
|
||||||
if ((conn->flags & CO_FL_ERROR) && !check->bi->i) {
|
* or not. It is very common that an RST sent by the server is
|
||||||
/* Report network errors only if we got no other data. Otherwise
|
* reported as an error just after the last data chunk.
|
||||||
* we'll let the upper layers decide whether the response is OK
|
*/
|
||||||
* or not. It is very common that an RST sent by the server is
|
chk_report_conn_err(conn, errno, 0);
|
||||||
* reported as an error just after the last data chunk.
|
goto out_end_tcpcheck;
|
||||||
*/
|
}
|
||||||
chk_report_conn_err(conn, errno, 0);
|
|
||||||
goto out_end_tcpcheck;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
goto out_need_io;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Intermediate or complete response received.
|
/* Intermediate or complete response received.
|
||||||
@ -2068,7 +2082,7 @@ static void tcpcheck_main(struct connection *conn)
|
|||||||
/* Check that response body is not empty... */
|
/* Check that response body is not empty... */
|
||||||
if (*contentptr == '\0') {
|
if (*contentptr == '\0') {
|
||||||
if (!done)
|
if (!done)
|
||||||
return;
|
continue;
|
||||||
|
|
||||||
/* empty response */
|
/* empty response */
|
||||||
chunk_printf(&trash, "TCPCHK got an empty response at step %d",
|
chunk_printf(&trash, "TCPCHK got an empty response at step %d",
|
||||||
@ -2148,7 +2162,12 @@ static void tcpcheck_main(struct connection *conn)
|
|||||||
set_server_check_status(check, HCHK_STATUS_L7OKD, "(tcp-check)");
|
set_server_check_status(check, HCHK_STATUS_L7OKD, "(tcp-check)");
|
||||||
goto out_end_tcpcheck;
|
goto out_end_tcpcheck;
|
||||||
|
|
||||||
out_incomplete:
|
out_need_io:
|
||||||
|
if (check->bo->o)
|
||||||
|
__conn_data_want_send(conn);
|
||||||
|
|
||||||
|
if (check->current_step->action == TCPCHK_ACT_EXPECT)
|
||||||
|
__conn_data_want_recv(conn);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
out_end_tcpcheck:
|
out_end_tcpcheck:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user