Skip to content

Commit e139dd9

Browse files
committed
MAJOR: mux_quic: support stream elasticity during connection lifetime
qcc_release_remote_stream() is called each time a remote stream is closed. Flow control accounting is updated and when necessary, a MAX_STREAMS_BIDI frame is prepared to allow the peer to initiate new streams. This patch extends stream elasticity features with the QUIC bidirection stream flow control mechanism. The announced value can now be possibly reduced depending on conn_calc_max_streams(). The first step is to decrement closed streams from the global committed extra streams total. This must be performed conn_calc_max_streams() to ensure the calculation will be valid. Then, there is two cases depending on conn_calc_max_streams() result. If the value is less than the peer still remaining stream window, nothing more is performed. If the opposite case, flow control must be increased and a MAX_STREAMS_BIDI frame is prepared, with the value adjusted to not exceed the stream elasticity limit. Global extra streams total is then finally incremented. This calcul also ensures that when all streams are closed, global extra streams accounting operations are decremented by 1, as a connection always has access to one stream which is excluded from the global total. Note that if stream elasticity is not active, flow control increases principle is unchanged and remains statically performed. This patch is labelled as major as it complexifies bidirectional stream flow control mechanisme. This is a sensitive operation as there is a risk of connection freeze if flow control updates are inadvertently skipped.
1 parent 89f3975 commit e139dd9

2 files changed

Lines changed: 46 additions & 6 deletions

File tree

doc/configuration.txt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5727,9 +5727,15 @@ tune.streams-elasticity <number>
57275727
use lower values (120 to 200) to support 1.2 to 2 streams per connection on
57285728
average at full load.
57295729

5730-
There is a limitation for QUIC listeners with enabled 0-RTT. In this case,
5731-
the initial value advertised to the peer will ignore stream elasticity and
5732-
instead rely solely on the "tune.quic.stream.max-concurrent" setting.
5730+
Contrary to HTTP/2, QUIC is capable to dynamically adjust the number of
5731+
concurrent streams during the connection lifetime. However, QUIC flow control
5732+
is stricter than HTTP/2, thus it is preferable when using it to specify
5733+
values big enough to prevent extra latency on the connection. There is also a
5734+
limitation for QUIC listeners with enabled 0-RTT. In this case, the initial
5735+
value advertised to the peer will ignore stream elasticity and instead rely
5736+
solely on the "tune.quic.stream.max-concurrent" setting. However, the stream
5737+
elasticity principle will still be effective past this initial annoucement
5738+
during the connection lifetime.
57335739

57345740
Monitoring the total number of active streams on backends, including queues,
57355741
provides a practical indicator of a sustainable target load and helps avoid

src/mux_quic.c

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2467,6 +2467,7 @@ int qcc_recv_stop_sending(struct qcc *qcc, uint64_t id, uint64_t err)
24672467
static int qcc_release_remote_stream(struct qcc *qcc, uint64_t id)
24682468
{
24692469
struct quic_frame *frm;
2470+
uint64_t conn_max, rem, non_extra, inc;
24702471

24712472
TRACE_ENTER(QMUX_EV_QCS_END, qcc->conn);
24722473

@@ -2485,6 +2486,40 @@ static int qcc_release_remote_stream(struct qcc *qcc, uint64_t id)
24852486
*/
24862487
if (qcc->lfctl.cl_bidi_r > qcc->lfctl.ms_bidi_rel / 2 ||
24872488
qcc->lfctl.cl_bidi_r + qcc->lfctl.ms_bidi == max) {
2489+
2490+
BUG_ON(qcc->lfctl.ms_bidi_rel < qcc->lfctl.cl_bidi_r);
2491+
rem = qcc->lfctl.ms_bidi_rel - qcc->lfctl.cl_bidi_r;
2492+
/* if every streams are closed, decrement extra stream accounting by 1 */
2493+
non_extra = !rem ? 1 : 0;
2494+
2495+
if (!(qcc->flags & QC_CF_IS_BACK) && global.tune.streams_elasticity) {
2496+
/* If stream elasticity is active, first decrement closed from extra streams. */
2497+
if (qcc->lfctl.ms_bidi_rel > 1) {
2498+
_HA_ATOMIC_SUB(&tg_ctx->committed_extra_streams,
2499+
qcc->lfctl.cl_bidi_r - non_extra);
2500+
}
2501+
2502+
/* Now calculate the available streams. */
2503+
conn_max = conn_calc_max_streams(qcc->lfctl.ms_bidi_init);
2504+
if (conn_max <= rem) {
2505+
/* More streams already consumed than currently allowed,
2506+
* keep the current flow control limit.
2507+
*/
2508+
qcc->lfctl.ms_bidi_rel = rem;
2509+
qcc->lfctl.cl_bidi_r = 0;
2510+
goto out;
2511+
}
2512+
2513+
/* Update flow control limit up to the allowed elasticity limit. */
2514+
inc = conn_max - rem;
2515+
_HA_ATOMIC_ADD(&tg_ctx->committed_extra_streams, inc - non_extra);
2516+
qcc->lfctl.ms_bidi_rel = rem + inc;
2517+
}
2518+
else {
2519+
/* Stream elasticity not active, flow control increase remains static. */
2520+
inc = qcc->lfctl.cl_bidi_r;
2521+
}
2522+
24882523
TRACE_DATA("increase max stream limit with MAX_STREAMS_BIDI", QMUX_EV_QCC_SEND, qcc->conn);
24892524
frm = qc_frm_alloc(QUIC_FT_MAX_STREAMS_BIDI);
24902525
if (!frm) {
@@ -2493,12 +2528,11 @@ static int qcc_release_remote_stream(struct qcc *qcc, uint64_t id)
24932528
goto err;
24942529
}
24952530

2496-
frm->max_streams_bidi.max_streams = qcc->lfctl.ms_bidi +
2497-
qcc->lfctl.cl_bidi_r;
2531+
frm->max_streams_bidi.max_streams = qcc->lfctl.ms_bidi + inc;
24982532
LIST_APPEND(&qcc->lfctl.frms, &frm->list);
24992533
tasklet_wakeup(qcc->wait_event.tasklet);
25002534

2501-
qcc->lfctl.ms_bidi += qcc->lfctl.cl_bidi_r;
2535+
qcc->lfctl.ms_bidi += inc;
25022536
qcc->lfctl.cl_bidi_r = 0;
25032537
}
25042538
}

0 commit comments

Comments
 (0)