mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-05-11 20:28:13 +00:00
MINOR: mux-quic: limit emitted MSD frames count per qcs
The previous commit has implemented a new calcul method for MAX_STREAM_DATA frame emission. Now, a frame may be emitted as soon as a buffer was consumed by a QCS instance. This will probably increase the number of MAX_STREAM_DATA frame emission. It may even cause a series of frame emitted for the same stream with increasing values under high load, which is completely unnecessary. To improve this, limit the number of MAX_STREAM_DATA frames built to one per QCS instance. This is implemented by storing a reference to this frame in QCS structure via a new member <tx.msd_frm>. Note that to properly reset QCS msd_frm member, emission of flow-control frames have been changed. Now, each frame is emitted individually. On one side, it is better as it prevent to emit frames related to different streams in a single datagram, which is not desirable in case of packet loss. However, this can also increase sendto() syscall invocation.
This commit is contained in:
parent
14a3fb679f
commit
df50d3e39f
@ -160,6 +160,7 @@ struct qcs {
|
||||
} rx;
|
||||
struct {
|
||||
struct quic_fctl fc; /* stream flow control applied on sending */
|
||||
struct quic_frame *msd_frm; /* MAX_STREAM_DATA frame prepared */
|
||||
} tx;
|
||||
|
||||
struct eb64_node by_id;
|
||||
|
@ -162,6 +162,8 @@ static struct qcs *qcs_new(struct qcc *qcc, uint64_t id, enum qcs_type type)
|
||||
qfctl_init(&qcs->tx.fc, 0);
|
||||
}
|
||||
|
||||
qcs->tx.msd_frm = NULL;
|
||||
|
||||
qcs->rx.bufs = EB_ROOT_UNIQUE;
|
||||
qcs->rx.app_buf = BUF_NULL;
|
||||
qcs->rx.offset = qcs->rx.offset_max = 0;
|
||||
@ -1237,20 +1239,25 @@ static void qcs_consume(struct qcs *qcs, uint64_t bytes, struct qc_stream_rxbuf
|
||||
}
|
||||
|
||||
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);
|
||||
frm = qcs->tx.msd_frm;
|
||||
if (!frm) {
|
||||
qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR, 0);
|
||||
return;
|
||||
frm = qc_frm_alloc(QUIC_FT_MAX_STREAM_DATA);
|
||||
if (!frm) {
|
||||
qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
frm->max_stream_data.id = qcs->id;
|
||||
LIST_APPEND(&qcc->lfctl.frms, &frm->list);
|
||||
qcs->tx.msd_frm = frm;
|
||||
}
|
||||
|
||||
TRACE_DATA("increase stream credit via MAX_STREAM_DATA", QMUX_EV_QCS_RECV, qcc->conn, qcs);
|
||||
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;
|
||||
|
||||
LIST_APPEND(&qcc->lfctl.frms, &frm->list);
|
||||
tasklet_wakeup(qcc->wait_event.tasklet);
|
||||
}
|
||||
|
||||
@ -2585,6 +2592,56 @@ static int qcs_send(struct qcs *qcs, struct list *frms, uint64_t window_conn)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Emit prepared flow-control related frames from <qcc> list.
|
||||
*
|
||||
* Returns 0 on success else non zero.
|
||||
*/
|
||||
static int qcc_emit_fctl(struct qcc *qcc)
|
||||
{
|
||||
struct list single_frm = LIST_HEAD_INIT(single_frm);
|
||||
struct quic_frame *frm;
|
||||
struct eb64_node *node;
|
||||
struct qcs *qcs;
|
||||
int64_t id;
|
||||
|
||||
TRACE_ENTER(QMUX_EV_QCC_END, qcc->conn);
|
||||
|
||||
while (!LIST_ISEMPTY(&qcc->lfctl.frms)) {
|
||||
/* Each frame is sent individually in a single element list. */
|
||||
frm = LIST_ELEM(qcc->lfctl.frms.n, struct quic_frame *, list);
|
||||
id = frm->type == QUIC_FT_MAX_STREAM_DATA ?
|
||||
frm->max_stream_data.id : -1;
|
||||
|
||||
LIST_DELETE(&frm->list);
|
||||
LIST_APPEND(&single_frm, &frm->list);
|
||||
|
||||
if (qcc_send_frames(qcc, &single_frm, 0)) {
|
||||
/* replace frame that cannot be sent in qcc list. */
|
||||
LIST_DELETE(&frm->list);
|
||||
LIST_INSERT(&qcc->lfctl.frms, &frm->list);
|
||||
goto err;
|
||||
}
|
||||
|
||||
BUG_ON_HOT(!LIST_ISEMPTY(&single_frm));
|
||||
|
||||
/* If frame is MAX_STREAM_DATA, reset corresponding QCS msd_frm pointer. */
|
||||
if (id >= 0) {
|
||||
node = eb64_lookup(&qcc->streams_by_id, frm->max_stream_data.id);
|
||||
if (node) {
|
||||
qcs = eb64_entry(node, struct qcs, by_id);
|
||||
qcs->tx.msd_frm = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TRACE_LEAVE(QMUX_EV_QCC_SEND, qcc->conn);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
TRACE_DEVEL("leaving on error", QMUX_EV_QCC_SEND, qcc->conn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Send RESET_STREAM/STOP_SENDING for streams in <qcc> send_list if requested.
|
||||
* Each frame is encoded and emitted separately for now. If a frame cannot be
|
||||
* sent, send_list looping is interrupted.
|
||||
@ -2830,7 +2887,7 @@ static int qcc_io_send(struct qcc *qcc)
|
||||
}
|
||||
|
||||
if (!LIST_ISEMPTY(&qcc->lfctl.frms)) {
|
||||
if (qcc_send_frames(qcc, &qcc->lfctl.frms, 0)) {
|
||||
if (qcc_emit_fctl(qcc)) {
|
||||
TRACE_DEVEL("flow-control frames rejected by transport, aborting send", QMUX_EV_QCC_SEND, qcc->conn);
|
||||
goto out;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user