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 }