Mercurial > hg > nginx-vendor-0-8
comparison src/core/ngx_output_chain.c @ 406:79c5df00501e NGINX_0_7_15
nginx 0.7.15
*) Feature: the ngx_http_random_index_module.
*) Feature: the "directio" directive has been optimized for file
requests starting from arbitrary position.
*) Feature: the "directio" directive turns off sendfile if it is
necessary.
*) Feature: now nginx allows underscores in a client request header
line names.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 08 Sep 2008 00:00:00 +0400 |
parents | 9d81578d04bb |
children | a2a3905c04ab |
comparison
equal
deleted
inserted
replaced
405:2993e60bc4e0 | 406:79c5df00501e |
---|---|
16 | 16 |
17 #define NGX_NONE 1 | 17 #define NGX_NONE 1 |
18 | 18 |
19 | 19 |
20 static ngx_inline ngx_int_t | 20 static ngx_inline ngx_int_t |
21 ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf); | 21 ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf); |
22 static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool, | 22 static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool, |
23 ngx_chain_t **chain, ngx_chain_t *in); | 23 ngx_chain_t **chain, ngx_chain_t *in); |
24 static ngx_int_t ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src, | 24 static ngx_int_t ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, |
25 ngx_uint_t sendfile); | 25 off_t bsize); |
26 static ngx_int_t ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, | |
27 off_t bsize); | |
28 static ngx_int_t ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx); | |
26 | 29 |
27 | 30 |
28 ngx_int_t | 31 ngx_int_t |
29 ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in) | 32 ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in) |
30 { | 33 { |
31 off_t bsize; | 34 off_t bsize; |
32 size_t size; | |
33 ngx_int_t rc, last; | 35 ngx_int_t rc, last; |
34 ngx_uint_t recycled; | |
35 ngx_buf_t *b; | |
36 ngx_chain_t *cl, *out, **last_out; | 36 ngx_chain_t *cl, *out, **last_out; |
37 | 37 |
38 if (ctx->in == NULL && ctx->busy == NULL) { | 38 if (ctx->in == NULL && ctx->busy == NULL) { |
39 | 39 |
40 /* | 40 /* |
49 | 49 |
50 if (in->next == NULL | 50 if (in->next == NULL |
51 #if (NGX_SENDFILE_LIMIT) | 51 #if (NGX_SENDFILE_LIMIT) |
52 && !(in->buf->in_file && in->buf->file_last > NGX_SENDFILE_LIMIT) | 52 && !(in->buf->in_file && in->buf->file_last > NGX_SENDFILE_LIMIT) |
53 #endif | 53 #endif |
54 && !ngx_output_chain_need_to_copy(ctx, in->buf)) | 54 && ngx_output_chain_as_is(ctx, in->buf)) |
55 { | 55 { |
56 return ctx->output_filter(ctx->filter_ctx, in); | 56 return ctx->output_filter(ctx->filter_ctx, in); |
57 } | 57 } |
58 } | 58 } |
59 | 59 |
73 | 73 |
74 while (ctx->in) { | 74 while (ctx->in) { |
75 | 75 |
76 /* | 76 /* |
77 * cycle while there are the ctx->in bufs | 77 * cycle while there are the ctx->in bufs |
78 * or there are the free output bufs to copy in | 78 * and there are the free output bufs to copy in |
79 */ | 79 */ |
80 | 80 |
81 bsize = ngx_buf_size(ctx->in->buf); | 81 bsize = ngx_buf_size(ctx->in->buf); |
82 | 82 |
83 if (bsize == 0 && !ngx_buf_special(ctx->in->buf)) { | 83 if (bsize == 0 && !ngx_buf_special(ctx->in->buf)) { |
100 ctx->in = ctx->in->next; | 100 ctx->in = ctx->in->next; |
101 | 101 |
102 continue; | 102 continue; |
103 } | 103 } |
104 | 104 |
105 if (!ngx_output_chain_need_to_copy(ctx, ctx->in->buf)) { | 105 if (ngx_output_chain_as_is(ctx, ctx->in->buf)) { |
106 | 106 |
107 /* move the chain link to the output chain */ | 107 /* move the chain link to the output chain */ |
108 | 108 |
109 cl = ctx->in; | 109 cl = ctx->in; |
110 ctx->in = cl->next; | 110 ctx->in = cl->next; |
116 continue; | 116 continue; |
117 } | 117 } |
118 | 118 |
119 if (ctx->buf == NULL) { | 119 if (ctx->buf == NULL) { |
120 | 120 |
121 /* get the free buf */ | 121 rc = ngx_output_chain_align_file_buf(ctx, bsize); |
122 | 122 |
123 if (ctx->free) { | 123 if (rc == NGX_ERROR) { |
124 cl = ctx->free; | 124 return NGX_ERROR; |
125 ctx->buf = cl->buf; | 125 } |
126 ctx->free = cl->next; | 126 |
127 ngx_free_chain(ctx->pool, cl); | 127 if (rc != NGX_OK) { |
128 | 128 |
129 } else if (out || ctx->allocated == ctx->bufs.num) { | 129 if (ctx->free) { |
130 | 130 |
131 break; | 131 /* get the free buf */ |
132 | 132 |
133 } else { | 133 cl = ctx->free; |
134 | 134 ctx->buf = cl->buf; |
135 size = ctx->bufs.size; | 135 ctx->free = cl->next; |
136 recycled = 1; | 136 |
137 | 137 ngx_free_chain(ctx->pool, cl); |
138 if (ctx->in->buf->last_in_chain) { | 138 |
139 | 139 } else if (out || ctx->allocated == ctx->bufs.num) { |
140 if (bsize < (off_t) ctx->bufs.size) { | 140 |
141 | 141 break; |
142 /* | 142 |
143 * allocate small temp buf for the small last buf | 143 } else if (ngx_output_chain_get_buf(ctx, bsize) != NGX_OK) { |
144 * or its small last part | |
145 */ | |
146 | |
147 size = (size_t) bsize; | |
148 recycled = 0; | |
149 | |
150 } else if (ctx->bufs.num == 1 | |
151 && (bsize < (off_t) (ctx->bufs.size | |
152 + (ctx->bufs.size >> 2)))) | |
153 { | |
154 /* | |
155 * allocate a temp buf that equals | |
156 * to the last buf if the last buf size is lesser | |
157 * than 1.25 of bufs.size and a temp buf is single | |
158 */ | |
159 | |
160 size = (size_t) bsize; | |
161 recycled = 0; | |
162 } | |
163 } | |
164 | |
165 b = ngx_calloc_buf(ctx->pool); | |
166 if (b == NULL) { | |
167 return NGX_ERROR; | 144 return NGX_ERROR; |
168 } | 145 } |
169 | |
170 /* | |
171 * allocate block aligned to a disk sector size | |
172 * to enable O_DIRECT | |
173 */ | |
174 | |
175 b->start = ngx_pmemalign(ctx->pool, size, 512); | |
176 if (b->start == NULL) { | |
177 return NGX_ERROR; | |
178 } | |
179 | |
180 b->pos = b->start; | |
181 b->last = b->start; | |
182 b->end = b->last + size; | |
183 b->temporary = 1; | |
184 b->tag = ctx->tag; | |
185 b->recycled = recycled; | |
186 | |
187 ctx->buf = b; | |
188 ctx->allocated++; | |
189 } | 146 } |
190 } | 147 } |
191 | 148 |
192 rc = ngx_output_chain_copy_buf(ctx->buf, ctx->in->buf, | 149 rc = ngx_output_chain_copy_buf(ctx); |
193 ctx->sendfile); | |
194 | 150 |
195 if (rc == NGX_ERROR) { | 151 if (rc == NGX_ERROR) { |
196 return rc; | 152 return rc; |
197 } | 153 } |
198 | 154 |
242 } | 198 } |
243 } | 199 } |
244 | 200 |
245 | 201 |
246 static ngx_inline ngx_int_t | 202 static ngx_inline ngx_int_t |
247 ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) | 203 ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) |
248 { | 204 { |
249 ngx_uint_t sendfile; | 205 ngx_uint_t sendfile; |
250 | 206 |
251 if (ngx_buf_special(buf)) { | 207 if (ngx_buf_special(buf)) { |
208 return 1; | |
209 } | |
210 | |
211 if (buf->in_file && buf->file->directio) { | |
252 return 0; | 212 return 0; |
253 } | 213 } |
254 | 214 |
255 sendfile = ctx->sendfile; | 215 sendfile = ctx->sendfile; |
256 | 216 |
263 #endif | 223 #endif |
264 | 224 |
265 if (!sendfile) { | 225 if (!sendfile) { |
266 | 226 |
267 if (!ngx_buf_in_memory(buf)) { | 227 if (!ngx_buf_in_memory(buf)) { |
268 return 1; | 228 return 0; |
269 } | 229 } |
270 | 230 |
271 buf->in_file = 0; | 231 buf->in_file = 0; |
272 } | 232 } |
273 | 233 |
274 if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) { | 234 if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) { |
275 return 1; | 235 return 0; |
276 } | 236 } |
277 | 237 |
278 if (ctx->need_in_temp && (buf->memory || buf->mmap)) { | 238 if (ctx->need_in_temp && (buf->memory || buf->mmap)) { |
279 return 1; | 239 return 0; |
280 } | 240 } |
281 | 241 |
282 return 0; | 242 return 1; |
283 } | 243 } |
284 | 244 |
285 | 245 |
286 static ngx_int_t | 246 static ngx_int_t |
287 ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, | 247 ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, |
311 | 271 |
312 if (buf->in_file | 272 if (buf->in_file |
313 && buf->file_pos < NGX_SENDFILE_LIMIT | 273 && buf->file_pos < NGX_SENDFILE_LIMIT |
314 && buf->file_last > NGX_SENDFILE_LIMIT) | 274 && buf->file_last > NGX_SENDFILE_LIMIT) |
315 { | 275 { |
276 /* split a file buf on two bufs by the sendfile limit */ | |
277 | |
316 b = ngx_calloc_buf(pool); | 278 b = ngx_calloc_buf(pool); |
317 if (b == NULL) { | 279 if (b == NULL) { |
318 return NGX_ERROR; | 280 return NGX_ERROR; |
319 } | 281 } |
320 | 282 |
350 return NGX_OK; | 312 return NGX_OK; |
351 } | 313 } |
352 | 314 |
353 | 315 |
354 static ngx_int_t | 316 static ngx_int_t |
355 ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src, ngx_uint_t sendfile) | 317 ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, off_t bsize) |
356 { | 318 { |
357 off_t size; | 319 size_t size; |
358 ssize_t n; | 320 ngx_buf_t *in; |
321 | |
322 in = ctx->in->buf; | |
323 | |
324 if (in->file == NULL || !in->file->directio) { | |
325 return NGX_DECLINED; | |
326 } | |
327 | |
328 ctx->directio = 1; | |
329 | |
330 size = (size_t) (in->file_pos - (in->file_pos & ~511)); | |
331 | |
332 if (size == 0) { | |
333 | |
334 if (bsize >= ctx->bufs.size) { | |
335 return NGX_DECLINED; | |
336 } | |
337 | |
338 size = (size_t) bsize; | |
339 | |
340 } else { | |
341 size = 512 - size; | |
342 | |
343 if (size > bsize) { | |
344 size = (size_t) bsize; | |
345 } | |
346 } | |
347 | |
348 ctx->buf = ngx_create_temp_buf(ctx->pool, size); | |
349 if (ctx->buf == NULL) { | |
350 return NGX_ERROR; | |
351 } | |
352 | |
353 /* | |
354 * we do not set ctx->buf->tag, because we do not want | |
355 * to reuse the buf via ctx->free list | |
356 */ | |
357 | |
358 return NGX_OK; | |
359 } | |
360 | |
361 | |
362 static ngx_int_t | |
363 ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize) | |
364 { | |
365 size_t size; | |
366 ngx_buf_t *b, *in; | |
367 ngx_uint_t recycled; | |
368 | |
369 in = ctx->in->buf; | |
370 size = ctx->bufs.size; | |
371 recycled = 1; | |
372 | |
373 if (in->last_in_chain) { | |
374 | |
375 if (bsize < (off_t) size) { | |
376 | |
377 /* | |
378 * allocate a small temp buf for a small last buf | |
379 * or its small last part | |
380 */ | |
381 | |
382 size = (size_t) bsize; | |
383 recycled = 0; | |
384 | |
385 } else if (!ctx->directio | |
386 && ctx->bufs.num == 1 | |
387 && (bsize < (off_t) (size + size / 4))) | |
388 { | |
389 /* | |
390 * allocate a temp buf that equals to a last buf, | |
391 * if there is no directio, the last buf size is lesser | |
392 * than 1.25 of bufs.size and the temp buf is single | |
393 */ | |
394 | |
395 size = (size_t) bsize; | |
396 recycled = 0; | |
397 } | |
398 } | |
399 | |
400 b = ngx_calloc_buf(ctx->pool); | |
401 if (b == NULL) { | |
402 return NGX_ERROR; | |
403 } | |
404 | |
405 if (ctx->directio) { | |
406 | |
407 /* | |
408 * allocate block aligned to a disk sector size to enable | |
409 * userland buffer direct usage conjunctly with directio | |
410 */ | |
411 | |
412 b->start = ngx_pmemalign(ctx->pool, size, 512); | |
413 if (b->start == NULL) { | |
414 return NGX_ERROR; | |
415 } | |
416 | |
417 } else { | |
418 b->start = ngx_palloc(ctx->pool, size); | |
419 if (b->start == NULL) { | |
420 return NGX_ERROR; | |
421 } | |
422 } | |
423 | |
424 b->pos = b->start; | |
425 b->last = b->start; | |
426 b->end = b->last + size; | |
427 b->temporary = 1; | |
428 b->tag = ctx->tag; | |
429 b->recycled = recycled; | |
430 | |
431 ctx->buf = b; | |
432 ctx->allocated++; | |
433 | |
434 return NGX_OK; | |
435 } | |
436 | |
437 | |
438 static ngx_int_t | |
439 ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx) | |
440 { | |
441 off_t size; | |
442 ssize_t n; | |
443 ngx_buf_t *src, *dst; | |
444 ngx_uint_t sendfile; | |
445 | |
446 src = ctx->in->buf; | |
447 dst = ctx->buf; | |
359 | 448 |
360 size = ngx_buf_size(src); | 449 size = ngx_buf_size(src); |
361 | 450 |
362 if (size > dst->end - dst->pos) { | 451 if (size > dst->end - dst->pos) { |
363 size = dst->end - dst->pos; | 452 size = dst->end - dst->pos; |
364 } | 453 } |
454 | |
455 sendfile = ctx->sendfile & !ctx->directio; | |
365 | 456 |
366 #if (NGX_SENDFILE_LIMIT) | 457 #if (NGX_SENDFILE_LIMIT) |
367 | 458 |
368 if (src->in_file && src->file_pos >= NGX_SENDFILE_LIMIT) { | 459 if (src->in_file && src->file_pos >= NGX_SENDFILE_LIMIT) { |
369 sendfile = 0; | 460 sendfile = 0; |
411 return (ngx_int_t) n; | 502 return (ngx_int_t) n; |
412 } | 503 } |
413 #endif | 504 #endif |
414 | 505 |
415 if (n != size) { | 506 if (n != size) { |
416 ngx_log_error(NGX_LOG_ALERT, src->file->log, 0, | 507 ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, |
417 ngx_read_file_n " read only %z of %O from file", | 508 ngx_read_file_n " read only %z of %O from file", |
418 n, size); | 509 n, size); |
419 if (n == 0) { | 510 if (n == 0) { |
420 return NGX_ERROR; | 511 return NGX_ERROR; |
421 } | 512 } |