changeset 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 992613253d93
files src/core/ngx_buf.h src/core/ngx_file.h src/core/ngx_open_file_cache.c src/core/ngx_open_file_cache.h src/core/ngx_output_chain.c src/http/modules/ngx_http_flv_module.c src/http/modules/ngx_http_gzip_static_module.c src/http/modules/ngx_http_static_module.c src/http/modules/perl/nginx.xs
diffstat 9 files changed, 139 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/ngx_buf.h
+++ b/src/core/ngx_buf.h
@@ -78,6 +78,7 @@ typedef struct {
     ngx_chain_t                 *busy;
 
     unsigned                     sendfile;
+    unsigned                     directio;
     unsigned                     need_in_memory;
     unsigned                     need_in_temp;
 
--- a/src/core/ngx_file.h
+++ b/src/core/ngx_file.h
@@ -26,7 +26,8 @@ struct ngx_file_s {
 
     ngx_log_t          *log;
 
-    ngx_uint_t          valid_info;  /* unsigned  valid_info:1; */
+    unsigned            valid_info:1;
+    unsigned            directio:1;
 };
 
 #define NGX_MAX_PATH_LEVEL  3
--- a/src/core/ngx_open_file_cache.c
+++ b/src/core/ngx_open_file_cache.c
@@ -502,6 +502,9 @@ ngx_open_and_stat_file(u_char *name, ngx
             if (ngx_directio(fd) == -1) {
                 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                               ngx_directio_n " \"%s\" failed", name);
+
+            } else {
+                of->is_directio = 1;
             }
         }
     }
--- a/src/core/ngx_open_file_cache.h
+++ b/src/core/ngx_open_file_cache.h
@@ -33,6 +33,7 @@ typedef struct {
     unsigned                 is_file:1;
     unsigned                 is_link:1;
     unsigned                 is_exec:1;
+    unsigned                 is_directio:1;
 } ngx_open_file_info_t;
 
 
--- a/src/core/ngx_output_chain.c
+++ b/src/core/ngx_output_chain.c
@@ -18,13 +18,14 @@
 
 
 static ngx_inline ngx_int_t
-    ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf);
+    ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf);
 static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool,
     ngx_chain_t **chain, ngx_chain_t *in);
+static ngx_int_t ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx,
+    off_t bsize);
 static ngx_int_t ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx,
     off_t bsize);
-static ngx_int_t ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src,
-    ngx_uint_t sendfile);
+static ngx_int_t ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx);
 
 
 ngx_int_t
@@ -50,7 +51,7 @@ ngx_output_chain(ngx_output_chain_ctx_t 
 #if (NGX_SENDFILE_LIMIT)
             && !(in->buf->in_file && in->buf->file_last > NGX_SENDFILE_LIMIT)
 #endif
-            && !ngx_output_chain_need_to_copy(ctx, in->buf))
+            && ngx_output_chain_as_is(ctx, in->buf))
         {
             return ctx->output_filter(ctx->filter_ctx, in);
         }
@@ -74,7 +75,7 @@ ngx_output_chain(ngx_output_chain_ctx_t 
 
             /*
              * cycle while there are the ctx->in bufs
-             * or there are the free output bufs to copy in
+             * and there are the free output bufs to copy in
              */
 
             bsize = ngx_buf_size(ctx->in->buf);
@@ -101,7 +102,7 @@ ngx_output_chain(ngx_output_chain_ctx_t 
                 continue;
             }
 
-            if (!ngx_output_chain_need_to_copy(ctx, ctx->in->buf)) {
+            if (ngx_output_chain_as_is(ctx, ctx->in->buf)) {
 
                 /* move the chain link to the output chain */
 
@@ -117,25 +118,35 @@ ngx_output_chain(ngx_output_chain_ctx_t 
 
             if (ctx->buf == NULL) {
 
-                /* get the free buf */
+                rc = ngx_output_chain_align_file_buf(ctx, bsize);
+
+                if (rc == NGX_ERROR) {
+                    return NGX_ERROR;
+                }
+
+                if (rc != NGX_OK) {
+
+                    if (ctx->free) {
+
+                        /* get the free buf */
 
-                if (ctx->free) {
-                    cl = ctx->free;
-                    ctx->buf = cl->buf;
-                    ctx->free = cl->next;
-                    ngx_free_chain(ctx->pool, cl);
+                        cl = ctx->free;
+                        ctx->buf = cl->buf;
+                        ctx->free = cl->next;
+
+                        ngx_free_chain(ctx->pool, cl);
 
-                } else if (out || ctx->allocated == ctx->bufs.num) {
+                    } else if (out || ctx->allocated == ctx->bufs.num) {
+
+                        break;
 
-                    break;
-
-                } else if (ngx_output_chain_get_buf(ctx, bsize) != NGX_OK) {
-                    return NGX_ERROR;
+                    } else if (ngx_output_chain_get_buf(ctx, bsize) != NGX_OK) {
+                        return NGX_ERROR;
+                    }
                 }
             }
 
-            rc = ngx_output_chain_copy_buf(ctx->buf, ctx->in->buf,
-                                           ctx->sendfile);
+            rc = ngx_output_chain_copy_buf(ctx);
 
             if (rc == NGX_ERROR) {
                 return rc;
@@ -189,11 +200,15 @@ ngx_output_chain(ngx_output_chain_ctx_t 
 
 
 static ngx_inline ngx_int_t
-ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf)
+ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf)
 {
     ngx_uint_t  sendfile;
 
     if (ngx_buf_special(buf)) {
+        return 1;
+    }
+
+    if (buf->in_file && buf->file->directio) {
         return 0;
     }
 
@@ -210,21 +225,21 @@ ngx_output_chain_need_to_copy(ngx_output
     if (!sendfile) {
 
         if (!ngx_buf_in_memory(buf)) {
-            return 1;
+            return 0;
         }
 
         buf->in_file = 0;
     }
 
     if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) {
-        return 1;
+        return 0;
     }
 
     if (ctx->need_in_temp && (buf->memory || buf->mmap)) {
-        return 1;
+        return 0;
     }
 
-    return 0;
+    return 1;
 }
 
 
@@ -258,6 +273,8 @@ ngx_output_chain_add_copy(ngx_pool_t *po
             && buf->file_pos < NGX_SENDFILE_LIMIT
             && buf->file_last > NGX_SENDFILE_LIMIT)
         {
+            /* split a file buf on two bufs by the sendfile limit */
+
             b = ngx_calloc_buf(pool);
             if (b == NULL) {
                 return NGX_ERROR;
@@ -297,32 +314,82 @@ ngx_output_chain_add_copy(ngx_pool_t *po
 
 
 static ngx_int_t
+ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, off_t bsize)
+{
+    size_t      size;
+    ngx_buf_t  *in;
+
+    in = ctx->in->buf;
+
+    if (in->file == NULL || !in->file->directio) {
+        return NGX_DECLINED;
+    }
+
+    ctx->directio = 1;
+
+    size = (size_t) (in->file_pos - (in->file_pos & ~511));
+
+    if (size == 0) {
+
+        if (bsize >= ctx->bufs.size) {
+            return NGX_DECLINED;
+        }
+
+        size = (size_t) bsize;
+
+    } else {
+        size = 512 - size;
+
+        if (size > bsize) {
+            size = (size_t) bsize;
+        }
+    }
+
+    ctx->buf = ngx_create_temp_buf(ctx->pool, size);
+    if (ctx->buf == NULL) {
+        return NGX_ERROR;
+    }
+
+    /*
+     * we do not set ctx->buf->tag, because we do not want
+     * to reuse the buf via ctx->free list
+     */
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
 ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize)
 {
     size_t       size;
-    ngx_buf_t   *b;
+    ngx_buf_t   *b, *in;
     ngx_uint_t   recycled;
 
+    in = ctx->in->buf;
     size = ctx->bufs.size;
     recycled = 1;
 
-    if (ctx->in->buf->last_in_chain) {
+    if (in->last_in_chain) {
 
         if (bsize < (off_t) size) {
 
-           /*
-            * allocate a small temp buf for a small last buf
-            * or its small last part
-            */
+            /*
+             * allocate a small temp buf for a small last buf
+             * or its small last part
+             */
 
             size = (size_t) bsize;
             recycled = 0;
 
-        } else if (ctx->bufs.num == 1 && (bsize < (off_t) (size + size / 4))) {
-
+        } else if (!ctx->directio
+                   && ctx->bufs.num == 1
+                   && (bsize < (off_t) (size + size / 4)))
+        {
             /*
-             * allocate a temp buf that equals to a last buf, if the last buf
-             * size is lesser than 1.25 of bufs.size and the temp buf is single
+             * allocate a temp buf that equals to a last buf,
+             * if there is no directio, the last buf size is lesser
+             * than 1.25 of bufs.size and the temp buf is single
              */
 
             size = (size_t) bsize;
@@ -335,11 +402,23 @@ ngx_output_chain_get_buf(ngx_output_chai
         return NGX_ERROR;
     }
 
-    /* allocate block aligned to a disk sector size to enable O_DIRECT */
+    if (ctx->directio) {
+
+        /*
+         * allocate block aligned to a disk sector size to enable
+         * userland buffer direct usage conjunctly with directio
+         */
 
-    b->start = ngx_pmemalign(ctx->pool, size, 512);
-    if (b->start == NULL) {
-        return NGX_ERROR;
+        b->start = ngx_pmemalign(ctx->pool, size, 512);
+        if (b->start == NULL) {
+            return NGX_ERROR;
+        }
+
+    } else {
+        b->start = ngx_palloc(ctx->pool, size);
+        if (b->start == NULL) {
+            return NGX_ERROR;
+        }
     }
 
     b->pos = b->start;
@@ -357,10 +436,15 @@ ngx_output_chain_get_buf(ngx_output_chai
 
 
 static ngx_int_t
-ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src, ngx_uint_t sendfile)
+ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx)
 {
-    off_t    size;
-    ssize_t  n;
+    off_t        size;
+    ssize_t      n;
+    ngx_buf_t   *src, *dst;
+    ngx_uint_t   sendfile;
+
+    src = ctx->in->buf;
+    dst = ctx->buf;
 
     size = ngx_buf_size(src);
 
@@ -368,6 +452,8 @@ ngx_output_chain_copy_buf(ngx_buf_t *dst
         size = dst->end - dst->pos;
     }
 
+    sendfile = ctx->sendfile & !ctx->directio;
+
 #if (NGX_SENDFILE_LIMIT)
 
     if (src->in_file && src->file_pos >= NGX_SENDFILE_LIMIT) {
@@ -418,7 +504,7 @@ ngx_output_chain_copy_buf(ngx_buf_t *dst
 #endif
 
         if (n != size) {
-            ngx_log_error(NGX_LOG_ALERT, src->file->log, 0,
+            ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
                           ngx_read_file_n " read only %z of %O from file",
                           n, size);
             if (n == 0) {
--- a/src/http/modules/ngx_http_flv_module.c
+++ b/src/http/modules/ngx_http_flv_module.c
@@ -244,6 +244,7 @@ ngx_http_flv_handler(ngx_http_request_t 
     b->file->fd = of.fd;
     b->file->name = path;
     b->file->log = log;
+    b->file->directio = of.is_directio;
 
     out[1].buf = b;
     out[1].next = NULL;
--- a/src/http/modules/ngx_http_gzip_static_module.c
+++ b/src/http/modules/ngx_http_gzip_static_module.c
@@ -235,6 +235,7 @@ ngx_http_gzip_static_handler(ngx_http_re
     b->file->fd = of.fd;
     b->file->name = path;
     b->file->log = log;
+    b->file->directio = of.is_directio;
 
     out.buf = b;
     out.next = NULL;
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -251,6 +251,7 @@ ngx_http_static_handler(ngx_http_request
     b->file->fd = of.fd;
     b->file->name = path;
     b->file->log = log;
+    b->file->directio = of.is_directio;
 
     out.buf = b;
     out.next = NULL;
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -681,6 +681,7 @@ sendfile(r, filename, offset = -1, bytes
 
     b->file->fd = of.fd;
     b->file->log = r->connection->log;
+    b->file->directio = of.is_directio;
 
     (void) ngx_http_perl_output(r, b);