MEDIUM: mux-quic: increase flow-control on each bufsize

Recently, QCS Rx allocation buffer method has been improved. It is now
possible to allocate multiple buffers per QCS instances, which was
necessary to improve HTTP/3 POST throughput.

However, a limitation remained related to the emission of
MAX_STREAM_DATA. These frames are only emitted once at least half of the
receive capacity has been consumed by its QCS instance. This may be too
restrictive when a client need to upload a large payload.

Improve this by adjusting MAX_STREAM_DATA allocation. If QCS capacity is
still limited to 1 or 2 buffers max, the old calcul is still used. This
is necessary when user has limited upload throughput via their
configuration. If QCS capacity is more than 2 buffers, a new frame is
emitted if at least a buffer was consumed.

This patch has reduced number of STREAM_DATA_BLOCKED frames received in
POST tests with some specific clients.
This commit is contained in:
Amaury Denoyelle 2025-03-19 16:09:08 +01:00
parent 2ccfebcebf
commit 14a3fb679f
2 changed files with 23 additions and 4 deletions

View File

@ -156,7 +156,7 @@ struct qcs {
struct eb_root bufs; /* receive buffers tree ordered by offset */
struct buffer app_buf; /* receive buffer used by stconn layer */
uint64_t msd; /* current max-stream-data limit to enforce */
uint64_t msd_init; /* initial max-stream-data */
uint64_t msd_base; /* max-stream-data previous to latest update */
} rx;
struct {
struct quic_fctl fc; /* stream flow control applied on sending */

View File

@ -173,7 +173,7 @@ static struct qcs *qcs_new(struct qcc *qcc, uint64_t id, enum qcs_type type)
else if (quic_stream_is_remote(qcc, id)) {
qcs->rx.msd = qcc->lfctl.msd_uni_r;
}
qcs->rx.msd_init = qcs->rx.msd;
qcs->rx.msd_base = 0;
qcs->wait_event.tasklet = NULL;
qcs->wait_event.events = 0;
@ -1198,6 +1198,7 @@ static void qcs_consume(struct qcs *qcs, uint64_t bytes, struct qc_stream_rxbuf
struct qcc *qcc = qcs->qcc;
struct quic_frame *frm;
enum ncb_ret ret;
uint64_t diff, inc = 0;
TRACE_ENTER(QMUX_EV_QCS_RECV, qcc->conn, qcs);
@ -1218,7 +1219,24 @@ static void qcs_consume(struct qcs *qcs, uint64_t bytes, struct qc_stream_rxbuf
if (qcs->flags & QC_SF_SIZE_KNOWN)
goto conn_fctl;
if (qcs->rx.msd - qcs->rx.offset < qcs->rx.msd_init / 2) {
/* Check if a MAX_STREAM_DATA frame should be emitted, determined by
* the consumed capacity. If no more than 2 Rx buffers can be allocated
* per QCS, the limit is set to half the capacity. Else, the limit is
* set to match bufsize.
*/
if (qcs->rx.msd - qcs->rx.msd_base < qmux_stream_rx_bufsz() * 2) {
if ((qcs->rx.offset - qcs->rx.msd_base) * 2 >= qcs->rx.msd - qcs->rx.msd_base)
inc = qcs->rx.offset - qcs->rx.msd_base;
}
else {
diff = qcs->rx.offset - qcs->rx.msd_base;
while (diff >= qmux_stream_rx_bufsz()) {
inc += qmux_stream_rx_bufsz();
diff -= qmux_stream_rx_bufsz();
}
}
if (inc) {
TRACE_DATA("increase stream credit via MAX_STREAM_DATA", QMUX_EV_QCS_RECV, qcc->conn, qcs);
frm = qc_frm_alloc(QUIC_FT_MAX_STREAM_DATA);
if (!frm) {
@ -1226,7 +1244,8 @@ static void qcs_consume(struct qcs *qcs, uint64_t bytes, struct qc_stream_rxbuf
return;
}
qcs->rx.msd = qcs->rx.offset + qcs->rx.msd_init;
qcs->rx.msd += inc;
qcs->rx.msd_base += inc;
frm->max_stream_data.id = qcs->id;
frm->max_stream_data.max_stream_data = qcs->rx.msd;