From: Amaury Denoyelle Date: Fri, 6 Jan 2023 16:16:47 +0000 (+0100) Subject: MINOR: mux-quic: use send-list for immediate sending retry X-Git-Tag: v2.8-dev2~62 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a9de7ea1dc3bbc627ae3ab82de9e012d10ed7ffb;p=thirdparty%2Fhaproxy.git MINOR: mux-quic: use send-list for immediate sending retry Sending is done with several iterations over qcs streams in qc_send(). The first loop is conducted over streams in . After this first iteration, some streams may still have data in their Tx buffer but were blocked by a full qc_stream_desc buffer. In this case, they have release their qc_stream_desc buffer in qcc_streams_sent_done(). New iterations can be done for these streams which can allocate new qc_stream_desc buffer if available. Before this patch, this was done through another stream list . Now, we can reuse the new for this usage. This is safe to use as after first iteration, we have guarantee that either one of the following is true if there is still streams in : * transport layer has rejected data due to congestion * stream is left because it is blocked on stream flow control * stream still has data and has released a fulfilled qc_stream_desc buffer. Immediate retry is useful for these streams : they will allocate a new qc_stream_desc buffer if possible to continue sending. This must be backported up to 2.7. --- diff --git a/src/mux_quic.c b/src/mux_quic.c index 195ba9f2a8..71aae7165c 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -1499,12 +1499,10 @@ void qcc_streams_sent_done(struct qcs *qcs, uint64_t data, uint64_t offset) TRACE_STATE("stream flow-control reached", QMUX_EV_QCS_SEND, qcc->conn, qcs); } + /* If qcs.stream.buf is full, release it to the lower layer. */ if (qcs->tx.offset == qcs->tx.sent_offset && b_full(&qcs->stream->buf->buf)) { qc_stream_buf_release(qcs->stream); - /* prepare qcs for immediate send retry if data to send */ - if (b_data(&qcs->tx.buf)) - LIST_APPEND(&qcc->send_retry_list, &qcs->el); } } @@ -1539,8 +1537,6 @@ static int qc_send_frames(struct qcc *qcc, struct list *frms) goto err; } - LIST_INIT(&qcc->send_retry_list); - if (!qc_send_mux(qcc->conn->handle.qc, frms)) goto err; @@ -1725,7 +1721,7 @@ static int qc_send(struct qcc *qcc) { struct list frms = LIST_HEAD_INIT(frms); struct qcs *qcs, *qcs_tmp; - int total = 0, tmp_total = 0; + int total = 0; TRACE_ENTER(QMUX_EV_QCC_SEND, qcc->conn); @@ -1797,27 +1793,25 @@ static int qc_send(struct qcc *qcc) total += _qc_send_qcs(qcs, &frms); } - if (qc_send_frames(qcc, &frms)) { - /* data rejected by transport layer, do not retry. */ - goto out; - } - - retry: - tmp_total = 0; - list_for_each_entry_safe(qcs, qcs_tmp, &qcc->send_retry_list, el) { - int ret; - BUG_ON(!b_data(&qcs->tx.buf)); - BUG_ON(qc_stream_buf_get(qcs->stream)); + /* Retry sending until no frame to send, data rejected or connection + * flow-control limit reached. + */ + while (qc_send_frames(qcc, &frms) == 0 && !(qcc->flags & QC_CF_BLK_MFCTL)) { + /* Reloop over . Useful for streams which have + * fulfilled their qc_stream_desc buf and have now release it. + */ + list_for_each_entry(qcs, &qcc->send_list, el_send) { + /* Only streams blocked on flow-control or waiting on a + * new qc_stream_desc should be present in send_list as + * long as transport layer can handle all data. + */ + BUG_ON(qcs->stream->buf && !(qcs->flags & QC_SF_BLK_SFCTL)); - ret = _qc_send_qcs(qcs, &frms); - tmp_total += ret; - LIST_DELETE(&qcs->el); + if (!(qcs->flags & QC_SF_BLK_SFCTL)) + total += _qc_send_qcs(qcs, &frms); + } } - total += tmp_total; - if (!qc_send_frames(qcc, &frms) && !LIST_ISEMPTY(&qcc->send_retry_list)) - goto retry; - out: /* Deallocate frames that the transport layer has rejected. */ if (!LIST_ISEMPTY(&frms)) { @@ -2174,7 +2168,6 @@ static int qc_init(struct connection *conn, struct proxy *prx, } LIST_INIT(&qcc->send_list); - LIST_INIT(&qcc->send_retry_list); qcc->wait_event.tasklet->process = qc_io_cb; qcc->wait_event.tasklet->context = qcc;