Skip to content

Commit 86af5a6

Browse files
a-denoyellehaproxyFred
authored andcommitted
MEDIUM: mux-quic: allow to only release one buffer
Previous commit relaxed conditions for QUIC MUX Tx buffer allocation. This was necessary to prevent slow throughput when a standalone stream could only allocate a single buffer. Now, when a buffer is released, it is removed from connection buffer window, thus allowing a new allocation. However, this virtually allows a QCS to allocate many buffers without any limit. To fix this, add a limit on the number of released buffer that a QCS may have. Once this limit is reached, qcc_release_stream_txbuf() operation will return an error, flagging QCS with QC_SF_BLK_MROOM. Each time an already released buffer is freed after ACK reception, new qcs_notify_buf() is called by qc_stream_desc layer to wakeup the QCS stream if currently blocked. The limit is configured via a define QMUX_MAX_QCS_TXBUF_RELEASED. It is set to 1 by default. This value is low enough to guarantee minimal memory consumption for a QUIC connection while preserving transfer throughput. Thus, the new buffer allocation limit is now : qc_window_size + (1 * nb_streams)
1 parent e06e3b7 commit 86af5a6

File tree

5 files changed

+42
-12
lines changed

5 files changed

+42
-12
lines changed

include/haproxy/mux_quic-t.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
#include <haproxy/stconn-t.h>
2020
#include <haproxy/time-t.h>
2121

22+
/* Maximim number of released buffer a QCS may have. */
23+
#define QMUX_MAX_QCS_TXBUF_RELEASED 1
24+
2225
/* Stream types */
2326
enum qcs_type {
2427
QCS_CLT_BIDI,
@@ -140,6 +143,7 @@ struct qcs {
140143
} rx;
141144
struct {
142145
struct quic_fctl fc; /* stream flow control applied on sending */
146+
int buf_released; /* count of released buffer waiting for ACK */
143147
} tx;
144148

145149
struct eb64_node by_id;

include/haproxy/mux_quic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ int qcs_is_close_remote(struct qcs *qcs);
2323
int qcs_subscribe(struct qcs *qcs, int event_type, struct wait_event *es);
2424
void qcs_notify_recv(struct qcs *qcs);
2525
void qcs_notify_send(struct qcs *qcs);
26+
void qcs_notify_buf(struct qcs *qcs);
2627
void qcc_notify_buf(struct qcc *qcc, uint64_t free_size);
2728

2829
struct buffer *qcc_get_stream_rxbuf(struct qcs *qcs);

src/mux_quic.c

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ static struct qcs *qcs_new(struct qcc *qcc, uint64_t id, enum qcs_type type)
134134
qfctl_init(&qcs->tx.fc, 0);
135135
}
136136

137+
qcs->tx.buf_released = 0;
138+
137139
qcs->rx.ncbuf = NCBUF_NULL;
138140
qcs->rx.app_buf = BUF_NULL;
139141
qcs->rx.offset = qcs->rx.offset_max = 0;
@@ -524,6 +526,22 @@ void qcs_notify_send(struct qcs *qcs)
524526
}
525527
}
526528

529+
/* Report that a released buffer from <qcs> have been freed. A released buffer
530+
* is already removed from QCC buffer window. However, <qcs> stream emission
531+
* may also be blocked as it could not release anymore buffer.
532+
*
533+
* Noop if <qcs> is NULL.
534+
*/
535+
void qcs_notify_buf(struct qcs *qcs)
536+
{
537+
if (qcs) {
538+
BUG_ON(!qcs->tx.buf_released);
539+
--qcs->tx.buf_released;
540+
qcs_notify_send(qcs);
541+
qcs->flags &= ~QC_SF_BLK_MROOM;
542+
}
543+
}
544+
527545
/* Returns true if <qcc> buffer window does not have room for a new buffer. */
528546
static inline int qcc_bufwnd_full(const struct qcc *qcc)
529547
{
@@ -1159,17 +1177,20 @@ int qcc_realign_stream_txbuf(const struct qcs *qcs, struct buffer *out)
11591177
int qcc_release_stream_txbuf(struct qcs *qcs)
11601178
{
11611179
struct buffer *buf = qc_stream_buf_get(qcs->stream);
1162-
const uint64_t bytes = qcs_prep_bytes(qcs);
11631180

1164-
/* Cannot release buffer if prepared data is not fully sent. */
1165-
if (bytes) {
1181+
/* Cannot release buffer if prepared data is not fully sent or already
1182+
* reached the maximum number of released buffer for this stream.
1183+
*/
1184+
if (qcs_prep_bytes(qcs) ||
1185+
qcs->tx.buf_released >= QMUX_MAX_QCS_TXBUF_RELEASED) {
11661186
qcs->flags |= QC_SF_BLK_MROOM;
11671187
return 1;
11681188
}
11691189

11701190
/* Free released buf size from buf window. */
11711191
qc_stream_buf_release(qcs->stream);
11721192
qcc_notify_buf(qcs->qcc, b_size(buf));
1193+
++qcs->tx.buf_released;
11731194

11741195
return 0;
11751196
}
@@ -1977,11 +1998,11 @@ void qcc_streams_sent_done(struct qcs *qcs, uint64_t data, uint64_t offset)
19771998
QMUX_EV_QCS_SEND, qcc->conn, qcs);
19781999
}
19792000
/* Release buffer if everything sent and buf is full or stream is waiting for room. */
1980-
if (!qcs_prep_bytes(qcs) &&
1981-
(b_full(&qcs->stream->buf->buf) || qcs->flags & QC_SF_BLK_MROOM)) {
1982-
qcc_release_stream_txbuf(qcs);
1983-
qcs->flags &= ~QC_SF_BLK_MROOM;
1984-
qcs_notify_send(qcs);
2001+
if ((b_full(&qcs->stream->buf->buf) || qcs->flags & QC_SF_BLK_MROOM)) {
2002+
if (!qcc_release_stream_txbuf(qcs)) {
2003+
qcs_notify_send(qcs);
2004+
qcs->flags &= ~QC_SF_BLK_MROOM;
2005+
}
19852006
}
19862007

19872008
/* Add measurement for send rate. This is done at the MUX layer
@@ -3419,7 +3440,7 @@ void qcc_show_quic(struct qcc *qcc)
34193440
if (!quic_stream_is_uni(qcs->id) || !quic_stream_is_local(qcc, qcs->id))
34203441
chunk_appendf(&trash, " rxoff=%llu", (ullong)qcs->rx.offset);
34213442
if (!quic_stream_is_uni(qcs->id) || !quic_stream_is_remote(qcc, qcs->id))
3422-
chunk_appendf(&trash, " txoff=%llu", (ullong)qcs->tx.fc.off_real);
3443+
chunk_appendf(&trash, " txoff=%llu br=%d", (ullong)qcs->tx.fc.off_real, qcs->tx.buf_released);
34233444
chunk_appendf(&trash, "\n");
34243445
node = eb64_next(node);
34253446
}

src/qmux_trace.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,9 @@ void qmux_dump_qcs_info(struct buffer *msg, const struct qcs *qcs)
150150
qcs_st_to_str(qcs->st), qcs->flags);
151151

152152
chunk_appendf(msg, " .rx=%llu/%llu", (ullong)qcs->rx.offset_max, (ullong)qcs->rx.msd);
153-
chunk_appendf(msg, " .tx=%llu %llu/%llu", (ullong)qcs->tx.fc.off_soft,
154-
(ullong)qcs->tx.fc.off_real,
155-
(ullong)qcs->tx.fc.limit);
153+
chunk_appendf(msg, " .tx=%llu %llu/%llu br=%d",
154+
(ullong)qcs->tx.fc.off_soft, (ullong)qcs->tx.fc.off_real,
155+
(ullong)qcs->tx.fc.limit, qcs->tx.buf_released);
156156

157157
chunk_appendf(msg, " .ti=%u/%u/%u",
158158
tot_time_read(&qcs->timer.base),

src/quic_stream.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ static void qc_stream_buf_free(struct qc_stream_desc *stream,
4545
}
4646
}
4747
}
48+
else {
49+
/* Notify about a freed released buffer. */
50+
qcs_notify_buf(stream->ctx);
51+
}
4852

4953
if ((*stream_buf)->sbuf) {
5054
pool_free(pool_head_sbuf, buf->area);

0 commit comments

Comments
 (0)