comparison src/event/quic/ngx_event_quic_frames.c @ 8950:fb811b6c76ee quic

QUIC: refactored buffer allocation, spliting and freeing. Previously, buffer lists was used to track used buffers. Now reference counter is used instead. The new implementation is simpler and faster with many buffer clones.
author Roman Arutyunyan <arut@nginx.com>
date Fri, 24 Dec 2021 18:39:22 +0300
parents 2e22110828dd
children 5acd0d89d8c2
comparison
equal deleted inserted replaced
8949:2e22110828dd 8950:fb811b6c76ee
10 #include <ngx_event_quic_connection.h> 10 #include <ngx_event_quic_connection.h>
11 11
12 12
13 #define NGX_QUIC_BUFFER_SIZE 4096 13 #define NGX_QUIC_BUFFER_SIZE 4096
14 14
15 #define ngx_quic_buf_refs(b) (b)->shadow->num
16 #define ngx_quic_buf_inc_refs(b) ngx_quic_buf_refs(b)++
17 #define ngx_quic_buf_dec_refs(b) ngx_quic_buf_refs(b)--
18 #define ngx_quic_buf_set_refs(b, v) ngx_quic_buf_refs(b) = v
19
20
21 static ngx_buf_t *ngx_quic_alloc_buf(ngx_connection_t *c);
22 static void ngx_quic_free_buf(ngx_connection_t *c, ngx_buf_t *b);
23 static ngx_buf_t *ngx_quic_clone_buf(ngx_connection_t *c, ngx_buf_t *b);
24
25
26 static ngx_buf_t *
27 ngx_quic_alloc_buf(ngx_connection_t *c)
28 {
29 u_char *p;
30 ngx_buf_t *b;
31 ngx_quic_connection_t *qc;
32
33 qc = ngx_quic_get_connection(c);
34
35 b = qc->free_bufs;
36
37 if (b) {
38 qc->free_bufs = b->shadow;
39 p = b->start;
40
41 } else {
42 b = qc->free_shadow_bufs;
43
44 if (b) {
45 qc->free_shadow_bufs = b->shadow;
46
47 #ifdef NGX_QUIC_DEBUG_ALLOC
48 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
49 "quic use shadow buffer n:%ui %ui",
50 ++qc->nbufs, --qc->nshadowbufs);
51 #endif
52
53 } else {
54 b = ngx_palloc(c->pool, sizeof(ngx_buf_t));
55 if (b == NULL) {
56 return NULL;
57 }
58
59 #ifdef NGX_QUIC_DEBUG_ALLOC
60 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
61 "quic new buffer n:%ui", ++qc->nbufs);
62 #endif
63 }
64
65 p = ngx_pnalloc(c->pool, NGX_QUIC_BUFFER_SIZE);
66 if (p == NULL) {
67 return NULL;
68 }
69 }
70
71 #ifdef NGX_QUIC_DEBUG_ALLOC
72 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic alloc buffer %p", b);
73 #endif
74
75 ngx_memzero(b, sizeof(ngx_buf_t));
76
77 b->tag = (ngx_buf_tag_t) &ngx_quic_alloc_buf;
78 b->temporary = 1;
79 b->shadow = b;
80
81 b->start = p;
82 b->pos = p;
83 b->last = p;
84 b->end = p + NGX_QUIC_BUFFER_SIZE;
85
86 ngx_quic_buf_set_refs(b, 1);
87
88 return b;
89 }
90
91
92 static void
93 ngx_quic_free_buf(ngx_connection_t *c, ngx_buf_t *b)
94 {
95 ngx_buf_t *shadow;
96 ngx_quic_connection_t *qc;
97
98 qc = ngx_quic_get_connection(c);
99
100 ngx_quic_buf_dec_refs(b);
101
102 #ifdef NGX_QUIC_DEBUG_ALLOC
103 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
104 "quic free buffer %p r:%ui",
105 b, (ngx_uint_t) ngx_quic_buf_refs(b));
106 #endif
107
108 shadow = b->shadow;
109
110 if (ngx_quic_buf_refs(b) == 0) {
111 shadow->shadow = qc->free_bufs;
112 qc->free_bufs = shadow;
113 }
114
115 if (b != shadow) {
116 b->shadow = qc->free_shadow_bufs;
117 qc->free_shadow_bufs = b;
118 }
119
120 }
121
122
123 static ngx_buf_t *
124 ngx_quic_clone_buf(ngx_connection_t *c, ngx_buf_t *b)
125 {
126 ngx_buf_t *nb;
127 ngx_quic_connection_t *qc;
128
129 qc = ngx_quic_get_connection(c);
130
131 nb = qc->free_shadow_bufs;
132
133 if (nb) {
134 qc->free_shadow_bufs = nb->shadow;
135
136 } else {
137 nb = ngx_palloc(c->pool, sizeof(ngx_buf_t));
138 if (nb == NULL) {
139 return NULL;
140 }
141
142 #ifdef NGX_QUIC_DEBUG_ALLOC
143 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
144 "quic new shadow buffer n:%ui", ++qc->nshadowbufs);
145 #endif
146 }
147
148 *nb = *b;
149
150 ngx_quic_buf_inc_refs(b);
151
152 #ifdef NGX_QUIC_DEBUG_ALLOC
153 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
154 "quic clone buffer %p %p r:%ui",
155 b, nb, (ngx_uint_t) ngx_quic_buf_refs(b));
156 #endif
157
158 return nb;
159 }
160
15 161
16 ngx_quic_frame_t * 162 ngx_quic_frame_t *
17 ngx_quic_alloc_frame(ngx_connection_t *c) 163 ngx_quic_alloc_frame(ngx_connection_t *c)
18 { 164 {
19 ngx_queue_t *q; 165 ngx_queue_t *q;
99 245
100 246
101 void 247 void
102 ngx_quic_free_chain(ngx_connection_t *c, ngx_chain_t *in) 248 ngx_quic_free_chain(ngx_connection_t *c, ngx_chain_t *in)
103 { 249 {
104 ngx_buf_t *b, *shadow; 250 ngx_chain_t *cl;
105 ngx_chain_t *cl;
106 ngx_quic_connection_t *qc;
107
108 qc = ngx_quic_get_connection(c);
109 251
110 while (in) { 252 while (in) {
111 #ifdef NGX_QUIC_DEBUG_ALLOC
112 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
113 "quic free buffer n:%ui", qc->nbufs);
114 #endif
115
116 cl = in; 253 cl = in;
117 in = in->next; 254 in = in->next;
118 b = cl->buf; 255
119 256 ngx_quic_free_buf(c, cl->buf);
120 if (b->shadow) { 257 ngx_free_chain(c->pool, cl);
121 if (!b->last_shadow) {
122 b->recycled = 1;
123 ngx_free_chain(c->pool, cl);
124 continue;
125 }
126
127 do {
128 shadow = b->shadow;
129 b->shadow = qc->free_shadow_bufs;
130 qc->free_shadow_bufs = b;
131 b = shadow;
132 } while (b->recycled);
133
134 if (b->shadow) {
135 b->last_shadow = 1;
136 ngx_free_chain(c->pool, cl);
137 continue;
138 }
139
140 cl->buf = b;
141 }
142
143 cl->next = qc->free_bufs;
144 qc->free_bufs = cl;
145 } 258 }
146 } 259 }
147 260
148 261
149 void 262 void
251 364
252 365
253 ngx_chain_t * 366 ngx_chain_t *
254 ngx_quic_read_chain(ngx_connection_t *c, ngx_chain_t **chain, off_t limit) 367 ngx_quic_read_chain(ngx_connection_t *c, ngx_chain_t **chain, off_t limit)
255 { 368 {
256 off_t n; 369 off_t n;
257 ngx_buf_t *b; 370 ngx_buf_t *b;
258 ngx_chain_t *out, *in, *cl, **ll; 371 ngx_chain_t *out, *cl, **ll;
259 ngx_quic_connection_t *qc;
260
261 qc = ngx_quic_get_connection(c);
262 372
263 out = *chain; 373 out = *chain;
264 374
265 for (ll = &out; *ll; ll = &(*ll)->next) { 375 for (ll = &out; *ll; ll = &(*ll)->next) {
266 b = (*ll)->buf; 376 b = (*ll)->buf;
288 398
289 return out; 399 return out;
290 400
291 split: 401 split:
292 402
293 in = *ll;
294
295 /* split in->buf by creating shadow bufs which reference it */
296
297 if (in->buf->shadow == NULL) {
298 if (qc->free_shadow_bufs) {
299 b = qc->free_shadow_bufs;
300 qc->free_shadow_bufs = b->shadow;
301
302 } else {
303 b = ngx_alloc_buf(c->pool);
304 if (b == NULL) {
305 return NGX_CHAIN_ERROR;
306 }
307 }
308
309 *b = *in->buf;
310 b->shadow = in->buf;
311 b->last_shadow = 1;
312 in->buf = b;
313 }
314
315 cl = ngx_alloc_chain_link(c->pool); 403 cl = ngx_alloc_chain_link(c->pool);
316 if (cl == NULL) { 404 if (cl == NULL) {
317 return NGX_CHAIN_ERROR; 405 return NGX_CHAIN_ERROR;
318 } 406 }
319 407
320 if (qc->free_shadow_bufs) { 408 cl->buf = ngx_quic_clone_buf(c, b);
321 b = qc->free_shadow_bufs; 409 if (cl->buf == NULL) {
322 qc->free_shadow_bufs = b->shadow; 410 return NGX_CHAIN_ERROR;
323 411 }
324 } else { 412
325 b = ngx_alloc_buf(c->pool); 413 cl->buf->pos += limit;
326 if (b == NULL) { 414 b->last = cl->buf->pos;
327 ngx_free_chain(c->pool, cl); 415 b->last_buf = 0;
328 return NGX_CHAIN_ERROR; 416
329 } 417 ll = &(*ll)->next;
330 } 418 cl->next = *ll;
331 419 *ll = NULL;
332 cl->buf = b;
333 cl->next = in->next;
334 in->next = NULL;
335 *chain = cl; 420 *chain = cl;
336
337 *b = *in->buf;
338 b->last_shadow = 0;
339 b->pos += limit;
340
341 in->buf->shadow = b;
342 in->buf->last = b->pos;
343 in->buf->last_buf = 0;
344 421
345 return out; 422 return out;
346 } 423 }
347 424
348 425
349 ngx_chain_t * 426 ngx_chain_t *
350 ngx_quic_alloc_chain(ngx_connection_t *c) 427 ngx_quic_alloc_chain(ngx_connection_t *c)
351 { 428 {
352 ngx_buf_t *b; 429 ngx_chain_t *cl;
353 ngx_chain_t *cl;
354 ngx_quic_connection_t *qc;
355
356 qc = ngx_quic_get_connection(c);
357
358 if (qc->free_bufs) {
359 cl = qc->free_bufs;
360 qc->free_bufs = cl->next;
361
362 b = cl->buf;
363 b->pos = b->start;
364 b->last = b->start;
365
366 #ifdef NGX_QUIC_DEBUG_ALLOC
367 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
368 "quic reuse buffer n:%ui", qc->nbufs);
369 #endif
370
371 return cl;
372 }
373 430
374 cl = ngx_alloc_chain_link(c->pool); 431 cl = ngx_alloc_chain_link(c->pool);
375 if (cl == NULL) { 432 if (cl == NULL) {
376 return NULL; 433 return NULL;
377 } 434 }
378 435
379 b = ngx_create_temp_buf(c->pool, NGX_QUIC_BUFFER_SIZE); 436 cl->buf = ngx_quic_alloc_buf(c);
380 if (b == NULL) { 437 if (cl->buf == NULL) {
381 return NULL; 438 return NULL;
382 } 439 }
383
384 b->tag = (ngx_buf_tag_t) &ngx_quic_alloc_chain;
385
386 cl->buf = b;
387
388 #ifdef NGX_QUIC_DEBUG_ALLOC
389 ++qc->nbufs;
390
391 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
392 "quic alloc buffer n:%ui", qc->nbufs);
393 #endif
394 440
395 return cl; 441 return cl;
396 } 442 }
397 443
398 444