*) handle unaligned file part for directio
*) disable sendfile in directio mode
This commit is contained in:
parent
ef78cf29da
commit
7e50cdf90d
9 changed files with 140 additions and 44 deletions
|
@ -78,6 +78,7 @@ typedef struct {
|
||||||
ngx_chain_t *busy;
|
ngx_chain_t *busy;
|
||||||
|
|
||||||
unsigned sendfile;
|
unsigned sendfile;
|
||||||
|
unsigned directio;
|
||||||
unsigned need_in_memory;
|
unsigned need_in_memory;
|
||||||
unsigned need_in_temp;
|
unsigned need_in_temp;
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,8 @@ struct ngx_file_s {
|
||||||
|
|
||||||
ngx_log_t *log;
|
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
|
#define NGX_MAX_PATH_LEVEL 3
|
||||||
|
|
|
@ -502,6 +502,9 @@ ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, ngx_log_t *log)
|
||||||
if (ngx_directio(fd) == -1) {
|
if (ngx_directio(fd) == -1) {
|
||||||
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
|
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
|
||||||
ngx_directio_n " \"%s\" failed", name);
|
ngx_directio_n " \"%s\" failed", name);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
of->is_directio = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ typedef struct {
|
||||||
unsigned is_file:1;
|
unsigned is_file:1;
|
||||||
unsigned is_link:1;
|
unsigned is_link:1;
|
||||||
unsigned is_exec:1;
|
unsigned is_exec:1;
|
||||||
|
unsigned is_directio:1;
|
||||||
} ngx_open_file_info_t;
|
} ngx_open_file_info_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,13 +18,14 @@
|
||||||
|
|
||||||
|
|
||||||
static ngx_inline ngx_int_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);
|
||||||
static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool,
|
static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool,
|
||||||
ngx_chain_t **chain, ngx_chain_t *in);
|
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,
|
static ngx_int_t ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx,
|
||||||
off_t bsize);
|
off_t bsize);
|
||||||
static ngx_int_t ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src,
|
static ngx_int_t ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx);
|
||||||
ngx_uint_t sendfile);
|
|
||||||
|
|
||||||
|
|
||||||
ngx_int_t
|
ngx_int_t
|
||||||
|
@ -50,7 +51,7 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
|
||||||
#if (NGX_SENDFILE_LIMIT)
|
#if (NGX_SENDFILE_LIMIT)
|
||||||
&& !(in->buf->in_file && in->buf->file_last > NGX_SENDFILE_LIMIT)
|
&& !(in->buf->in_file && in->buf->file_last > NGX_SENDFILE_LIMIT)
|
||||||
#endif
|
#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);
|
return ctx->output_filter(ctx->filter_ctx, in);
|
||||||
}
|
}
|
||||||
|
@ -74,7 +75,7 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* cycle while there are the ctx->in bufs
|
* 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);
|
bsize = ngx_buf_size(ctx->in->buf);
|
||||||
|
@ -101,7 +102,7 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
|
||||||
continue;
|
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 */
|
/* move the chain link to the output chain */
|
||||||
|
|
||||||
|
@ -117,12 +118,22 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
|
||||||
|
|
||||||
if (ctx->buf == NULL) {
|
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) {
|
if (ctx->free) {
|
||||||
|
|
||||||
|
/* get the free buf */
|
||||||
|
|
||||||
cl = ctx->free;
|
cl = ctx->free;
|
||||||
ctx->buf = cl->buf;
|
ctx->buf = cl->buf;
|
||||||
ctx->free = cl->next;
|
ctx->free = cl->next;
|
||||||
|
|
||||||
ngx_free_chain(ctx->pool, cl);
|
ngx_free_chain(ctx->pool, cl);
|
||||||
|
|
||||||
} else if (out || ctx->allocated == ctx->bufs.num) {
|
} else if (out || ctx->allocated == ctx->bufs.num) {
|
||||||
|
@ -133,9 +144,9 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rc = ngx_output_chain_copy_buf(ctx->buf, ctx->in->buf,
|
rc = ngx_output_chain_copy_buf(ctx);
|
||||||
ctx->sendfile);
|
|
||||||
|
|
||||||
if (rc == NGX_ERROR) {
|
if (rc == NGX_ERROR) {
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -189,11 +200,15 @@ ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
|
||||||
|
|
||||||
|
|
||||||
static ngx_inline ngx_int_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;
|
ngx_uint_t sendfile;
|
||||||
|
|
||||||
if (ngx_buf_special(buf)) {
|
if (ngx_buf_special(buf)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf->in_file && buf->file->directio) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,21 +225,21 @@ ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf)
|
||||||
if (!sendfile) {
|
if (!sendfile) {
|
||||||
|
|
||||||
if (!ngx_buf_in_memory(buf)) {
|
if (!ngx_buf_in_memory(buf)) {
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf->in_file = 0;
|
buf->in_file = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) {
|
if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) {
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->need_in_temp && (buf->memory || buf->mmap)) {
|
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 *pool, ngx_chain_t **chain,
|
||||||
&& buf->file_pos < NGX_SENDFILE_LIMIT
|
&& buf->file_pos < NGX_SENDFILE_LIMIT
|
||||||
&& buf->file_last > 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);
|
b = ngx_calloc_buf(pool);
|
||||||
if (b == NULL) {
|
if (b == NULL) {
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
|
@ -296,17 +313,64 @@ ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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
|
static ngx_int_t
|
||||||
ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize)
|
ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize)
|
||||||
{
|
{
|
||||||
size_t size;
|
size_t size;
|
||||||
ngx_buf_t *b;
|
ngx_buf_t *b, *in;
|
||||||
ngx_uint_t recycled;
|
ngx_uint_t recycled;
|
||||||
|
|
||||||
|
in = ctx->in->buf;
|
||||||
size = ctx->bufs.size;
|
size = ctx->bufs.size;
|
||||||
recycled = 1;
|
recycled = 1;
|
||||||
|
|
||||||
if (ctx->in->buf->last_in_chain) {
|
if (in->last_in_chain) {
|
||||||
|
|
||||||
if (bsize < (off_t) size) {
|
if (bsize < (off_t) size) {
|
||||||
|
|
||||||
|
@ -318,11 +382,14 @@ ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize)
|
||||||
size = (size_t) bsize;
|
size = (size_t) bsize;
|
||||||
recycled = 0;
|
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
|
* allocate a temp buf that equals to a last buf,
|
||||||
* size is lesser than 1.25 of bufs.size and the temp buf is single
|
* 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;
|
size = (size_t) bsize;
|
||||||
|
@ -335,13 +402,25 @@ ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize)
|
||||||
return NGX_ERROR;
|
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);
|
b->start = ngx_pmemalign(ctx->pool, size, 512);
|
||||||
if (b->start == NULL) {
|
if (b->start == NULL) {
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
b->start = ngx_palloc(ctx->pool, size);
|
||||||
|
if (b->start == NULL) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
b->pos = b->start;
|
b->pos = b->start;
|
||||||
b->last = b->start;
|
b->last = b->start;
|
||||||
b->end = b->last + size;
|
b->end = b->last + size;
|
||||||
|
@ -357,10 +436,15 @@ ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize)
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
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;
|
off_t size;
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
|
ngx_buf_t *src, *dst;
|
||||||
|
ngx_uint_t sendfile;
|
||||||
|
|
||||||
|
src = ctx->in->buf;
|
||||||
|
dst = ctx->buf;
|
||||||
|
|
||||||
size = ngx_buf_size(src);
|
size = ngx_buf_size(src);
|
||||||
|
|
||||||
|
@ -368,6 +452,8 @@ ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src, ngx_uint_t sendfile)
|
||||||
size = dst->end - dst->pos;
|
size = dst->end - dst->pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendfile = ctx->sendfile & !ctx->directio;
|
||||||
|
|
||||||
#if (NGX_SENDFILE_LIMIT)
|
#if (NGX_SENDFILE_LIMIT)
|
||||||
|
|
||||||
if (src->in_file && src->file_pos >= 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, ngx_buf_t *src, ngx_uint_t sendfile)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (n != size) {
|
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",
|
ngx_read_file_n " read only %z of %O from file",
|
||||||
n, size);
|
n, size);
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
|
|
|
@ -244,6 +244,7 @@ ngx_http_flv_handler(ngx_http_request_t *r)
|
||||||
b->file->fd = of.fd;
|
b->file->fd = of.fd;
|
||||||
b->file->name = path;
|
b->file->name = path;
|
||||||
b->file->log = log;
|
b->file->log = log;
|
||||||
|
b->file->directio = of.is_directio;
|
||||||
|
|
||||||
out[1].buf = b;
|
out[1].buf = b;
|
||||||
out[1].next = NULL;
|
out[1].next = NULL;
|
||||||
|
|
|
@ -235,6 +235,7 @@ ngx_http_gzip_static_handler(ngx_http_request_t *r)
|
||||||
b->file->fd = of.fd;
|
b->file->fd = of.fd;
|
||||||
b->file->name = path;
|
b->file->name = path;
|
||||||
b->file->log = log;
|
b->file->log = log;
|
||||||
|
b->file->directio = of.is_directio;
|
||||||
|
|
||||||
out.buf = b;
|
out.buf = b;
|
||||||
out.next = NULL;
|
out.next = NULL;
|
||||||
|
|
|
@ -251,6 +251,7 @@ ngx_http_static_handler(ngx_http_request_t *r)
|
||||||
b->file->fd = of.fd;
|
b->file->fd = of.fd;
|
||||||
b->file->name = path;
|
b->file->name = path;
|
||||||
b->file->log = log;
|
b->file->log = log;
|
||||||
|
b->file->directio = of.is_directio;
|
||||||
|
|
||||||
out.buf = b;
|
out.buf = b;
|
||||||
out.next = NULL;
|
out.next = NULL;
|
||||||
|
|
|
@ -681,6 +681,7 @@ sendfile(r, filename, offset = -1, bytes = 0)
|
||||||
|
|
||||||
b->file->fd = of.fd;
|
b->file->fd = of.fd;
|
||||||
b->file->log = r->connection->log;
|
b->file->log = r->connection->log;
|
||||||
|
b->file->directio = of.is_directio;
|
||||||
|
|
||||||
(void) ngx_http_perl_output(r, b);
|
(void) ngx_http_perl_output(r, b);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue