Mercurial > hg > nginx
comparison src/event/quic/ngx_event_quic_streams.c @ 8946:56dec0d4e5b1 quic
QUIC: avoid excessive buffer allocations in stream output.
Previously, when a few bytes were send to a QUIC stream by the application, a
4K buffer was allocated for these bytes. Then a STREAM frame was created and
that entire buffer was used as data for that frame. The frame with the buffer
were in use up until the frame was acked by client. Meanwhile, when more
bytes were send to the stream, more buffers were allocated and assigned as
data to newer STREAM frames. In this scenario most buffer memory is unused.
Now the unused part of the stream output buffer is available for further
stream output while earlier parts of the buffer are waiting to be acked.
This is achieved by splitting the output buffer.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Fri, 24 Dec 2021 18:13:51 +0300 |
parents | 23880e4ad3e2 |
children | 6ccf3867959a |
comparison
equal
deleted
inserted
replaced
8945:e72db9162180 | 8946:56dec0d4e5b1 |
---|---|
836 | 836 |
837 static ngx_chain_t * | 837 static ngx_chain_t * |
838 ngx_quic_stream_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) | 838 ngx_quic_stream_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) |
839 { | 839 { |
840 size_t n, flow; | 840 size_t n, flow; |
841 ngx_buf_t *b; | |
841 ngx_event_t *wev; | 842 ngx_event_t *wev; |
842 ngx_chain_t *cl; | 843 ngx_chain_t *out, **ll; |
843 ngx_connection_t *pc; | 844 ngx_connection_t *pc; |
844 ngx_quic_frame_t *frame; | 845 ngx_quic_frame_t *frame; |
845 ngx_quic_stream_t *qs; | 846 ngx_quic_stream_t *qs; |
846 ngx_quic_connection_t *qc; | 847 ngx_quic_connection_t *qc; |
847 | 848 |
860 return in; | 861 return in; |
861 } | 862 } |
862 | 863 |
863 n = (limit && (size_t) limit < flow) ? (size_t) limit : flow; | 864 n = (limit && (size_t) limit < flow) ? (size_t) limit : flow; |
864 | 865 |
866 if (ngx_quic_order_bufs(pc, &qs->out, in, n, 0) != NGX_OK) { | |
867 return NGX_CHAIN_ERROR; | |
868 } | |
869 | |
870 n = 0; | |
871 out = qs->out; | |
872 | |
873 for (ll = &out; *ll; ll = &(*ll)->next) { | |
874 b = (*ll)->buf; | |
875 | |
876 if (b->sync) { | |
877 /* hole */ | |
878 break; | |
879 } | |
880 | |
881 n += b->last - b->pos; | |
882 } | |
883 | |
884 qs->out = *ll; | |
885 *ll = NULL; | |
886 | |
865 frame = ngx_quic_alloc_frame(pc); | 887 frame = ngx_quic_alloc_frame(pc); |
866 if (frame == NULL) { | 888 if (frame == NULL) { |
867 return NGX_CHAIN_ERROR; | 889 return NGX_CHAIN_ERROR; |
868 } | 890 } |
869 | 891 |
870 frame->data = ngx_quic_copy_chain(pc, in, n); | |
871 if (frame->data == NGX_CHAIN_ERROR) { | |
872 return NGX_CHAIN_ERROR; | |
873 } | |
874 | |
875 for (n = 0, cl = frame->data; cl; cl = cl->next) { | |
876 n += ngx_buf_size(cl->buf); | |
877 } | |
878 | |
879 while (in && ngx_buf_size(in->buf) == 0) { | 892 while (in && ngx_buf_size(in->buf) == 0) { |
880 in = in->next; | 893 in = in->next; |
881 } | 894 } |
882 | 895 |
883 frame->level = ssl_encryption_application; | 896 frame->level = ssl_encryption_application; |
884 frame->type = NGX_QUIC_FT_STREAM; | 897 frame->type = NGX_QUIC_FT_STREAM; |
898 frame->data = out; | |
885 frame->u.stream.off = 1; | 899 frame->u.stream.off = 1; |
886 frame->u.stream.len = 1; | 900 frame->u.stream.len = 1; |
887 frame->u.stream.fin = 0; | 901 frame->u.stream.fin = 0; |
888 | 902 |
889 frame->u.stream.stream_id = qs->id; | 903 frame->u.stream.stream_id = qs->id; |
975 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | 989 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, |
976 "quic stream id:0x%xL cleanup", qs->id); | 990 "quic stream id:0x%xL cleanup", qs->id); |
977 | 991 |
978 ngx_rbtree_delete(&qc->streams.tree, &qs->node); | 992 ngx_rbtree_delete(&qc->streams.tree, &qs->node); |
979 ngx_quic_free_bufs(pc, qs->in); | 993 ngx_quic_free_bufs(pc, qs->in); |
994 ngx_quic_free_bufs(pc, qs->out); | |
980 | 995 |
981 if (qc->closing) { | 996 if (qc->closing) { |
982 /* schedule handler call to continue ngx_quic_close_connection() */ | 997 /* schedule handler call to continue ngx_quic_close_connection() */ |
983 ngx_post_event(pc->read, &ngx_posted_events); | 998 ngx_post_event(pc->read, &ngx_posted_events); |
984 return; | 999 return; |
1096 | 1111 |
1097 rev->pending_eof = 1; | 1112 rev->pending_eof = 1; |
1098 qs->final_size = last; | 1113 qs->final_size = last; |
1099 } | 1114 } |
1100 | 1115 |
1101 if (ngx_quic_order_bufs(c, &qs->in, frame->data, | 1116 if (ngx_quic_order_bufs(c, &qs->in, frame->data, f->length, |
1102 f->offset - qs->recv_offset) | 1117 f->offset - qs->recv_offset) |
1103 != NGX_OK) | 1118 != NGX_OK) |
1104 { | 1119 { |
1105 return NGX_ERROR; | 1120 return NGX_ERROR; |
1106 } | 1121 } |