mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2026-05-07 22:16:10 +02:00
MINOR: mux_quic: release BE conns if reuse definitely blocked
avail_streams callback serves to indicates how many streams can be attached for a backend connection. On QUIC mux, this relies on several parameters, first based on static limitation which only decreases over time, but also on flow control which is dynamically adjusted by the peer and can be increased or decreased at will. qcc_is_dead() on the other hand serves to determine if a connection can be removed. First, it must be inactive (no request in progress). Then, if a backend connection cannot be reused due to some of the above limitation reached, it is definitely useless and should be removed as soon as possible. However, prior to this patch, qcc_is_dead() did not take into account the same set of parameters than avail_streams : only if graceful shutdown was initiated by the peer was considered. The purpose of this patch is to linked these two functions together. Reuse calcul based on static limits is extracted from avail_streams() into new qcc_be_is_reusable(). This function is used directly in qcc_is_dead(), which now for example takes into account the server max-reuse parameter. This patch should ensure that a backend connection which can not be reuse anymore is release as soon as possible. This could improve slightly reuse rate in some specific scenarii as non-reusable connections should not pollute the idle cache. Return value of QUIC avail_streams() is changed by this patch as server max-reuse and max stream ID limits are now only taken into account when already exceeded or if a single stream remains. However, this has no consequence as callers of avail_streams() do not differentiates return value of 2 or more.
This commit is contained in:
parent
e586458ec0
commit
b8961ee8b3
@ -277,6 +277,32 @@ static forceinline void qcc_rm_sc(struct qcc *qcc)
|
||||
--qcc->nb_sc;
|
||||
}
|
||||
|
||||
/* Checks if <qcc> connection can be used to attach new streams on it or if
|
||||
* reuse is definitely blocked. This is based on constant parameters such as
|
||||
* the server max-reuse limit or if the peer has requested a graceful shutdown.
|
||||
* Flow control is not taken into account here as it can be adjusted
|
||||
* dynamically over the connection lifetime.
|
||||
*
|
||||
* Returns a boolean value indicating if reuse is possible.
|
||||
*/
|
||||
static int qcc_be_is_reusable(const struct qcc *qcc)
|
||||
{
|
||||
const struct server *srv = __objt_server(qcc->conn->target);
|
||||
|
||||
/* Shutdown initiated by the peer - in HTTP/3 this corresponds to a GOAWAY frame received. */
|
||||
if (qcc->flags & QC_CF_CONN_SHUT)
|
||||
return 0;
|
||||
|
||||
if (srv->max_reuse >= 0 && qcc->tot_sc > srv->max_reuse)
|
||||
return 0;
|
||||
|
||||
/* Ensure we do not exceed the maximum usable stream ID. */
|
||||
if (qcc->next_bidi_l > QCS_ID_MAX_STRM_CL_BIDI)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int qcc_is_dead(const struct qcc *qcc)
|
||||
{
|
||||
/* Maintain connection if there is still request streams active. */
|
||||
@ -288,12 +314,12 @@ static inline int qcc_is_dead(const struct qcc *qcc)
|
||||
* - error detected locally
|
||||
* - MUX timeout expired
|
||||
* - app layer shut (FE side only - used for stream.max-total)
|
||||
* - new stream initiating definitely blocked (BE side only - used for H3 GOAWAY reception)
|
||||
* - stream attach definitely blocked (BE side only - max-reuse reached or H3 GOAWAY reception)
|
||||
*/
|
||||
if (qcc->flags & (QC_CF_ERR_CONN|QC_CF_ERRL_DONE) ||
|
||||
!qcc->task ||
|
||||
(!conn_is_back(qcc->conn) && qcc->app_st == QCC_APP_ST_SHUT) ||
|
||||
(conn_is_back(qcc->conn) && (qcc->flags & QC_CF_CONN_SHUT))) {
|
||||
(conn_is_back(qcc->conn) && !qcc_be_is_reusable(qcc))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -3271,27 +3297,23 @@ static int qcc_io_recv(struct qcc *qcc)
|
||||
*/
|
||||
static int qmux_avail_streams(struct connection *conn)
|
||||
{
|
||||
struct server *srv = __objt_server(conn->target);
|
||||
const struct server *srv = __objt_server(conn->target);
|
||||
struct qcc *qcc = conn->ctx;
|
||||
int ret, max_reuse = 0;
|
||||
int ret;
|
||||
|
||||
/* Shutdown initiated by the peer - in HTTP/3 this corresponds to a GOAWAY frame received. */
|
||||
if (qcc->flags & QC_CF_CONN_SHUT)
|
||||
if (!qcc_be_is_reusable(qcc))
|
||||
return 0;
|
||||
|
||||
ret = qcc_fctl_avail_streams(qcc, 1);
|
||||
|
||||
if (srv->max_reuse >= 0) {
|
||||
max_reuse = qcc->tot_sc <= srv->max_reuse ?
|
||||
srv->max_reuse - qcc->tot_sc + 1: 0;
|
||||
ret = MIN(ret, max_reuse);
|
||||
}
|
||||
|
||||
/* Do not exceed maximum usable stream ID. To simplify the calcul,
|
||||
* limit is only applied when one or zero stream remains.
|
||||
/* Now cap return value if reaching max-reuse server or maximum stream
|
||||
* ID. qcc_be_is_reusable() already detected if one of these has been
|
||||
* exceeded.
|
||||
*/
|
||||
if (ret && unlikely(qcc->next_bidi_l >= QCS_ID_MAX_STRM_CL_BIDI))
|
||||
ret = qcc->next_bidi_l == QCS_ID_MAX_STRM_CL_BIDI ? 1 : 0;
|
||||
if (ret > 1 && srv->max_reuse >= 0 && qcc->tot_sc == srv->max_reuse)
|
||||
ret = 1;
|
||||
else if (ret > 1 && unlikely(qcc->next_bidi_l == QCS_ID_MAX_STRM_CL_BIDI))
|
||||
ret = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user