Skip to content

Commit

Permalink
Refactored sendfile() AIO preload.
Browse files Browse the repository at this point in the history
This reduces layering violation and simplifies the logic of AIO preread, since
it's now triggered by the send chain function itself without falling back to
the copy filter.  The context of AIO operation is now stored per file buffer,
which makes it possible to properly handle cases when multiple buffers come
from different locations, each with its own configuration.
  • Loading branch information
VBart committed Feb 11, 2015
1 parent 2b7e167 commit 2b8d6ad
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 119 deletions.
3 changes: 3 additions & 0 deletions src/core/ngx_buf.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ struct ngx_output_chain_ctx_s {
unsigned aio:1;

ngx_output_chain_aio_pt aio_handler;
#if (NGX_HAVE_FILE_AIO)
ssize_t (*aio_preload)(ngx_buf_t *file);
#endif
#endif

off_t alignment;
Expand Down
2 changes: 0 additions & 2 deletions src/core/ngx_connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,7 @@ struct ngx_connection_s {
#endif

#if (NGX_HAVE_AIO_SENDFILE)
unsigned aio_sendfile:1;
unsigned busy_count:2;
ngx_buf_t *busy_sendfile;
#endif

#if (NGX_THREADS)
Expand Down
32 changes: 32 additions & 0 deletions src/core/ngx_output_chain.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@

static ngx_inline ngx_int_t
ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf);
#if (NGX_HAVE_AIO_SENDFILE)
static ngx_int_t ngx_output_chain_aio_setup(ngx_output_chain_ctx_t *ctx,
ngx_file_t *file);
#endif
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,
Expand Down Expand Up @@ -252,6 +256,12 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf)
buf->in_file = 0;
}

#if (NGX_HAVE_AIO_SENDFILE)
if (ctx->aio_preload && buf->in_file) {
(void) ngx_output_chain_aio_setup(ctx, buf->file);
}
#endif

if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) {
return 0;
}
Expand All @@ -264,6 +274,28 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf)
}


#if (NGX_HAVE_AIO_SENDFILE)

static ngx_int_t
ngx_output_chain_aio_setup(ngx_output_chain_ctx_t *ctx, ngx_file_t *file)
{
ngx_event_aio_t *aio;

if (file->aio == NULL && ngx_file_aio_init(file, ctx->pool) != NGX_OK) {
return NGX_ERROR;
}

aio = file->aio;

aio->data = ctx->filter_ctx;
aio->preload_handler = ctx->aio_preload;

return NGX_OK;
}

#endif


static ngx_int_t
ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain,
ngx_chain_t *in)
Expand Down
8 changes: 4 additions & 4 deletions src/event/ngx_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ struct ngx_event_aio_s {
ngx_event_handler_pt handler;
ngx_file_t *file;

#if (NGX_HAVE_AIO_SENDFILE)
ssize_t (*preload_handler)(ngx_buf_t *file);
#endif

ngx_fd_t fd;

#if (NGX_HAVE_EVENTFD)
Expand All @@ -181,10 +185,6 @@ struct ngx_event_aio_s {
size_t nbytes;
#endif

#if (NGX_HAVE_AIO_SENDFILE)
off_t last_offset;
#endif

ngx_aiocb_t aiocb;
ngx_event_t event;
};
Expand Down
99 changes: 36 additions & 63 deletions src/http/ngx_http_copy_filter_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ static void ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx,
ngx_file_t *file);
static void ngx_http_copy_aio_event_handler(ngx_event_t *ev);
#if (NGX_HAVE_AIO_SENDFILE)
static ssize_t ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file);
static void ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev);
#endif
#endif
Expand Down Expand Up @@ -125,7 +126,9 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
ctx->aio_handler = ngx_http_copy_aio_handler;
}
#if (NGX_HAVE_AIO_SENDFILE)
c->aio_sendfile = (clcf->aio == NGX_HTTP_AIO_SENDFILE);
if (clcf->aio == NGX_HTTP_AIO_SENDFILE) {
ctx->aio_preload = ngx_http_copy_aio_sendfile_preload;
}
#endif
}
#endif
Expand All @@ -139,72 +142,19 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
ctx->aio = r->aio;
#endif

for ( ;; ) {
rc = ngx_output_chain(ctx, in);

if (ctx->in == NULL) {
r->buffered &= ~NGX_HTTP_COPY_BUFFERED;

} else {
r->buffered |= NGX_HTTP_COPY_BUFFERED;
}

ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args);

#if (NGX_HAVE_FILE_AIO && NGX_HAVE_AIO_SENDFILE)

if (c->busy_sendfile) {
ssize_t n;
off_t offset;
ngx_file_t *file;
ngx_http_ephemeral_t *e;

if (r->aio) {
c->busy_sendfile = NULL;
return rc;
}

file = c->busy_sendfile->file;
offset = c->busy_sendfile->file_pos;

if (file->aio) {
c->busy_count = (offset == file->aio->last_offset) ?
c->busy_count + 1 : 0;
file->aio->last_offset = offset;

if (c->busy_count > 2) {
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
"sendfile(%V) returned busy again",
&file->name);
c->aio_sendfile = 0;
}
}

c->busy_sendfile = NULL;
e = (ngx_http_ephemeral_t *) &r->uri_start;

n = ngx_file_aio_read(file, &e->aio_preload, 1, offset, r->pool);

if (n > 0) {
in = NULL;
continue;
}
rc = ngx_output_chain(ctx, in);

rc = n;
if (ctx->in == NULL) {
r->buffered &= ~NGX_HTTP_COPY_BUFFERED;

if (rc == NGX_AGAIN) {
file->aio->data = r;
file->aio->handler = ngx_http_copy_aio_sendfile_event_handler;
} else {
r->buffered |= NGX_HTTP_COPY_BUFFERED;
}

r->main->blocked++;
r->aio = 1;
}
}
#endif
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args);

return rc;
}
return rc;
}


Expand Down Expand Up @@ -244,6 +194,29 @@ ngx_http_copy_aio_event_handler(ngx_event_t *ev)

#if (NGX_HAVE_AIO_SENDFILE)

static ssize_t
ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file)
{
ssize_t n;
static u_char buf[1];
ngx_event_aio_t *aio;
ngx_http_request_t *r;

n = ngx_file_aio_read(file->file, buf, 1, file->file_pos, NULL);

if (n == NGX_AGAIN) {
aio = file->file->aio;
aio->handler = ngx_http_copy_aio_sendfile_event_handler;

r = aio->data;
r->main->blocked++;
r->aio = 1;
}

return n;
}


static void
ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev)
{
Expand Down
3 changes: 0 additions & 3 deletions src/http/ngx_http_request.h
Original file line number Diff line number Diff line change
Expand Up @@ -574,9 +574,6 @@ struct ngx_http_request_s {

typedef struct {
ngx_http_posted_request_t terminal_posted_request;
#if (NGX_HAVE_AIO_SENDFILE)
u_char aio_preload;
#endif
} ngx_http_ephemeral_t;


Expand Down
42 changes: 25 additions & 17 deletions src/os/unix/ngx_file_aio_read.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,28 @@ static ssize_t ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio,
static void ngx_file_aio_event_handler(ngx_event_t *ev);


ngx_int_t
ngx_file_aio_init(ngx_file_t *file, ngx_pool_t *pool)
{
ngx_event_aio_t *aio;

aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t));
if (aio == NULL) {
return NGX_ERROR;
}

aio->file = file;
aio->fd = file->fd;
aio->event.data = aio;
aio->event.ready = 1;
aio->event.log = file->log;

file->aio = aio;

return NGX_OK;
}


ssize_t
ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
ngx_pool_t *pool)
Expand All @@ -48,25 +70,11 @@ ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
return ngx_read_file(file, buf, size, offset);
}

aio = file->aio;

if (aio == NULL) {
aio = ngx_pcalloc(pool, sizeof(ngx_event_aio_t));
if (aio == NULL) {
return NGX_ERROR;
}

aio->file = file;
aio->fd = file->fd;
aio->event.data = aio;
aio->event.ready = 1;
aio->event.log = file->log;
#if (NGX_HAVE_AIO_SENDFILE)
aio->last_offset = -1;
#endif
file->aio = aio;
if (file->aio == NULL && ngx_file_aio_init(file, pool) != NGX_OK) {
return NGX_ERROR;
}

aio = file->aio;
ev = &aio->event;

if (!ev->ready) {
Expand Down
1 change: 1 addition & 0 deletions src/os/unix/ngx_files.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ size_t ngx_fs_bsize(u_char *name);

#if (NGX_HAVE_FILE_AIO)

ngx_int_t ngx_file_aio_init(ngx_file_t *file, ngx_pool_t *pool);
ssize_t ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size,
off_t offset, ngx_pool_t *pool);

Expand Down
Loading

0 comments on commit 2b8d6ad

Please sign in to comment.