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 }