]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: mux-quic: increase flow-control on each bufsize
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 19 Mar 2025 15:09:08 +0000 (16:09 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 30 Apr 2025 14:08:47 +0000 (16:08 +0200)
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.

include/haproxy/mux_quic-t.h
src/mux_quic.c

index d87e2fecde6648857032a7dab946324d85426aa9..46f671329e84f56c20998510fc4e24d0cbdb7e5a 100644 (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 */
index 89b24a573f881c0706c06de8338dcc3e411282f1..329477413f8a22071772aa359c7971571fd5cdaf 100644 (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;