Mercurial > hg > nginx
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 |