HTTP/3: optimize encoder stream memory usage

Previously, the encoder stream allocated each new inserted field in the
connection pool.  This memory was not freed until the end of the connection.
Now a special insert buffer is used for all inserts.
This commit is contained in:
Roman Arutyunyan
2026-04-10 21:42:18 +04:00
committed by Roman Arutyunyan
parent 4e89ce224f
commit d7dd7e9ae4
4 changed files with 52 additions and 3 deletions
+27 -3
View File
@@ -633,9 +633,23 @@ ngx_http_v3_parse_literal(ngx_connection_t *c, ngx_http_v3_parse_literal_t *st,
st->huffstate = 0;
}
st->last = ngx_pnalloc(c->pool, n + 1);
if (st->last == NULL) {
return NGX_ERROR;
if (st->buf) {
if ((size_t) (st->buf->end - st->buf->last) < n + 1) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"not enough dynamic table capacity");
st->last = NULL;
return NGX_ERROR;
}
st->last = st->buf->last;
st->buf->last += n + 1;
} else {
st->last = ngx_pnalloc(c->pool, n + 1);
if (st->last == NULL) {
return NGX_ERROR;
}
}
st->value.data = st->last;
@@ -1486,6 +1500,11 @@ ngx_http_v3_parse_field_inr(ngx_connection_t *c,
ch = *b->pos;
st->literal.buf = ngx_http_v3_get_insert_buffer(c);
if (st->literal.buf == NULL) {
return NGX_ERROR;
}
st->dynamic = (ch & 0x40) ? 0 : 1;
st->state = sw_name_index;
@@ -1590,6 +1609,11 @@ ngx_http_v3_parse_field_iln(ngx_connection_t *c,
ch = *b->pos;
st->literal.buf = ngx_http_v3_get_insert_buffer(c);
if (st->literal.buf == NULL) {
return NGX_ERROR;
}
st->literal.huffman = (ch & 0x20) ? 1 : 0;
st->state = sw_name_len;
+1
View File
@@ -51,6 +51,7 @@ typedef struct {
ngx_str_t value;
u_char *last;
u_char huffstate;
ngx_buf_t *buf;
} ngx_http_v3_parse_literal_t;
+22
View File
@@ -155,6 +155,28 @@ static ngx_http_v3_field_t ngx_http_v3_static_table[] = {
};
ngx_buf_t *
ngx_http_v3_get_insert_buffer(ngx_connection_t *c)
{
ngx_http_v3_session_t *h3c;
ngx_http_v3_dynamic_table_t *dt;
h3c = ngx_http_v3_get_session(c);
dt = &h3c->table;
if (dt->insert_buffer == NULL) {
dt->insert_buffer = ngx_create_temp_buf(c->pool, dt->capacity);
if (dt->insert_buffer == NULL) {
return NULL;
}
}
dt->insert_buffer->last = dt->insert_buffer->pos;
return dt->insert_buffer;
}
ngx_int_t
ngx_http_v3_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic,
ngx_uint_t index, ngx_str_t *value)
+2
View File
@@ -29,11 +29,13 @@ typedef struct {
uint64_t insert_count;
uint64_t ack_insert_count;
ngx_event_t send_insert_count;
ngx_buf_t *insert_buffer;
} ngx_http_v3_dynamic_table_t;
void ngx_http_v3_inc_insert_count_handler(ngx_event_t *ev);
void ngx_http_v3_cleanup_table(ngx_http_v3_session_t *h3c);
ngx_buf_t *ngx_http_v3_get_insert_buffer(ngx_connection_t *c);
ngx_int_t ngx_http_v3_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic,
ngx_uint_t index, ngx_str_t *value);
ngx_int_t ngx_http_v3_insert(ngx_connection_t *c, ngx_str_t *name,