mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-10 00:57:02 +02:00
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 <qcc.send_list>. 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 <qcc.send_retry_list>. Now, we can reuse the new <qcc.send_list> 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 <qcc.send_list> : * 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.
This commit is contained in:
parent
0a1154afb5
commit
a9de7ea1dc
@ -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);
|
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 &&
|
if (qcs->tx.offset == qcs->tx.sent_offset &&
|
||||||
b_full(&qcs->stream->buf->buf)) {
|
b_full(&qcs->stream->buf->buf)) {
|
||||||
qc_stream_buf_release(qcs->stream);
|
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;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
LIST_INIT(&qcc->send_retry_list);
|
|
||||||
|
|
||||||
if (!qc_send_mux(qcc->conn->handle.qc, frms))
|
if (!qc_send_mux(qcc->conn->handle.qc, frms))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
@ -1725,7 +1721,7 @@ static int qc_send(struct qcc *qcc)
|
|||||||
{
|
{
|
||||||
struct list frms = LIST_HEAD_INIT(frms);
|
struct list frms = LIST_HEAD_INIT(frms);
|
||||||
struct qcs *qcs, *qcs_tmp;
|
struct qcs *qcs, *qcs_tmp;
|
||||||
int total = 0, tmp_total = 0;
|
int total = 0;
|
||||||
|
|
||||||
TRACE_ENTER(QMUX_EV_QCC_SEND, qcc->conn);
|
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);
|
total += _qc_send_qcs(qcs, &frms);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qc_send_frames(qcc, &frms)) {
|
/* Retry sending until no frame to send, data rejected or connection
|
||||||
/* data rejected by transport layer, do not retry. */
|
* flow-control limit reached.
|
||||||
goto out;
|
*/
|
||||||
|
while (qc_send_frames(qcc, &frms) == 0 && !(qcc->flags & QC_CF_BLK_MFCTL)) {
|
||||||
|
/* Reloop over <qcc.send_list>. 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));
|
||||||
|
|
||||||
|
if (!(qcs->flags & QC_SF_BLK_SFCTL))
|
||||||
|
total += _qc_send_qcs(qcs, &frms);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
ret = _qc_send_qcs(qcs, &frms);
|
|
||||||
tmp_total += ret;
|
|
||||||
LIST_DELETE(&qcs->el);
|
|
||||||
}
|
|
||||||
|
|
||||||
total += tmp_total;
|
|
||||||
if (!qc_send_frames(qcc, &frms) && !LIST_ISEMPTY(&qcc->send_retry_list))
|
|
||||||
goto retry;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
/* Deallocate frames that the transport layer has rejected. */
|
/* Deallocate frames that the transport layer has rejected. */
|
||||||
if (!LIST_ISEMPTY(&frms)) {
|
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_list);
|
||||||
LIST_INIT(&qcc->send_retry_list);
|
|
||||||
|
|
||||||
qcc->wait_event.tasklet->process = qc_io_cb;
|
qcc->wait_event.tasklet->process = qc_io_cb;
|
||||||
qcc->wait_event.tasklet->context = qcc;
|
qcc->wait_event.tasklet->context = qcc;
|
||||||
|
Loading…
Reference in New Issue
Block a user