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 }