FreeBSD and Linux AIO support
This commit is contained in:
parent
1f2d427a5a
commit
6ae55a7a8f
26 changed files with 958 additions and 82 deletions
|
@ -41,6 +41,7 @@ fi
|
||||||
|
|
||||||
if [ $NGX_TEST_BUILD_EPOLL = YES ]; then
|
if [ $NGX_TEST_BUILD_EPOLL = YES ]; then
|
||||||
have=NGX_HAVE_EPOLL . auto/have
|
have=NGX_HAVE_EPOLL . auto/have
|
||||||
|
have=NGX_HAVE_EVENTFD . auto/have
|
||||||
have=NGX_TEST_BUILD_EPOLL . auto/have
|
have=NGX_TEST_BUILD_EPOLL . auto/have
|
||||||
EVENT_MODULES="$EVENT_MODULES $EPOLL_MODULE"
|
EVENT_MODULES="$EVENT_MODULES $EPOLL_MODULE"
|
||||||
CORE_SRCS="$CORE_SRCS $EPOLL_SRCS"
|
CORE_SRCS="$CORE_SRCS $EPOLL_SRCS"
|
||||||
|
|
|
@ -43,6 +43,7 @@ EVENT_AIO=NO
|
||||||
|
|
||||||
USE_THREADS=NO
|
USE_THREADS=NO
|
||||||
|
|
||||||
|
NGX_FILE_AIO=NO
|
||||||
NGX_IPV6=NO
|
NGX_IPV6=NO
|
||||||
|
|
||||||
HTTP=YES
|
HTTP=YES
|
||||||
|
@ -170,6 +171,7 @@ do
|
||||||
#--with-threads=*) USE_THREADS="$value" ;;
|
#--with-threads=*) USE_THREADS="$value" ;;
|
||||||
#--with-threads) USE_THREADS="pthreads" ;;
|
#--with-threads) USE_THREADS="pthreads" ;;
|
||||||
|
|
||||||
|
--with-file-aio) NGX_FILE_AIO=YES ;;
|
||||||
--with-ipv6) NGX_IPV6=YES ;;
|
--with-ipv6) NGX_IPV6=YES ;;
|
||||||
|
|
||||||
--without-http) HTTP=NO ;;
|
--without-http) HTTP=NO ;;
|
||||||
|
@ -305,6 +307,7 @@ cat << END
|
||||||
--with-poll_module enable poll module
|
--with-poll_module enable poll module
|
||||||
--without-poll_module disable poll module
|
--without-poll_module disable poll module
|
||||||
|
|
||||||
|
--with-file-aio enable file aio support
|
||||||
--with-ipv6 enable ipv6 support
|
--with-ipv6 enable ipv6 support
|
||||||
|
|
||||||
--with-http_ssl_module enable ngx_http_ssl_module
|
--with-http_ssl_module enable ngx_http_ssl_module
|
||||||
|
|
|
@ -274,3 +274,43 @@ if [ $ngx_found != yes ]; then
|
||||||
CORE_LIBS="$CORE_LIBS -lrt"
|
CORE_LIBS="$CORE_LIBS -lrt"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if [ $NGX_FILE_AIO = YES ]; then
|
||||||
|
ngx_feature="kqueue AIO support"
|
||||||
|
ngx_feature_name="NGX_HAVE_FILE_AIO"
|
||||||
|
ngx_feature_run=no
|
||||||
|
ngx_feature_incs="#include <aio.h>"
|
||||||
|
ngx_feature_path=
|
||||||
|
ngx_feature_libs=
|
||||||
|
ngx_feature_test="int n; struct aiocb iocb;
|
||||||
|
iocb.aio_sigevent.sigev_notify = SIGEV_KEVENT;
|
||||||
|
n = aio_read(&iocb)"
|
||||||
|
. auto/feature
|
||||||
|
|
||||||
|
if [ $ngx_found = yes ]; then
|
||||||
|
CORE_SRCS="$CORE_SRCS $FILE_AIO_SRCS"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if [ $NGX_FILE_AIO = YES ]; then
|
||||||
|
ngx_feature="Linux AIO support"
|
||||||
|
ngx_feature_name="NGX_HAVE_FILE_AIO"
|
||||||
|
ngx_feature_run=no
|
||||||
|
ngx_feature_incs="#include <linux/aio_abi.h>
|
||||||
|
#include <sys/syscall.h>"
|
||||||
|
ngx_feature_path=
|
||||||
|
ngx_feature_libs=
|
||||||
|
ngx_feature_test="int n = SYS_eventfd;
|
||||||
|
struct iocb iocb;
|
||||||
|
iocb.aio_lio_opcode = IOCB_CMD_PREAD;
|
||||||
|
iocb.aio_flags = IOCB_FLAG_RESFD;
|
||||||
|
iocb.aio_resfd = -1;"
|
||||||
|
. auto/feature
|
||||||
|
|
||||||
|
if [ $ngx_found = yes ]; then
|
||||||
|
have=NGX_HAVE_EVENTFD . auto/have
|
||||||
|
CORE_SRCS="$CORE_SRCS $LINUX_AIO_SRCS"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
|
@ -125,6 +125,8 @@ AIO_SRCS="src/event/modules/ngx_aio_module.c \
|
||||||
src/os/unix/ngx_aio_read_chain.c \
|
src/os/unix/ngx_aio_read_chain.c \
|
||||||
src/os/unix/ngx_aio_write_chain.c"
|
src/os/unix/ngx_aio_write_chain.c"
|
||||||
|
|
||||||
|
FILE_AIO_SRCS="src/os/unix/ngx_file_aio_read.c"
|
||||||
|
LINUX_AIO_SRCS="src/os/unix/ngx_linux_aio_read.c"
|
||||||
|
|
||||||
UNIX_INCS="$CORE_INCS $EVENT_INCS src/os/unix"
|
UNIX_INCS="$CORE_INCS $EVENT_INCS src/os/unix"
|
||||||
|
|
||||||
|
|
|
@ -67,9 +67,16 @@ typedef struct {
|
||||||
} ngx_bufs_t;
|
} ngx_bufs_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct ngx_output_chain_ctx_s ngx_output_chain_ctx_t;
|
||||||
|
|
||||||
typedef ngx_int_t (*ngx_output_chain_filter_pt)(void *ctx, ngx_chain_t *in);
|
typedef ngx_int_t (*ngx_output_chain_filter_pt)(void *ctx, ngx_chain_t *in);
|
||||||
|
|
||||||
typedef struct {
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
typedef void (*ngx_output_chain_aio_pt)(ngx_output_chain_ctx_t *ctx,
|
||||||
|
ngx_file_t *file);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct ngx_output_chain_ctx_s {
|
||||||
ngx_buf_t *buf;
|
ngx_buf_t *buf;
|
||||||
ngx_chain_t *in;
|
ngx_chain_t *in;
|
||||||
ngx_chain_t *free;
|
ngx_chain_t *free;
|
||||||
|
@ -90,7 +97,11 @@ typedef struct {
|
||||||
|
|
||||||
ngx_output_chain_filter_pt output_filter;
|
ngx_output_chain_filter_pt output_filter;
|
||||||
void *filter_ctx;
|
void *filter_ctx;
|
||||||
} ngx_output_chain_ctx_t;
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
ngx_output_chain_aio_pt aio;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -19,6 +19,7 @@ typedef struct ngx_open_file_s ngx_open_file_t;
|
||||||
typedef struct ngx_command_s ngx_command_t;
|
typedef struct ngx_command_s ngx_command_t;
|
||||||
typedef struct ngx_file_s ngx_file_t;
|
typedef struct ngx_file_s ngx_file_t;
|
||||||
typedef struct ngx_event_s ngx_event_t;
|
typedef struct ngx_event_s ngx_event_t;
|
||||||
|
typedef struct ngx_event_aio_s ngx_event_aio_t;
|
||||||
typedef struct ngx_connection_s ngx_connection_t;
|
typedef struct ngx_connection_s ngx_connection_t;
|
||||||
|
|
||||||
typedef void (*ngx_event_handler_pt)(ngx_event_t *ev);
|
typedef void (*ngx_event_handler_pt)(ngx_event_t *ev);
|
||||||
|
|
|
@ -22,10 +22,15 @@ struct ngx_file_s {
|
||||||
|
|
||||||
ngx_log_t *log;
|
ngx_log_t *log;
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
ngx_event_aio_t *aio;
|
||||||
|
#endif
|
||||||
|
|
||||||
unsigned valid_info:1;
|
unsigned valid_info:1;
|
||||||
unsigned directio:1;
|
unsigned directio:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define NGX_MAX_PATH_LEVEL 3
|
#define NGX_MAX_PATH_LEVEL 3
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -519,8 +519,26 @@ ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
|
||||||
|
if (ctx->aio) {
|
||||||
|
n = ngx_file_aio_read(src->file, dst->pos, (size_t) size,
|
||||||
|
src->file_pos, ctx->pool);
|
||||||
|
if (n == NGX_AGAIN) {
|
||||||
|
ctx->aio(ctx, src->file);
|
||||||
|
return NGX_AGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
n = ngx_read_file(src->file, dst->pos, (size_t) size,
|
||||||
|
src->file_pos);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
n = ngx_read_file(src->file, dst->pos, (size_t) size, src->file_pos);
|
n = ngx_read_file(src->file, dst->pos, (size_t) size, src->file_pos);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#if (NGX_HAVE_ALIGNED_DIRECTIO)
|
#if (NGX_HAVE_ALIGNED_DIRECTIO)
|
||||||
|
|
||||||
if (ctx->unaligned) {
|
if (ctx->unaligned) {
|
||||||
|
@ -545,12 +563,6 @@ ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx)
|
||||||
return (ngx_int_t) n;
|
return (ngx_int_t) n;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (NGX_FILE_AIO_READ)
|
|
||||||
if (n == NGX_AGAIN) {
|
|
||||||
return (ngx_int_t) n;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (n != size) {
|
if (n != size) {
|
||||||
ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
|
ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
|
||||||
ngx_read_file_n " read only %z of %O from \"%s\"",
|
ngx_read_file_n " read only %z of %O from \"%s\"",
|
||||||
|
|
|
@ -58,6 +58,29 @@ int epoll_wait(int epfd, struct epoll_event *events, int nevents, int timeout)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
|
||||||
|
#define SYS_io_setup 245
|
||||||
|
#define SYS_io_destroy 246
|
||||||
|
#define SYS_io_getevents 247
|
||||||
|
#define SYS_eventfd 323
|
||||||
|
|
||||||
|
typedef u_int aio_context_t;
|
||||||
|
|
||||||
|
struct io_event {
|
||||||
|
uint64_t data; /* the data field from the iocb */
|
||||||
|
uint64_t obj; /* what iocb this event came from */
|
||||||
|
int64_t res; /* result code for this event */
|
||||||
|
int64_t res2; /* secondary result */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int eventfd(u_int initval)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -78,6 +101,10 @@ static ngx_int_t ngx_epoll_del_connection(ngx_connection_t *c,
|
||||||
static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
|
static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
|
||||||
ngx_uint_t flags);
|
ngx_uint_t flags);
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
static void ngx_epoll_eventfd_handler(ngx_event_t *ev);
|
||||||
|
#endif
|
||||||
|
|
||||||
static void *ngx_epoll_create_conf(ngx_cycle_t *cycle);
|
static void *ngx_epoll_create_conf(ngx_cycle_t *cycle);
|
||||||
static char *ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf);
|
static char *ngx_epoll_init_conf(ngx_cycle_t *cycle, void *conf);
|
||||||
|
|
||||||
|
@ -85,6 +112,15 @@ static int ep = -1;
|
||||||
static struct epoll_event *event_list;
|
static struct epoll_event *event_list;
|
||||||
static ngx_uint_t nevents;
|
static ngx_uint_t nevents;
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
|
||||||
|
int ngx_eventfd = -1;
|
||||||
|
aio_context_t ngx_aio_ctx = 0;
|
||||||
|
|
||||||
|
static ngx_event_t ngx_eventfd_event;
|
||||||
|
static ngx_connection_t ngx_eventfd_conn;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static ngx_str_t epoll_name = ngx_string("epoll");
|
static ngx_str_t epoll_name = ngx_string("epoll");
|
||||||
|
|
||||||
|
@ -136,6 +172,42 @@ ngx_module_t ngx_epoll_module = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We call io_setup(), io_destroy() io_submit(), and io_getevents() directly
|
||||||
|
* as syscalls instead of libaio usage, because the library header file
|
||||||
|
* supports eventfd() since 0.3.107 version only.
|
||||||
|
*
|
||||||
|
* Also we do not use eventfd() in glibc, because glibc supports it
|
||||||
|
* since 2.8 version and glibc maps two syscalls eventfd() and eventfd2()
|
||||||
|
* into single eventfd() function with different number of parameters.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static long
|
||||||
|
io_setup(u_int nr_reqs, aio_context_t *ctx)
|
||||||
|
{
|
||||||
|
return syscall(SYS_io_setup, nr_reqs, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
io_destroy(aio_context_t ctx)
|
||||||
|
{
|
||||||
|
return syscall(SYS_io_destroy, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static long
|
||||||
|
io_getevents(aio_context_t ctx, long min_nr, long nr, struct io_event *events,
|
||||||
|
struct timespec *tmo)
|
||||||
|
{
|
||||||
|
return syscall(SYS_io_getevents, ctx, min_nr, nr, events, tmo);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
static ngx_int_t
|
||||||
ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
|
ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
|
||||||
{
|
{
|
||||||
|
@ -151,6 +223,55 @@ ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
|
||||||
"epoll_create() failed");
|
"epoll_create() failed");
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
struct epoll_event ee;
|
||||||
|
|
||||||
|
ngx_eventfd = syscall(SYS_eventfd, 0);
|
||||||
|
|
||||||
|
if (ngx_eventfd == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
|
||||||
|
"eventfd() failed");
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = 1;
|
||||||
|
|
||||||
|
if (ioctl(ngx_eventfd, FIONBIO, &n) == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
|
||||||
|
"ioctl(eventfd, FIONBIO) failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
|
||||||
|
"eventfd: %d", ngx_eventfd);
|
||||||
|
|
||||||
|
n = io_setup(1024, &ngx_aio_ctx);
|
||||||
|
|
||||||
|
if (n != 0) {
|
||||||
|
ngx_log_error(NGX_LOG_EMERG, cycle->log, -n, "io_setup() failed");
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_eventfd_event.data = &ngx_eventfd_conn;
|
||||||
|
ngx_eventfd_event.handler = ngx_epoll_eventfd_handler;
|
||||||
|
ngx_eventfd_event.log = cycle->log;
|
||||||
|
ngx_eventfd_event.active = 1;
|
||||||
|
ngx_eventfd_conn.fd = ngx_eventfd;
|
||||||
|
ngx_eventfd_conn.read = &ngx_eventfd_event;
|
||||||
|
ngx_eventfd_conn.log = cycle->log;
|
||||||
|
|
||||||
|
ee.events = EPOLLIN|EPOLLET;
|
||||||
|
ee.data.ptr = &ngx_eventfd_conn;
|
||||||
|
|
||||||
|
if (epoll_ctl(ep, EPOLL_CTL_ADD, ngx_eventfd, &ee) == -1) {
|
||||||
|
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
|
||||||
|
"epoll_ctl(EPOLL_CTL_ADD, eventfd) failed");
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nevents < epcf->events) {
|
if (nevents < epcf->events) {
|
||||||
|
@ -193,6 +314,17 @@ ngx_epoll_done(ngx_cycle_t *cycle)
|
||||||
|
|
||||||
ep = -1;
|
ep = -1;
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
|
||||||
|
if (io_destroy(ngx_aio_ctx) != 0) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
||||||
|
"io_destroy() failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_aio_ctx = 0;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
ngx_free(event_list);
|
ngx_free(event_list);
|
||||||
|
|
||||||
event_list = NULL;
|
event_list = NULL;
|
||||||
|
@ -537,6 +669,91 @@ ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
|
||||||
|
static void
|
||||||
|
ngx_epoll_eventfd_handler(ngx_event_t *ev)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
long i, events;
|
||||||
|
uint64_t ready;
|
||||||
|
ngx_err_t err;
|
||||||
|
ngx_event_t *e;
|
||||||
|
ngx_event_aio_t *aio;
|
||||||
|
struct io_event event[64];
|
||||||
|
struct timespec ts;
|
||||||
|
|
||||||
|
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "eventfd handler");
|
||||||
|
|
||||||
|
n = read(ngx_eventfd, &ready, 8);
|
||||||
|
|
||||||
|
err = ngx_errno;
|
||||||
|
|
||||||
|
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, "eventfd: %d", n);
|
||||||
|
|
||||||
|
if (n != 8) {
|
||||||
|
if (n == -1) {
|
||||||
|
if (err == NGX_EAGAIN) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, ev->log, err, "read(eventfd) failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
|
||||||
|
"read(eventfd) returned only %d bytes", n);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ts.tv_sec = 0;
|
||||||
|
ts.tv_nsec = 0;
|
||||||
|
|
||||||
|
while (ready) {
|
||||||
|
|
||||||
|
events = io_getevents(ngx_aio_ctx, 1, 64, event, &ts);
|
||||||
|
|
||||||
|
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||||
|
"io_getevents: %l", events);
|
||||||
|
|
||||||
|
if (events > 0) {
|
||||||
|
ready -= events;
|
||||||
|
|
||||||
|
for (i = 0; i < events; i++) {
|
||||||
|
|
||||||
|
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, ev->log, 0,
|
||||||
|
"io_event: %uXL %uXL %L %L",
|
||||||
|
event[i].data, event[i].obj,
|
||||||
|
event[i].res, event[i].res2);
|
||||||
|
|
||||||
|
e = (ngx_event_t *) (uintptr_t) event[i].data;
|
||||||
|
|
||||||
|
e->complete = 1;
|
||||||
|
e->active = 0;
|
||||||
|
e->ready = 1;
|
||||||
|
|
||||||
|
aio = e->data;
|
||||||
|
aio->res = event[i].res;
|
||||||
|
|
||||||
|
ngx_post_event(e, &ngx_posted_events);
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (events == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* events < 0 */
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, ev->log, -events, "io_getevents() failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
ngx_epoll_create_conf(ngx_cycle_t *cycle)
|
ngx_epoll_create_conf(ngx_cycle_t *cycle)
|
||||||
{
|
{
|
||||||
|
|
|
@ -189,6 +189,33 @@ struct ngx_event_s {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
|
||||||
|
struct ngx_event_aio_s {
|
||||||
|
void *data;
|
||||||
|
ngx_event_handler_pt handler;
|
||||||
|
ngx_file_t *file;
|
||||||
|
|
||||||
|
ngx_fd_t fd;
|
||||||
|
|
||||||
|
#if (NGX_HAVE_EVENTFD)
|
||||||
|
int64_t res;
|
||||||
|
#if (NGX_TEST_BUILD_EPOLL)
|
||||||
|
ngx_err_t err;
|
||||||
|
size_t nbytes;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
ngx_err_t err;
|
||||||
|
size_t nbytes;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ngx_aiocb_t aiocb;
|
||||||
|
ngx_event_t event;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
in_addr_t mask;
|
in_addr_t mask;
|
||||||
in_addr_t addr;
|
in_addr_t addr;
|
||||||
|
|
|
@ -24,15 +24,22 @@ ngx_int_t
|
||||||
ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write)
|
ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write)
|
||||||
{
|
{
|
||||||
u_int flags;
|
u_int flags;
|
||||||
|
ngx_int_t rc;
|
||||||
ngx_event_t *rev, *wev;
|
ngx_event_t *rev, *wev;
|
||||||
|
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
if (do_write) {
|
if (do_write) {
|
||||||
p->log->action = "sending to client";
|
p->log->action = "sending to client";
|
||||||
|
|
||||||
if (ngx_event_pipe_write_to_downstream(p) == NGX_ABORT) {
|
rc = ngx_event_pipe_write_to_downstream(p);
|
||||||
|
|
||||||
|
if (rc == NGX_ABORT) {
|
||||||
return NGX_ABORT;
|
return NGX_ABORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rc == NGX_BUSY) {
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p->read = 0;
|
p->read = 0;
|
||||||
|
@ -422,7 +429,7 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
|
||||||
u_char *prev;
|
u_char *prev;
|
||||||
size_t bsize;
|
size_t bsize;
|
||||||
ngx_int_t rc;
|
ngx_int_t rc;
|
||||||
ngx_uint_t flush, prev_last_shadow;
|
ngx_uint_t flush, flushed, prev_last_shadow;
|
||||||
ngx_chain_t *out, **ll, *cl, file;
|
ngx_chain_t *out, **ll, *cl, file;
|
||||||
ngx_connection_t *downstream;
|
ngx_connection_t *downstream;
|
||||||
|
|
||||||
|
@ -431,6 +438,8 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
|
||||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
|
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0,
|
||||||
"pipe write downstream: %d", downstream->write->ready);
|
"pipe write downstream: %d", downstream->write->ready);
|
||||||
|
|
||||||
|
flushed = 0;
|
||||||
|
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
if (p->downstream_error) {
|
if (p->downstream_error) {
|
||||||
return ngx_event_pipe_drain_chains(p);
|
return ngx_event_pipe_drain_chains(p);
|
||||||
|
@ -610,8 +619,16 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
|
||||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
|
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
|
||||||
"pipe write: out:%p, f:%d", out, flush);
|
"pipe write: out:%p, f:%d", out, flush);
|
||||||
|
|
||||||
if (out == NULL && !flush) {
|
if (out == NULL) {
|
||||||
break;
|
|
||||||
|
if (!flush) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* a workaround for AIO */
|
||||||
|
if (flushed++ > 10) {
|
||||||
|
return NGX_BUSY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = p->output_filter(p->output_ctx, out);
|
rc = p->output_filter(p->output_ctx, out);
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#define NGX_HTTP_CACHE_STALE 3
|
#define NGX_HTTP_CACHE_STALE 3
|
||||||
#define NGX_HTTP_CACHE_UPDATING 4
|
#define NGX_HTTP_CACHE_UPDATING 4
|
||||||
#define NGX_HTTP_CACHE_HIT 5
|
#define NGX_HTTP_CACHE_HIT 5
|
||||||
|
#define NGX_HTTP_CACHE_SCARCE 6
|
||||||
|
|
||||||
#define NGX_HTTP_CACHE_KEY_LEN 16
|
#define NGX_HTTP_CACHE_KEY_LEN 16
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,12 @@ typedef struct {
|
||||||
} ngx_http_copy_filter_conf_t;
|
} ngx_http_copy_filter_conf_t;
|
||||||
|
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
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);
|
||||||
|
#endif
|
||||||
|
|
||||||
static void *ngx_http_copy_filter_create_conf(ngx_conf_t *cf);
|
static void *ngx_http_copy_filter_create_conf(ngx_conf_t *cf);
|
||||||
static char *ngx_http_copy_filter_merge_conf(ngx_conf_t *cf,
|
static char *ngx_http_copy_filter_merge_conf(ngx_conf_t *cf,
|
||||||
void *parent, void *child);
|
void *parent, void *child);
|
||||||
|
@ -73,10 +79,15 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||||
ngx_int_t rc;
|
ngx_int_t rc;
|
||||||
ngx_connection_t *c;
|
ngx_connection_t *c;
|
||||||
ngx_output_chain_ctx_t *ctx;
|
ngx_output_chain_ctx_t *ctx;
|
||||||
|
ngx_http_core_loc_conf_t *clcf;
|
||||||
ngx_http_copy_filter_conf_t *conf;
|
ngx_http_copy_filter_conf_t *conf;
|
||||||
|
|
||||||
c = r->connection;
|
c = r->connection;
|
||||||
|
|
||||||
|
if (r->aio) {
|
||||||
|
return NGX_AGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
||||||
"copy filter: \"%V?%V\"", &r->uri, &r->args);
|
"copy filter: \"%V?%V\"", &r->uri, &r->args);
|
||||||
|
|
||||||
|
@ -104,6 +115,13 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||||
ctx->output_filter = (ngx_output_chain_filter_pt) ngx_http_next_filter;
|
ctx->output_filter = (ngx_output_chain_filter_pt) ngx_http_next_filter;
|
||||||
ctx->filter_ctx = r;
|
ctx->filter_ctx = r;
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
|
||||||
|
if (clcf->aio) {
|
||||||
|
ctx->aio = ngx_http_copy_aio_handler;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
r->request_output = 1;
|
r->request_output = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,6 +141,41 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
|
||||||
|
static void
|
||||||
|
ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx, ngx_file_t *file)
|
||||||
|
{
|
||||||
|
ngx_http_request_t *r;
|
||||||
|
|
||||||
|
r = ctx->filter_ctx;
|
||||||
|
|
||||||
|
file->aio->data = r;
|
||||||
|
file->aio->handler = ngx_http_copy_aio_event_handler;
|
||||||
|
|
||||||
|
r->main->blocked++;
|
||||||
|
r->aio = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
ngx_http_copy_aio_event_handler(ngx_event_t *ev)
|
||||||
|
{
|
||||||
|
ngx_event_aio_t *aio;
|
||||||
|
ngx_http_request_t *r;
|
||||||
|
|
||||||
|
aio = ev->data;
|
||||||
|
r = aio->data;
|
||||||
|
|
||||||
|
r->main->blocked--;
|
||||||
|
r->aio = 0;
|
||||||
|
|
||||||
|
r->connection->write->handler(r->connection->write);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
ngx_http_copy_filter_create_conf(ngx_conf_t *cf)
|
ngx_http_copy_filter_create_conf(ngx_conf_t *cf)
|
||||||
{
|
{
|
||||||
|
|
|
@ -383,6 +383,17 @@ static ngx_command_t ngx_http_core_commands[] = {
|
||||||
offsetof(ngx_http_core_loc_conf_t, sendfile_max_chunk),
|
offsetof(ngx_http_core_loc_conf_t, sendfile_max_chunk),
|
||||||
NULL },
|
NULL },
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
|
||||||
|
{ ngx_string("aio"),
|
||||||
|
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
|
||||||
|
ngx_conf_set_flag_slot,
|
||||||
|
NGX_HTTP_LOC_CONF_OFFSET,
|
||||||
|
offsetof(ngx_http_core_loc_conf_t, aio),
|
||||||
|
NULL },
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
{ ngx_string("directio"),
|
{ ngx_string("directio"),
|
||||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
|
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
|
||||||
ngx_http_core_directio,
|
ngx_http_core_directio,
|
||||||
|
@ -2916,6 +2927,9 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf)
|
||||||
lcf->internal = NGX_CONF_UNSET;
|
lcf->internal = NGX_CONF_UNSET;
|
||||||
lcf->sendfile = NGX_CONF_UNSET;
|
lcf->sendfile = NGX_CONF_UNSET;
|
||||||
lcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE;
|
lcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE;
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
lcf->aio = NGX_CONF_UNSET;
|
||||||
|
#endif
|
||||||
lcf->directio = NGX_CONF_UNSET;
|
lcf->directio = NGX_CONF_UNSET;
|
||||||
lcf->tcp_nopush = NGX_CONF_UNSET;
|
lcf->tcp_nopush = NGX_CONF_UNSET;
|
||||||
lcf->tcp_nodelay = NGX_CONF_UNSET;
|
lcf->tcp_nodelay = NGX_CONF_UNSET;
|
||||||
|
@ -3113,6 +3127,9 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||||
ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0);
|
ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0);
|
||||||
ngx_conf_merge_size_value(conf->sendfile_max_chunk,
|
ngx_conf_merge_size_value(conf->sendfile_max_chunk,
|
||||||
prev->sendfile_max_chunk, 0);
|
prev->sendfile_max_chunk, 0);
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
ngx_conf_merge_value(conf->aio, prev->aio, 0);
|
||||||
|
#endif
|
||||||
ngx_conf_merge_off_value(conf->directio, prev->directio,
|
ngx_conf_merge_off_value(conf->directio, prev->directio,
|
||||||
NGX_MAX_OFF_T_VALUE);
|
NGX_MAX_OFF_T_VALUE);
|
||||||
ngx_conf_merge_value(conf->tcp_nopush, prev->tcp_nopush, 0);
|
ngx_conf_merge_value(conf->tcp_nopush, prev->tcp_nopush, 0);
|
||||||
|
|
|
@ -347,6 +347,9 @@ struct ngx_http_core_loc_conf_s {
|
||||||
/* client_body_in_singe_buffer */
|
/* client_body_in_singe_buffer */
|
||||||
ngx_flag_t internal; /* internal */
|
ngx_flag_t internal; /* internal */
|
||||||
ngx_flag_t sendfile; /* sendfile */
|
ngx_flag_t sendfile; /* sendfile */
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
ngx_flag_t aio; /* aio */
|
||||||
|
#endif
|
||||||
ngx_flag_t tcp_nopush; /* tcp_nopush */
|
ngx_flag_t tcp_nopush; /* tcp_nopush */
|
||||||
ngx_flag_t tcp_nodelay; /* tcp_nodelay */
|
ngx_flag_t tcp_nodelay; /* tcp_nodelay */
|
||||||
ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */
|
ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */
|
||||||
|
|
|
@ -10,6 +10,11 @@
|
||||||
#include <ngx_md5.h>
|
#include <ngx_md5.h>
|
||||||
|
|
||||||
|
|
||||||
|
static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r,
|
||||||
|
ngx_http_cache_t *c);
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
static void ngx_http_cache_aio_event_handler(ngx_event_t *ev);
|
||||||
|
#endif
|
||||||
static ngx_int_t ngx_http_file_cache_exists(ngx_http_file_cache_t *cache,
|
static ngx_int_t ngx_http_file_cache_exists(ngx_http_file_cache_t *cache,
|
||||||
ngx_http_cache_t *c);
|
ngx_http_cache_t *c);
|
||||||
static ngx_http_file_cache_node_t *
|
static ngx_http_file_cache_node_t *
|
||||||
|
@ -173,20 +178,22 @@ ngx_http_file_cache_create_key(ngx_http_request_t *r)
|
||||||
ngx_int_t
|
ngx_int_t
|
||||||
ngx_http_file_cache_open(ngx_http_request_t *r)
|
ngx_http_file_cache_open(ngx_http_request_t *r)
|
||||||
{
|
{
|
||||||
u_char *p;
|
u_char *p;
|
||||||
time_t now;
|
ngx_int_t rc, rv;
|
||||||
ssize_t n;
|
ngx_uint_t cold, test;
|
||||||
ngx_int_t rc, rv;
|
ngx_path_t *path;
|
||||||
ngx_uint_t cold, test;
|
ngx_http_cache_t *c;
|
||||||
ngx_path_t *path;
|
ngx_pool_cleanup_t *cln;
|
||||||
ngx_http_cache_t *c;
|
ngx_open_file_info_t of;
|
||||||
ngx_pool_cleanup_t *cln;
|
ngx_http_file_cache_t *cache;
|
||||||
ngx_open_file_info_t of;
|
ngx_http_core_loc_conf_t *clcf;
|
||||||
ngx_http_file_cache_t *cache;
|
|
||||||
ngx_http_core_loc_conf_t *clcf;
|
|
||||||
ngx_http_file_cache_header_t *h;
|
|
||||||
|
|
||||||
c = r->cache;
|
c = r->cache;
|
||||||
|
|
||||||
|
if (c->buf) {
|
||||||
|
return ngx_http_file_cache_read(r, c);
|
||||||
|
}
|
||||||
|
|
||||||
cache = c->file_cache;
|
cache = c->file_cache;
|
||||||
|
|
||||||
cln = ngx_pool_cleanup_add(r->pool, 0);
|
cln = ngx_pool_cleanup_add(r->pool, 0);
|
||||||
|
@ -207,7 +214,7 @@ ngx_http_file_cache_open(ngx_http_request_t *r)
|
||||||
cln->data = c;
|
cln->data = c;
|
||||||
|
|
||||||
if (rc == NGX_AGAIN) {
|
if (rc == NGX_AGAIN) {
|
||||||
return rc;
|
return NGX_HTTP_CACHE_SCARCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
cold = cache->sh->cold;
|
cold = cache->sh->cold;
|
||||||
|
@ -227,11 +234,11 @@ ngx_http_file_cache_open(ngx_http_request_t *r)
|
||||||
if (c->min_uses > 1) {
|
if (c->min_uses > 1) {
|
||||||
|
|
||||||
if (!cold) {
|
if (!cold) {
|
||||||
return NGX_AGAIN;
|
return NGX_HTTP_CACHE_SCARCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
test = 1;
|
test = 1;
|
||||||
rv = NGX_AGAIN;
|
rv = NGX_HTTP_CACHE_SCARCE;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
c->temp_file = 1;
|
c->temp_file = 1;
|
||||||
|
@ -299,14 +306,58 @@ ngx_http_file_cache_open(ngx_http_request_t *r)
|
||||||
|
|
||||||
c->file.fd = of.fd;
|
c->file.fd = of.fd;
|
||||||
c->file.log = r->connection->log;
|
c->file.log = r->connection->log;
|
||||||
|
c->uniq = of.uniq;
|
||||||
|
c->length = of.size;
|
||||||
|
|
||||||
c->buf = ngx_create_temp_buf(r->pool, c->body_start);
|
c->buf = ngx_create_temp_buf(r->pool, c->body_start);
|
||||||
if (c->buf == NULL) {
|
if (c->buf == NULL) {
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ngx_http_file_cache_read(r, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ngx_int_t
|
||||||
|
ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c)
|
||||||
|
{
|
||||||
|
time_t now;
|
||||||
|
ssize_t n;
|
||||||
|
ngx_int_t rc;
|
||||||
|
ngx_http_file_cache_t *cache;
|
||||||
|
ngx_http_file_cache_header_t *h;
|
||||||
|
|
||||||
|
c = r->cache;
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
{
|
||||||
|
ngx_http_core_loc_conf_t *clcf;
|
||||||
|
|
||||||
|
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
|
||||||
|
|
||||||
|
if (clcf->aio) {
|
||||||
|
n = ngx_file_aio_read(&c->file, c->buf->pos, c->body_start, 0, r->pool);
|
||||||
|
|
||||||
|
if (n == NGX_AGAIN) {
|
||||||
|
c->file.aio->data = r;
|
||||||
|
c->file.aio->handler = ngx_http_cache_aio_event_handler;
|
||||||
|
|
||||||
|
r->main->blocked++;
|
||||||
|
r->aio = 1;
|
||||||
|
|
||||||
|
return NGX_AGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
|
n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
if (n == NGX_ERROR) {
|
if (n == NGX_ERROR) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
@ -331,12 +382,13 @@ ngx_http_file_cache_open(ngx_http_request_t *r)
|
||||||
c->last_modified = h->last_modified;
|
c->last_modified = h->last_modified;
|
||||||
c->date = h->date;
|
c->date = h->date;
|
||||||
c->valid_msec = h->valid_msec;
|
c->valid_msec = h->valid_msec;
|
||||||
c->length = of.size;
|
|
||||||
c->body_start = h->body_start;
|
c->body_start = h->body_start;
|
||||||
|
|
||||||
r->cached = 1;
|
r->cached = 1;
|
||||||
|
|
||||||
if (cold) {
|
cache = c->file_cache;
|
||||||
|
|
||||||
|
if (cache->sh->cold) {
|
||||||
|
|
||||||
ngx_shmtx_lock(&cache->shpool->mutex);
|
ngx_shmtx_lock(&cache->shpool->mutex);
|
||||||
|
|
||||||
|
@ -344,7 +396,7 @@ ngx_http_file_cache_open(ngx_http_request_t *r)
|
||||||
c->node->uses = 1;
|
c->node->uses = 1;
|
||||||
c->node->body_start = c->body_start;
|
c->node->body_start = c->body_start;
|
||||||
c->node->exists = 1;
|
c->node->exists = 1;
|
||||||
c->node->uniq = of.uniq;
|
c->node->uniq = c->uniq;
|
||||||
|
|
||||||
cache->sh->size += (c->length + cache->bsize - 1) / cache->bsize;
|
cache->sh->size += (c->length + cache->bsize - 1) / cache->bsize;
|
||||||
}
|
}
|
||||||
|
@ -379,6 +431,27 @@ ngx_http_file_cache_open(ngx_http_request_t *r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
ngx_http_cache_aio_event_handler(ngx_event_t *ev)
|
||||||
|
{
|
||||||
|
ngx_event_aio_t *aio;
|
||||||
|
ngx_http_request_t *r;
|
||||||
|
|
||||||
|
aio = ev->data;
|
||||||
|
r = aio->data;
|
||||||
|
|
||||||
|
r->main->blocked--;
|
||||||
|
r->aio = 0;
|
||||||
|
|
||||||
|
r->connection->write->handler(r->connection->write);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
static ngx_int_t
|
||||||
ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c)
|
ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1868,6 +1868,10 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (r->main->blocked) {
|
||||||
|
r->write_event_handler = ngx_http_request_finalizer;
|
||||||
|
}
|
||||||
|
|
||||||
ngx_http_terminate_request(r, rc);
|
ngx_http_terminate_request(r, rc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1969,7 +1973,7 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r->buffered || c->buffered || r->postponed) {
|
if (r->buffered || c->buffered || r->postponed || r->blocked) {
|
||||||
|
|
||||||
if (ngx_http_set_write_handler(r) != NGX_OK) {
|
if (ngx_http_set_write_handler(r) != NGX_OK) {
|
||||||
ngx_http_terminate_request(r, 0);
|
ngx_http_terminate_request(r, 0);
|
||||||
|
@ -2022,7 +2026,7 @@ ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc)
|
||||||
mr = r->main;
|
mr = r->main;
|
||||||
|
|
||||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||||
"http terminate request count: %d", mr->count);
|
"http terminate request count:%d", mr->count);
|
||||||
|
|
||||||
cln = mr->cleanup;
|
cln = mr->cleanup;
|
||||||
mr->cleanup = NULL;
|
mr->cleanup = NULL;
|
||||||
|
@ -2035,10 +2039,16 @@ ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc)
|
||||||
cln = cln->next;
|
cln = cln->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||||
"http terminate cleanup count: %d", mr->count);
|
"http terminate cleanup count:%d blk:%d",
|
||||||
|
mr->count, mr->blocked);
|
||||||
|
|
||||||
if (mr->write_event_handler) {
|
if (mr->write_event_handler) {
|
||||||
|
|
||||||
|
if (mr->blocked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mr->posted_requests = NULL;
|
mr->posted_requests = NULL;
|
||||||
mr->write_event_handler = ngx_http_terminate_handler;
|
mr->write_event_handler = ngx_http_terminate_handler;
|
||||||
(void) ngx_http_post_request(mr);
|
(void) ngx_http_post_request(mr);
|
||||||
|
@ -2053,7 +2063,7 @@ static void
|
||||||
ngx_http_terminate_handler(ngx_http_request_t *r)
|
ngx_http_terminate_handler(ngx_http_request_t *r)
|
||||||
{
|
{
|
||||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||||
"http terminate handler count: %d", r->count);
|
"http terminate handler count:%d", r->count);
|
||||||
|
|
||||||
r->count = 1;
|
r->count = 1;
|
||||||
|
|
||||||
|
@ -2161,7 +2171,7 @@ ngx_http_writer(ngx_http_request_t *r)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (wev->delayed) {
|
if (wev->delayed || r->aio) {
|
||||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0,
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0,
|
||||||
"http writer delayed");
|
"http writer delayed");
|
||||||
|
|
||||||
|
@ -2830,8 +2840,8 @@ ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc)
|
||||||
r = r->main;
|
r = r->main;
|
||||||
c = r->connection;
|
c = r->connection;
|
||||||
|
|
||||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
||||||
"http request count: %d", r->count);
|
"http request count:%d blk:%d", r->count, r->blocked);
|
||||||
|
|
||||||
if (r->count == 0) {
|
if (r->count == 0) {
|
||||||
ngx_log_error(NGX_LOG_ALERT, c->log, 0, "http request count is zero");
|
ngx_log_error(NGX_LOG_ALERT, c->log, 0, "http request count is zero");
|
||||||
|
@ -2839,7 +2849,7 @@ ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc)
|
||||||
|
|
||||||
r->count--;
|
r->count--;
|
||||||
|
|
||||||
if (r->count) {
|
if (r->count || r->blocked) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -416,6 +416,12 @@ struct ngx_http_request_s {
|
||||||
|
|
||||||
ngx_http_cleanup_t *cleanup;
|
ngx_http_cleanup_t *cleanup;
|
||||||
|
|
||||||
|
unsigned subrequests:8;
|
||||||
|
unsigned count:8;
|
||||||
|
unsigned blocked:8;
|
||||||
|
|
||||||
|
unsigned aio:1;
|
||||||
|
|
||||||
unsigned http_state:4;
|
unsigned http_state:4;
|
||||||
|
|
||||||
/* URI with "/." and on Win32 with "//" */
|
/* URI with "/." and on Win32 with "//" */
|
||||||
|
@ -501,9 +507,6 @@ struct ngx_http_request_s {
|
||||||
unsigned stat_writing:1;
|
unsigned stat_writing:1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
unsigned subrequests:8;
|
|
||||||
unsigned count:8;
|
|
||||||
|
|
||||||
/* used to parse HTTP headers */
|
/* used to parse HTTP headers */
|
||||||
|
|
||||||
ngx_uint_t state;
|
ngx_uint_t state;
|
||||||
|
|
|
@ -18,6 +18,7 @@ static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r,
|
||||||
ngx_http_variable_value_t *v, uintptr_t data);
|
ngx_http_variable_value_t *v, uintptr_t data);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void ngx_http_upstream_init_request(ngx_http_request_t *r);
|
||||||
static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx);
|
static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx);
|
||||||
static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r);
|
static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r);
|
||||||
static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r);
|
static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r);
|
||||||
|
@ -386,15 +387,7 @@ ngx_http_upstream_create(ngx_http_request_t *r)
|
||||||
void
|
void
|
||||||
ngx_http_upstream_init(ngx_http_request_t *r)
|
ngx_http_upstream_init(ngx_http_request_t *r)
|
||||||
{
|
{
|
||||||
ngx_str_t *host;
|
ngx_connection_t *c;
|
||||||
ngx_uint_t i;
|
|
||||||
ngx_connection_t *c;
|
|
||||||
ngx_resolver_ctx_t *ctx, temp;
|
|
||||||
ngx_http_cleanup_t *cln;
|
|
||||||
ngx_http_upstream_t *u;
|
|
||||||
ngx_http_core_loc_conf_t *clcf;
|
|
||||||
ngx_http_upstream_srv_conf_t *uscf, **uscfp;
|
|
||||||
ngx_http_upstream_main_conf_t *umcf;
|
|
||||||
|
|
||||||
c = r->connection;
|
c = r->connection;
|
||||||
|
|
||||||
|
@ -405,15 +398,6 @@ ngx_http_upstream_init(ngx_http_request_t *r)
|
||||||
ngx_del_timer(c->read);
|
ngx_del_timer(c->read);
|
||||||
}
|
}
|
||||||
|
|
||||||
u = r->upstream;
|
|
||||||
|
|
||||||
u->store = (u->conf->store || u->conf->store_lengths);
|
|
||||||
|
|
||||||
if (!u->store && !r->post_action && !u->conf->ignore_client_abort) {
|
|
||||||
r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
|
|
||||||
r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
|
if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
|
||||||
|
|
||||||
if (!c->write->active) {
|
if (!c->write->active) {
|
||||||
|
@ -426,10 +410,28 @@ ngx_http_upstream_init(ngx_http_request_t *r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r->request_body) {
|
ngx_http_upstream_init_request(r);
|
||||||
u->request_bufs = r->request_body->bufs;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
ngx_http_upstream_init_request(ngx_http_request_t *r)
|
||||||
|
{
|
||||||
|
ngx_str_t *host;
|
||||||
|
ngx_uint_t i;
|
||||||
|
ngx_resolver_ctx_t *ctx, temp;
|
||||||
|
ngx_http_cleanup_t *cln;
|
||||||
|
ngx_http_upstream_t *u;
|
||||||
|
ngx_http_core_loc_conf_t *clcf;
|
||||||
|
ngx_http_upstream_srv_conf_t *uscf, **uscfp;
|
||||||
|
ngx_http_upstream_main_conf_t *umcf;
|
||||||
|
|
||||||
|
if (r->aio) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u = r->upstream;
|
||||||
|
|
||||||
#if (NGX_HTTP_CACHE)
|
#if (NGX_HTTP_CACHE)
|
||||||
|
|
||||||
if (u->conf->cache) {
|
if (u->conf->cache) {
|
||||||
|
@ -437,6 +439,11 @@ ngx_http_upstream_init(ngx_http_request_t *r)
|
||||||
|
|
||||||
rc = ngx_http_upstream_cache(r, u);
|
rc = ngx_http_upstream_cache(r, u);
|
||||||
|
|
||||||
|
if (rc == NGX_AGAIN) {
|
||||||
|
r->write_event_handler = ngx_http_upstream_init_request;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (rc == NGX_DONE) {
|
if (rc == NGX_DONE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -449,6 +456,17 @@ ngx_http_upstream_init(ngx_http_request_t *r)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
u->store = (u->conf->store || u->conf->store_lengths);
|
||||||
|
|
||||||
|
if (!u->store && !r->post_action && !u->conf->ignore_client_abort) {
|
||||||
|
r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
|
||||||
|
r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r->request_body) {
|
||||||
|
u->request_bufs = r->request_body->bufs;
|
||||||
|
}
|
||||||
|
|
||||||
if (u->create_request(r) != NGX_OK) {
|
if (u->create_request(r) != NGX_OK) {
|
||||||
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
return;
|
return;
|
||||||
|
@ -543,7 +561,7 @@ ngx_http_upstream_init(ngx_http_request_t *r)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx == NGX_NO_RESOLVER) {
|
if (ctx == NGX_NO_RESOLVER) {
|
||||||
ngx_log_error(NGX_LOG_ERR, c->log, 0,
|
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||||
"no resolver defined to resolve %V", host);
|
"no resolver defined to resolve %V", host);
|
||||||
|
|
||||||
ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY);
|
ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY);
|
||||||
|
@ -657,10 +675,6 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NGX_ERROR:
|
|
||||||
|
|
||||||
return NGX_ERROR;
|
|
||||||
|
|
||||||
case NGX_HTTP_CACHE_STALE:
|
case NGX_HTTP_CACHE_STALE:
|
||||||
|
|
||||||
c->valid_sec = 0;
|
c->valid_sec = 0;
|
||||||
|
@ -681,12 +695,20 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NGX_AGAIN:
|
case NGX_HTTP_CACHE_SCARCE:
|
||||||
|
|
||||||
u->cacheable = 0;
|
u->cacheable = 0;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NGX_AGAIN:
|
||||||
|
|
||||||
|
return NGX_AGAIN;
|
||||||
|
|
||||||
|
case NGX_ERROR:
|
||||||
|
|
||||||
|
return NGX_ERROR;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
/* cached NGX_HTTP_BAD_GATEWAY, NGX_HTTP_GATEWAY_TIME_OUT, etc. */
|
/* cached NGX_HTTP_BAD_GATEWAY, NGX_HTTP_GATEWAY_TIME_OUT, etc. */
|
||||||
|
|
210
src/os/unix/ngx_file_aio_read.c
Normal file
210
src/os/unix/ngx_file_aio_read.c
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) Igor Sysoev
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <ngx_config.h>
|
||||||
|
#include <ngx_core.h>
|
||||||
|
#include <ngx_event.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FreeBSD file AIO features and quirks:
|
||||||
|
*
|
||||||
|
* if an asked data are already in VM cache, then aio_error() returns 0,
|
||||||
|
* and the data are already copied in buffer;
|
||||||
|
*
|
||||||
|
* aio_read() preread in VM cache as minimum 32K;
|
||||||
|
*
|
||||||
|
* aio_read/aio_error() may return EINPROGRESS for just written data;
|
||||||
|
*
|
||||||
|
* kqueue EVFILT_AIO filter is level triggered only: an event repeats
|
||||||
|
* until aio_return() will be called;
|
||||||
|
*
|
||||||
|
* aio_cancel() can not cancel file AIO: it returns AIO_NOTCANCELED always.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
extern int ngx_kqueue;
|
||||||
|
|
||||||
|
|
||||||
|
static ssize_t ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio,
|
||||||
|
ngx_event_t *ev);
|
||||||
|
static void ngx_file_aio_event_handler(ngx_event_t *ev);
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
|
||||||
|
ngx_pool_t *pool)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
ngx_event_t *ev;
|
||||||
|
ngx_event_aio_t *aio;
|
||||||
|
static ngx_uint_t enosys = 0;
|
||||||
|
|
||||||
|
if (enosys) {
|
||||||
|
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;
|
||||||
|
file->aio = aio;
|
||||||
|
}
|
||||||
|
|
||||||
|
ev = &aio->event;
|
||||||
|
|
||||||
|
if (!ev->ready) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, file->log, 0,
|
||||||
|
"second aio post for \"%V\"", &file->name);
|
||||||
|
return NGX_AGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
|
||||||
|
"aio complete:%d @%O:%z %V",
|
||||||
|
ev->complete, offset, size, &file->name);
|
||||||
|
|
||||||
|
if (ev->complete) {
|
||||||
|
ev->complete = 0;
|
||||||
|
ngx_set_errno(aio->err);
|
||||||
|
|
||||||
|
if (aio->err == 0) {
|
||||||
|
return aio->nbytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_memzero(&aio->aiocb, sizeof(struct aiocb));
|
||||||
|
|
||||||
|
aio->aiocb.aio_fildes = file->fd;
|
||||||
|
aio->aiocb.aio_offset = offset;
|
||||||
|
aio->aiocb.aio_buf = buf;
|
||||||
|
aio->aiocb.aio_nbytes = size;
|
||||||
|
#if (NGX_HAVE_KQUEUE)
|
||||||
|
aio->aiocb.aio_sigevent.sigev_notify_kqueue = ngx_kqueue;
|
||||||
|
aio->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT;
|
||||||
|
aio->aiocb.aio_sigevent.sigev_value.sigval_ptr = ev;
|
||||||
|
#endif
|
||||||
|
ev->handler = ngx_file_aio_event_handler;
|
||||||
|
|
||||||
|
n = aio_read(&aio->aiocb);
|
||||||
|
|
||||||
|
if (n == -1) {
|
||||||
|
n = ngx_errno;
|
||||||
|
|
||||||
|
if (n == NGX_EAGAIN) {
|
||||||
|
return ngx_read_file(file, buf, size, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_log_error(NGX_LOG_CRIT, file->log, n,
|
||||||
|
"aio_read(\"%V\") failed", &file->name);
|
||||||
|
|
||||||
|
if (n == NGX_ENOSYS) {
|
||||||
|
enosys = 1;
|
||||||
|
return ngx_read_file(file, buf, size, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0,
|
||||||
|
"aio_read: fd:%d %d", file->fd, n);
|
||||||
|
|
||||||
|
ev->active = 1;
|
||||||
|
ev->ready = 0;
|
||||||
|
ev->complete = 0;
|
||||||
|
|
||||||
|
return ngx_file_aio_result(aio->file, aio, ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
ngx_file_aio_result(ngx_file_t *file, ngx_event_aio_t *aio, ngx_event_t *ev)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
ngx_err_t err;
|
||||||
|
|
||||||
|
n = aio_error(&aio->aiocb);
|
||||||
|
|
||||||
|
ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0,
|
||||||
|
"aio_error: fd:%d %d", file->fd, n);
|
||||||
|
|
||||||
|
if (n == -1) {
|
||||||
|
err = ngx_errno;
|
||||||
|
aio->err = err;
|
||||||
|
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, file->log, err,
|
||||||
|
"aio_error(\"%V\") failed", &file->name);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n != 0) {
|
||||||
|
if (n == NGX_EINPROGRESS) {
|
||||||
|
if (ev->ready) {
|
||||||
|
ev->ready = 0;
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, file->log, n,
|
||||||
|
"aio_read(\"%V\") still in progress",
|
||||||
|
&file->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NGX_AGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
aio->err = n;
|
||||||
|
ev->ready = 0;
|
||||||
|
|
||||||
|
ngx_log_error(NGX_LOG_CRIT, file->log, n,
|
||||||
|
"aio_read(\"%V\") failed", &file->name);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = aio_return(&aio->aiocb);
|
||||||
|
|
||||||
|
if (n == -1) {
|
||||||
|
err = ngx_errno;
|
||||||
|
aio->err = err;
|
||||||
|
ev->ready = 0;
|
||||||
|
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, file->log, err,
|
||||||
|
"aio_return(\"%V\") failed", &file->name);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
aio->err = 0;
|
||||||
|
aio->nbytes = n;
|
||||||
|
ev->ready = 1;
|
||||||
|
ev->active = 0;
|
||||||
|
|
||||||
|
ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0,
|
||||||
|
"aio_return: fd:%d %d", file->fd, n);
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
ngx_file_aio_event_handler(ngx_event_t *ev)
|
||||||
|
{
|
||||||
|
ngx_event_aio_t *aio;
|
||||||
|
|
||||||
|
aio = ev->data;
|
||||||
|
|
||||||
|
ngx_log_debug2(NGX_LOG_DEBUG_CORE, ev->log, 0,
|
||||||
|
"aio event handler fd:%d %V", aio->fd, &aio->file->name);
|
||||||
|
|
||||||
|
if (ngx_file_aio_result(aio->file, aio, ev) != NGX_AGAIN) {
|
||||||
|
aio->handler(ev);
|
||||||
|
}
|
||||||
|
}
|
|
@ -287,4 +287,12 @@ size_t ngx_fs_bsize(u_char *name);
|
||||||
#define ngx_set_stderr_n "dup2(STDERR_FILENO)"
|
#define ngx_set_stderr_n "dup2(STDERR_FILENO)"
|
||||||
|
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
|
||||||
|
ssize_t ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size,
|
||||||
|
off_t offset, ngx_pool_t *pool);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif /* _NGX_FILES_H_INCLUDED_ */
|
#endif /* _NGX_FILES_H_INCLUDED_ */
|
||||||
|
|
|
@ -73,13 +73,14 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if (NGX_HAVE_AIO)
|
#if (NGX_HAVE_KQUEUE)
|
||||||
#include <aio.h>
|
#include <sys/event.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if (NGX_HAVE_KQUEUE)
|
#if (NGX_HAVE_FILE_AIO || NGX_HAVE_AIO)
|
||||||
#include <sys/event.h>
|
#include <aio.h>
|
||||||
|
typedef struct aiocb ngx_aiocb_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
131
src/os/unix/ngx_linux_aio_read.c
Normal file
131
src/os/unix/ngx_linux_aio_read.c
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) Igor Sysoev
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <ngx_config.h>
|
||||||
|
#include <ngx_core.h>
|
||||||
|
#include <ngx_event.h>
|
||||||
|
|
||||||
|
|
||||||
|
extern int ngx_eventfd;
|
||||||
|
extern aio_context_t ngx_aio_ctx;
|
||||||
|
|
||||||
|
|
||||||
|
static void ngx_file_aio_event_handler(ngx_event_t *ev);
|
||||||
|
|
||||||
|
|
||||||
|
static long
|
||||||
|
io_submit(aio_context_t ctx, long n, struct iocb **paiocb)
|
||||||
|
{
|
||||||
|
return syscall(SYS_io_submit, ctx, n, paiocb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
|
||||||
|
ngx_pool_t *pool)
|
||||||
|
{
|
||||||
|
long n;
|
||||||
|
struct iocb *piocb[1];
|
||||||
|
ngx_event_t *ev;
|
||||||
|
ngx_event_aio_t *aio;
|
||||||
|
static ngx_uint_t enosys = 0;
|
||||||
|
|
||||||
|
if (enosys) {
|
||||||
|
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;
|
||||||
|
file->aio = aio;
|
||||||
|
}
|
||||||
|
|
||||||
|
ev = &aio->event;
|
||||||
|
|
||||||
|
if (!ev->ready) {
|
||||||
|
ngx_log_error(NGX_LOG_ALERT, file->log, 0,
|
||||||
|
"second aio post for \"%V\"", &file->name);
|
||||||
|
return NGX_AGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
|
||||||
|
"aio complete:%d @%O:%z %V",
|
||||||
|
ev->complete, offset, size, &file->name);
|
||||||
|
|
||||||
|
if (ev->complete) {
|
||||||
|
ev->active = 0;
|
||||||
|
ev->complete = 0;
|
||||||
|
|
||||||
|
if (aio->res >= 0) {
|
||||||
|
ngx_set_errno(0);
|
||||||
|
return aio->res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_set_errno(-aio->res);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_memzero(&aio->aiocb, sizeof(struct iocb));
|
||||||
|
|
||||||
|
aio->aiocb.aio_data = (uint64_t) (uintptr_t) ev;
|
||||||
|
aio->aiocb.aio_lio_opcode = IOCB_CMD_PREAD;
|
||||||
|
aio->aiocb.aio_fildes = file->fd;
|
||||||
|
aio->aiocb.aio_buf = (uint64_t) (uintptr_t) buf;
|
||||||
|
aio->aiocb.aio_nbytes = size;
|
||||||
|
aio->aiocb.aio_offset = offset;
|
||||||
|
aio->aiocb.aio_flags = IOCB_FLAG_RESFD;
|
||||||
|
aio->aiocb.aio_resfd = ngx_eventfd;
|
||||||
|
|
||||||
|
ev->handler = ngx_file_aio_event_handler;
|
||||||
|
|
||||||
|
piocb[0] = &aio->aiocb;
|
||||||
|
|
||||||
|
n = io_submit(ngx_aio_ctx, 1, piocb);
|
||||||
|
|
||||||
|
if (n == 1) {
|
||||||
|
return NGX_AGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = -n;
|
||||||
|
|
||||||
|
if (n == NGX_EAGAIN) {
|
||||||
|
return ngx_read_file(file, buf, size, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_log_error(NGX_LOG_CRIT, file->log, n,
|
||||||
|
"io_submit(\"%V\") failed", &file->name);
|
||||||
|
|
||||||
|
if (n == NGX_ENOSYS) {
|
||||||
|
enosys = 1;
|
||||||
|
return ngx_read_file(file, buf, size, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
ngx_file_aio_event_handler(ngx_event_t *ev)
|
||||||
|
{
|
||||||
|
ngx_event_aio_t *aio;
|
||||||
|
|
||||||
|
aio = ev->data;
|
||||||
|
|
||||||
|
ngx_log_debug2(NGX_LOG_DEBUG_CORE, ev->log, 0,
|
||||||
|
"aio event handler fd:%d %V", aio->fd, &aio->file->name);
|
||||||
|
|
||||||
|
aio->handler(ev);
|
||||||
|
}
|
|
@ -81,6 +81,13 @@ extern ssize_t sendfile(int s, int fd, int32_t *offset, size_t size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <linux/aio_abi.h>
|
||||||
|
typedef struct iocb ngx_aiocb_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define NGX_LISTEN_BACKLOG 511
|
#define NGX_LISTEN_BACKLOG 511
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -112,6 +112,12 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if (NGX_HAVE_FILE_AIO)
|
||||||
|
#include <aio.h>
|
||||||
|
typedef struct aiocb ngx_aiocb_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define NGX_LISTEN_BACKLOG 511
|
#define NGX_LISTEN_BACKLOG 511
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -62,16 +62,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if (NGX_HAVE_SENDFILE)
|
|
||||||
#include <sys/sendfile.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if (NGX_HAVE_AIO)
|
|
||||||
#include <aio.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if (NGX_HAVE_DEVPOLL)
|
#if (NGX_HAVE_DEVPOLL)
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/devpoll.h>
|
#include <sys/devpoll.h>
|
||||||
|
@ -83,6 +73,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if (NGX_HAVE_SENDFILE)
|
||||||
|
#include <sys/sendfile.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define NGX_LISTEN_BACKLOG 511
|
#define NGX_LISTEN_BACKLOG 511
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue