void qcc_notify_buf(struct qcc *qcc, uint64_t free_size);
struct buffer *qcc_get_stream_rxbuf(struct qcs *qcs);
-struct buffer *qcc_get_stream_txbuf(struct qcs *qcs, int *err);
+struct buffer *qcc_get_stream_txbuf(struct qcs *qcs, int *err, int small);
int qcc_realign_stream_txbuf(const struct qcs *qcs, struct buffer *out);
int qcc_release_stream_txbuf(struct qcs *qcs);
int qcc_stream_can_send(const struct qcs *qcs);
struct qc_stream_buf {
struct buffer buf; /* STREAM payload */
struct list list; /* element for qc_stream_desc list */
+ int sbuf;
};
#define QC_SD_FL_RELEASE 0x00000001 /* set when MUX has finished to use this stream */
struct buffer *qc_stream_buf_get(struct qc_stream_desc *stream);
struct buffer *qc_stream_buf_alloc(struct qc_stream_desc *stream,
- uint64_t offset);
+ uint64_t offset, int small);
void qc_stream_buf_release(struct qc_stream_desc *stream);
#endif /* USE_QUIC */
goto err;
}
- if (!(res = qcc_get_stream_txbuf(qcs, &err))) {
+ if (!(res = qcc_get_stream_txbuf(qcs, &err, 0))) {
/* Only memory failure can cause buf alloc error for control stream due to qcs_send_metadata() usage. */
TRACE_ERROR("cannot allocate Tx buffer", H3_EV_TX_FRAME|H3_EV_TX_SETTINGS, qcs->qcc->conn, qcs);
goto err;
list[hdr].n = ist("");
- if (!(res = qcc_get_stream_txbuf(qcs, &err))) {
+ if (!(res = qcc_get_stream_txbuf(qcs, &err, 0))) {
if (err) {
TRACE_ERROR("cannot allocate Tx buffer", H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs);
goto err;
list[hdr].n = ist("");
start:
- if (!(res = qcc_get_stream_txbuf(qcs, &err))) {
+ if (!(res = qcc_get_stream_txbuf(qcs, &err, 0))) {
if (err) {
TRACE_ERROR("cannot allocate Tx buffer", H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs);
goto err;
if (type != HTX_BLK_DATA)
goto end;
- if (!(res = qcc_get_stream_txbuf(qcs, &err))) {
+ if (!(res = qcc_get_stream_txbuf(qcs, &err, 0))) {
if (err) {
TRACE_ERROR("cannot allocate Tx buffer", H3_EV_TX_FRAME|H3_EV_TX_DATA, qcs->qcc->conn, qcs);
goto err;
TRACE_ENTER(H3_EV_STRM_SEND, qcs->qcc->conn, qcs);
start:
- if (!(res = qcc_get_stream_txbuf(qcs, &err))) {
+ if (!(res = qcc_get_stream_txbuf(qcs, &err, 0))) {
if (err) {
qcs->sd->iobuf.flags |= IOBUF_FL_NO_FF;
goto end;
b_quic_enc_int(&pos, frm_len, 0);
b_quic_enc_int(&pos, h3c->id_goaway, 0);
- res = qcc_get_stream_txbuf(qcs, &err);
+ res = qcc_get_stream_txbuf(qcs, &err, 0);
if (!res || b_room(res) < b_data(&pos) ||
qfctl_sblocked(&qcs->tx.fc) || qfctl_sblocked(&h3c->qcc->tx.fc)) {
/* Do not try forcefully to emit GOAWAY if no buffer available or not enough space left. */
switch (btype) {
case HTX_BLK_DATA:
- res = qcc_get_stream_txbuf(qcs, &err);
+ res = qcc_get_stream_txbuf(qcs, &err, 0);
if (!res) {
if (err)
ABORT_NOW();
struct buffer *res;
start:
- res = qcc_get_stream_txbuf(qcs, &err);
+ res = qcc_get_stream_txbuf(qcs, &err, 0);
if (!res) {
if (err)
ABORT_NOW();
* Returns buffer pointer. May be NULL on allocation failure, in which case
* <err> will refer to the cause.
*/
-struct buffer *qcc_get_stream_txbuf(struct qcs *qcs, int *err)
+struct buffer *qcc_get_stream_txbuf(struct qcs *qcs, int *err, int small)
{
struct qcc *qcc = qcs->qcc;
struct buffer *out = qc_stream_buf_get(qcs->stream);
}
}
- out = qc_stream_buf_alloc(qcs->stream, qcs->tx.fc.off_real);
+ out = qc_stream_buf_alloc(qcs->stream, qcs->tx.fc.off_real, small);
if (!out) {
TRACE_ERROR("stream desc alloc failure", QMUX_EV_QCS_SEND, qcc->conn, qcs);
*err = 1;
}
if (likely(!unlimited))
- qcc->tx.buf_in_flight += global.tune.bufsize;
+ qcc->tx.buf_in_flight += b_size(out);
}
out:
stream->buf = NULL;
free_size = b_size(buf);
- b_free(buf);
- offer_buffers(NULL, 1);
+ if ((*stream_buf)->sbuf) {
+ pool_free(pool_head_sbuf, buf->area);
+ }
+ else {
+ b_free(buf);
+ offer_buffers(NULL, 1);
+ }
pool_free(pool_head_quic_stream_buf, *stream_buf);
*stream_buf = NULL;
list_for_each_entry_safe(buf, buf_back, &stream->buf_list, list) {
if (!(b_data(&buf->buf)) || closing) {
free_size += b_size(&buf->buf);
- b_free(&buf->buf);
+ if (buf->sbuf)
+ pool_free(pool_head_sbuf, buf->buf.area);
+ else
+ b_free(&buf->buf);
LIST_DELETE(&buf->list);
pool_free(pool_head_quic_stream_buf, buf);
++free_count;
* Returns the buffer or NULL on error.
*/
struct buffer *qc_stream_buf_alloc(struct qc_stream_desc *stream,
- uint64_t offset)
+ uint64_t offset, int small)
{
/* current buffer must be released first before allocate a new one. */
BUG_ON(stream->buf);
return NULL;
stream->buf->buf = BUF_NULL;
- if (!b_alloc(&stream->buf->buf, DB_MUX_TX)) {
- pool_free(pool_head_quic_stream_buf, stream->buf);
- stream->buf = NULL;
- return NULL;
+
+ if (!small) {
+ stream->buf->sbuf = 0;
+ if (!b_alloc(&stream->buf->buf, DB_MUX_TX)) {
+ pool_free(pool_head_quic_stream_buf, stream->buf);
+ stream->buf = NULL;
+ return NULL;
+ }
+ }
+ else {
+ char *area;
+
+ if (!(area = pool_alloc(pool_head_sbuf))) {
+ pool_free(pool_head_quic_stream_buf, stream->buf);
+ stream->buf = NULL;
+ return NULL;
+ }
+
+ stream->buf->sbuf = 1;
+ stream->buf->buf = b_make(area, global.tune.bufsize_small, 0, 0);
}
LIST_APPEND(&stream->buf_list, &stream->buf->list);