Mercurial > hg > nginx
comparison src/core/ngx_output_chain.c @ 2231:8564129d49b6
*) handle unaligned file part for directio
*) disable sendfile in directio mode
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Fri, 05 Sep 2008 14:48:47 +0000 |
parents | 25cf039c40bd |
children | a83218b65245 |
comparison
equal
deleted
inserted
replaced
2230:25cf039c40bd | 2231:8564129d49b6 |
---|---|
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_align_file_buf(ngx_output_chain_ctx_t *ctx, | |
25 off_t bsize); | |
24 static ngx_int_t ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, | 26 static ngx_int_t ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, |
25 off_t bsize); | 27 off_t bsize); |
26 static ngx_int_t ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src, | 28 static ngx_int_t ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx); |
27 ngx_uint_t sendfile); | |
28 | 29 |
29 | 30 |
30 ngx_int_t | 31 ngx_int_t |
31 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) |
32 { | 33 { |
48 | 49 |
49 if (in->next == NULL | 50 if (in->next == NULL |
50 #if (NGX_SENDFILE_LIMIT) | 51 #if (NGX_SENDFILE_LIMIT) |
51 && !(in->buf->in_file && in->buf->file_last > NGX_SENDFILE_LIMIT) | 52 && !(in->buf->in_file && in->buf->file_last > NGX_SENDFILE_LIMIT) |
52 #endif | 53 #endif |
53 && !ngx_output_chain_need_to_copy(ctx, in->buf)) | 54 && ngx_output_chain_as_is(ctx, in->buf)) |
54 { | 55 { |
55 return ctx->output_filter(ctx->filter_ctx, in); | 56 return ctx->output_filter(ctx->filter_ctx, in); |
56 } | 57 } |
57 } | 58 } |
58 | 59 |
72 | 73 |
73 while (ctx->in) { | 74 while (ctx->in) { |
74 | 75 |
75 /* | 76 /* |
76 * cycle while there are the ctx->in bufs | 77 * cycle while there are the ctx->in bufs |
77 * or there are the free output bufs to copy in | 78 * and there are the free output bufs to copy in |
78 */ | 79 */ |
79 | 80 |
80 bsize = ngx_buf_size(ctx->in->buf); | 81 bsize = ngx_buf_size(ctx->in->buf); |
81 | 82 |
82 if (bsize == 0 && !ngx_buf_special(ctx->in->buf)) { | 83 if (bsize == 0 && !ngx_buf_special(ctx->in->buf)) { |
99 ctx->in = ctx->in->next; | 100 ctx->in = ctx->in->next; |
100 | 101 |
101 continue; | 102 continue; |
102 } | 103 } |
103 | 104 |
104 if (!ngx_output_chain_need_to_copy(ctx, ctx->in->buf)) { | 105 if (ngx_output_chain_as_is(ctx, ctx->in->buf)) { |
105 | 106 |
106 /* move the chain link to the output chain */ | 107 /* move the chain link to the output chain */ |
107 | 108 |
108 cl = ctx->in; | 109 cl = ctx->in; |
109 ctx->in = cl->next; | 110 ctx->in = cl->next; |
115 continue; | 116 continue; |
116 } | 117 } |
117 | 118 |
118 if (ctx->buf == NULL) { | 119 if (ctx->buf == NULL) { |
119 | 120 |
120 /* get the free buf */ | 121 rc = ngx_output_chain_align_file_buf(ctx, bsize); |
121 | 122 |
122 if (ctx->free) { | 123 if (rc == NGX_ERROR) { |
123 cl = ctx->free; | |
124 ctx->buf = cl->buf; | |
125 ctx->free = cl->next; | |
126 ngx_free_chain(ctx->pool, cl); | |
127 | |
128 } else if (out || ctx->allocated == ctx->bufs.num) { | |
129 | |
130 break; | |
131 | |
132 } else if (ngx_output_chain_get_buf(ctx, bsize) != NGX_OK) { | |
133 return NGX_ERROR; | 124 return NGX_ERROR; |
134 } | 125 } |
135 } | 126 |
136 | 127 if (rc != NGX_OK) { |
137 rc = ngx_output_chain_copy_buf(ctx->buf, ctx->in->buf, | 128 |
138 ctx->sendfile); | 129 if (ctx->free) { |
130 | |
131 /* get the free buf */ | |
132 | |
133 cl = ctx->free; | |
134 ctx->buf = cl->buf; | |
135 ctx->free = cl->next; | |
136 | |
137 ngx_free_chain(ctx->pool, cl); | |
138 | |
139 } else if (out || ctx->allocated == ctx->bufs.num) { | |
140 | |
141 break; | |
142 | |
143 } else if (ngx_output_chain_get_buf(ctx, bsize) != NGX_OK) { | |
144 return NGX_ERROR; | |
145 } | |
146 } | |
147 } | |
148 | |
149 rc = ngx_output_chain_copy_buf(ctx); | |
139 | 150 |
140 if (rc == NGX_ERROR) { | 151 if (rc == NGX_ERROR) { |
141 return rc; | 152 return rc; |
142 } | 153 } |
143 | 154 |
187 } | 198 } |
188 } | 199 } |
189 | 200 |
190 | 201 |
191 static ngx_inline ngx_int_t | 202 static ngx_inline ngx_int_t |
192 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) |
193 { | 204 { |
194 ngx_uint_t sendfile; | 205 ngx_uint_t sendfile; |
195 | 206 |
196 if (ngx_buf_special(buf)) { | 207 if (ngx_buf_special(buf)) { |
208 return 1; | |
209 } | |
210 | |
211 if (buf->in_file && buf->file->directio) { | |
197 return 0; | 212 return 0; |
198 } | 213 } |
199 | 214 |
200 sendfile = ctx->sendfile; | 215 sendfile = ctx->sendfile; |
201 | 216 |
208 #endif | 223 #endif |
209 | 224 |
210 if (!sendfile) { | 225 if (!sendfile) { |
211 | 226 |
212 if (!ngx_buf_in_memory(buf)) { | 227 if (!ngx_buf_in_memory(buf)) { |
213 return 1; | 228 return 0; |
214 } | 229 } |
215 | 230 |
216 buf->in_file = 0; | 231 buf->in_file = 0; |
217 } | 232 } |
218 | 233 |
219 if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) { | 234 if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) { |
220 return 1; | 235 return 0; |
221 } | 236 } |
222 | 237 |
223 if (ctx->need_in_temp && (buf->memory || buf->mmap)) { | 238 if (ctx->need_in_temp && (buf->memory || buf->mmap)) { |
224 return 1; | 239 return 0; |
225 } | 240 } |
226 | 241 |
227 return 0; | 242 return 1; |
228 } | 243 } |
229 | 244 |
230 | 245 |
231 static ngx_int_t | 246 static ngx_int_t |
232 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, |
256 | 271 |
257 if (buf->in_file | 272 if (buf->in_file |
258 && buf->file_pos < NGX_SENDFILE_LIMIT | 273 && buf->file_pos < NGX_SENDFILE_LIMIT |
259 && buf->file_last > NGX_SENDFILE_LIMIT) | 274 && buf->file_last > NGX_SENDFILE_LIMIT) |
260 { | 275 { |
276 /* split a file buf on two bufs by the sendfile limit */ | |
277 | |
261 b = ngx_calloc_buf(pool); | 278 b = ngx_calloc_buf(pool); |
262 if (b == NULL) { | 279 if (b == NULL) { |
263 return NGX_ERROR; | 280 return NGX_ERROR; |
264 } | 281 } |
265 | 282 |
289 *ll = cl; | 306 *ll = cl; |
290 ll = &cl->next; | 307 ll = &cl->next; |
291 } | 308 } |
292 | 309 |
293 *ll = NULL; | 310 *ll = NULL; |
311 | |
312 return NGX_OK; | |
313 } | |
314 | |
315 | |
316 static ngx_int_t | |
317 ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, off_t bsize) | |
318 { | |
319 size_t size; | |
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 */ | |
294 | 357 |
295 return NGX_OK; | 358 return NGX_OK; |
296 } | 359 } |
297 | 360 |
298 | 361 |
299 static ngx_int_t | 362 static ngx_int_t |
300 ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize) | 363 ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize) |
301 { | 364 { |
302 size_t size; | 365 size_t size; |
303 ngx_buf_t *b; | 366 ngx_buf_t *b, *in; |
304 ngx_uint_t recycled; | 367 ngx_uint_t recycled; |
305 | 368 |
369 in = ctx->in->buf; | |
306 size = ctx->bufs.size; | 370 size = ctx->bufs.size; |
307 recycled = 1; | 371 recycled = 1; |
308 | 372 |
309 if (ctx->in->buf->last_in_chain) { | 373 if (in->last_in_chain) { |
310 | 374 |
311 if (bsize < (off_t) size) { | 375 if (bsize < (off_t) size) { |
312 | 376 |
313 /* | 377 /* |
314 * allocate a small temp buf for a small last buf | 378 * allocate a small temp buf for a small last buf |
315 * or its small last part | 379 * or its small last part |
316 */ | 380 */ |
317 | 381 |
318 size = (size_t) bsize; | 382 size = (size_t) bsize; |
319 recycled = 0; | 383 recycled = 0; |
320 | 384 |
321 } else if (ctx->bufs.num == 1 && (bsize < (off_t) (size + size / 4))) { | 385 } else if (!ctx->directio |
322 | 386 && ctx->bufs.num == 1 |
387 && (bsize < (off_t) (size + size / 4))) | |
388 { | |
323 /* | 389 /* |
324 * allocate a temp buf that equals to a last buf, if the last buf | 390 * allocate a temp buf that equals to a last buf, |
325 * size is lesser than 1.25 of bufs.size and the temp buf is single | 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 | |
326 */ | 393 */ |
327 | 394 |
328 size = (size_t) bsize; | 395 size = (size_t) bsize; |
329 recycled = 0; | 396 recycled = 0; |
330 } | 397 } |
333 b = ngx_calloc_buf(ctx->pool); | 400 b = ngx_calloc_buf(ctx->pool); |
334 if (b == NULL) { | 401 if (b == NULL) { |
335 return NGX_ERROR; | 402 return NGX_ERROR; |
336 } | 403 } |
337 | 404 |
338 /* allocate block aligned to a disk sector size to enable O_DIRECT */ | 405 if (ctx->directio) { |
339 | 406 |
340 b->start = ngx_pmemalign(ctx->pool, size, 512); | 407 /* |
341 if (b->start == NULL) { | 408 * allocate block aligned to a disk sector size to enable |
342 return NGX_ERROR; | 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 } | |
343 } | 422 } |
344 | 423 |
345 b->pos = b->start; | 424 b->pos = b->start; |
346 b->last = b->start; | 425 b->last = b->start; |
347 b->end = b->last + size; | 426 b->end = b->last + size; |
355 return NGX_OK; | 434 return NGX_OK; |
356 } | 435 } |
357 | 436 |
358 | 437 |
359 static ngx_int_t | 438 static ngx_int_t |
360 ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src, ngx_uint_t sendfile) | 439 ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx) |
361 { | 440 { |
362 off_t size; | 441 off_t size; |
363 ssize_t n; | 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; | |
364 | 448 |
365 size = ngx_buf_size(src); | 449 size = ngx_buf_size(src); |
366 | 450 |
367 if (size > dst->end - dst->pos) { | 451 if (size > dst->end - dst->pos) { |
368 size = dst->end - dst->pos; | 452 size = dst->end - dst->pos; |
369 } | 453 } |
454 | |
455 sendfile = ctx->sendfile & !ctx->directio; | |
370 | 456 |
371 #if (NGX_SENDFILE_LIMIT) | 457 #if (NGX_SENDFILE_LIMIT) |
372 | 458 |
373 if (src->in_file && src->file_pos >= NGX_SENDFILE_LIMIT) { | 459 if (src->in_file && src->file_pos >= NGX_SENDFILE_LIMIT) { |
374 sendfile = 0; | 460 sendfile = 0; |
416 return (ngx_int_t) n; | 502 return (ngx_int_t) n; |
417 } | 503 } |
418 #endif | 504 #endif |
419 | 505 |
420 if (n != size) { | 506 if (n != size) { |
421 ngx_log_error(NGX_LOG_ALERT, src->file->log, 0, | 507 ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, |
422 ngx_read_file_n " read only %z of %O from file", | 508 ngx_read_file_n " read only %z of %O from file", |
423 n, size); | 509 n, size); |
424 if (n == 0) { | 510 if (n == 0) { |
425 return NGX_ERROR; | 511 return NGX_ERROR; |
426 } | 512 } |