Hi, On Thu, Sep 13, 2018 at 09:10:23PM +0300, Maxim Dounin wrote: > Hello! > > On Tue, Sep 04, 2018 at 04:58:05PM -0700, Ka-Hing Cheung via nginx-devel > wrote: > > > On Mon, Sep 3, 2018 at 9:09 AM, Maxim Dounin <mdou...@mdounin.ru> wrote:
[..] Here's another approach to thread open. This time it's 4 patches: - #1 a small open file cache refactoring - #2 thread open in open file cache - #3 thread open in http static module - #4 thread open in http file cache -- Roman Arutyunyan
# HG changeset patch # User Roman Arutyunyan <a...@nginx.com> # Date 1538143636 -10800 # Fri Sep 28 17:07:16 2018 +0300 # Node ID 1ebbfd3e3cd814e4428561b814a5684c69668ba4 # Parent cd4fa2fab8d8f1a2d03841249230bed76d318502 Prepared open file cache for async open. Specifically, several open file cache internal functions now receive pool instead of log and return file descriptor in the ngx_open_file_info_t structure instead of returning it directtly. diff --git a/src/core/ngx_open_file_cache.c b/src/core/ngx_open_file_cache.c --- a/src/core/ngx_open_file_cache.c +++ b/src/core/ngx_open_file_cache.c @@ -30,13 +30,13 @@ static ngx_int_t ngx_file_o_path_info(ng ngx_log_t *log); #endif #endif -static ngx_fd_t ngx_open_file_wrapper(ngx_str_t *name, +static ngx_int_t ngx_open_file_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, ngx_int_t mode, ngx_int_t create, - ngx_int_t access, ngx_log_t *log); + ngx_int_t access, ngx_pool_t *pool); static ngx_int_t ngx_file_info_wrapper(ngx_str_t *name, - ngx_open_file_info_t *of, ngx_file_info_t *fi, ngx_log_t *log); + ngx_open_file_info_t *of, ngx_file_info_t *fi, ngx_pool_t *pool); static ngx_int_t ngx_open_and_stat_file(ngx_str_t *name, - ngx_open_file_info_t *of, ngx_log_t *log); + ngx_open_file_info_t *of, ngx_pool_t *pool); static void ngx_open_file_add_event(ngx_open_file_cache_t *cache, ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log); static void ngx_open_file_cleanup(void *data); @@ -160,10 +160,9 @@ ngx_open_cached_file(ngx_open_file_cache if (of->test_only) { - if (ngx_file_info_wrapper(name, of, &fi, pool->log) - == NGX_FILE_ERROR) - { - return NGX_ERROR; + rc = ngx_file_info_wrapper(name, of, &fi, pool); + if (rc != NGX_OK) { + return rc; } of->uniq = ngx_file_uniq(&fi); @@ -183,7 +182,7 @@ ngx_open_cached_file(ngx_open_file_cache return NGX_ERROR; } - rc = ngx_open_and_stat_file(name, of, pool->log); + rc = ngx_open_and_stat_file(name, of, pool); if (rc == NGX_OK && !of->is_dir) { cln->handler = ngx_pool_cleanup_file; @@ -218,7 +217,7 @@ ngx_open_cached_file(ngx_open_file_cache /* file was not used often enough to keep open */ - rc = ngx_open_and_stat_file(name, of, pool->log); + rc = ngx_open_and_stat_file(name, of, pool); if (rc != NGX_OK && (of->err == 0 || !of->errors)) { goto failed; @@ -286,7 +285,7 @@ ngx_open_cached_file(ngx_open_file_cache of->fd = file->fd; of->uniq = file->uniq; - rc = ngx_open_and_stat_file(name, of, pool->log); + rc = ngx_open_and_stat_file(name, of, pool); if (rc != NGX_OK && (of->err == 0 || !of->errors)) { goto failed; @@ -351,7 +350,7 @@ ngx_open_cached_file(ngx_open_file_cache /* not found */ - rc = ngx_open_and_stat_file(name, of, pool->log); + rc = ngx_open_and_stat_file(name, of, pool); if (rc != NGX_OK && (of->err == 0 || !of->errors)) { goto failed; @@ -610,40 +609,38 @@ ngx_file_o_path_info(ngx_fd_t fd, ngx_fi #endif /* NGX_HAVE_OPENAT */ -static ngx_fd_t +static ngx_int_t ngx_open_file_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, - ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log) + ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_pool_t *pool) { - ngx_fd_t fd; - #if !(NGX_HAVE_OPENAT) - fd = ngx_open_file(name->data, mode, create, access); + of->fd = ngx_open_file(name->data, mode, create, access); - if (fd == NGX_INVALID_FILE) { + if (of->fd == NGX_INVALID_FILE) { of->err = ngx_errno; of->failed = ngx_open_file_n; - return NGX_INVALID_FILE; + return NGX_ERROR; } - return fd; + return NGX_OK; #else - u_char *p, *cp, *end; - ngx_fd_t at_fd; - ngx_str_t at_name; + u_char *p, *cp, *end; + ngx_fd_t fd, at_fd; + ngx_str_t at_name; if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) { - fd = ngx_open_file(name->data, mode, create, access); + of->fd = ngx_open_file(name->data, mode, create, access); - if (fd == NGX_INVALID_FILE) { + if (of->fd == NGX_INVALID_FILE) { of->err = ngx_errno; of->failed = ngx_open_file_n; - return NGX_INVALID_FILE; + return NGX_ERROR; } - return fd; + return NGX_OK; } p = name->data; @@ -665,7 +662,7 @@ ngx_open_file_wrapper(ngx_str_t *name, n if (at_fd == NGX_INVALID_FILE) { of->err = ngx_errno; of->failed = ngx_open_file_n; - return NGX_INVALID_FILE; + return NGX_ERROR; } at_name.len = of->disable_symlinks_from; @@ -680,7 +677,7 @@ ngx_open_file_wrapper(ngx_str_t *name, n if (at_fd == NGX_INVALID_FILE) { of->err = ngx_errno; of->failed = ngx_openat_file_n; - return NGX_INVALID_FILE; + return NGX_ERROR; } at_name.len = 1; @@ -706,7 +703,7 @@ ngx_open_file_wrapper(ngx_str_t *name, n if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) { fd = ngx_openat_file_owner(at_fd, p, NGX_FILE_SEARCH|NGX_FILE_NONBLOCK, - NGX_FILE_OPEN, 0, log); + NGX_FILE_OPEN, 0, pool->log); } else { fd = ngx_openat_file(at_fd, p, @@ -723,7 +720,7 @@ ngx_open_file_wrapper(ngx_str_t *name, n } if (at_fd != NGX_AT_FDCWD && ngx_close_file(at_fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, ngx_close_file_n " \"%V\" failed", &at_name); } @@ -752,7 +749,7 @@ ngx_open_file_wrapper(ngx_str_t *name, n if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER && !(create & (NGX_FILE_CREATE_OR_OPEN|NGX_FILE_TRUNCATE))) { - fd = ngx_openat_file_owner(at_fd, p, mode, create, access, log); + fd = ngx_openat_file_owner(at_fd, p, mode, create, access, pool->log); } else { fd = ngx_openat_file(at_fd, p, mode|NGX_FILE_NOFOLLOW, create, access); @@ -768,18 +765,20 @@ done: failed: if (at_fd != NGX_AT_FDCWD && ngx_close_file(at_fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, ngx_close_file_n " \"%V\" failed", &at_name); } - return fd; + of->fd = fd; + + return fd == NGX_INVALID_FILE ? NGX_ERROR : NGX_OK; #endif } static ngx_int_t ngx_file_info_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, - ngx_file_info_t *fi, ngx_log_t *log) + ngx_file_info_t *fi, ngx_pool_t *pool) { ngx_int_t rc; @@ -790,15 +789,13 @@ ngx_file_info_wrapper(ngx_str_t *name, n if (rc == NGX_FILE_ERROR) { of->err = ngx_errno; of->failed = ngx_file_info_n; - return NGX_FILE_ERROR; + return NGX_ERROR; } - return rc; + return NGX_OK; #else - ngx_fd_t fd; - if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) { rc = ngx_file_info(name->data, fi); @@ -806,48 +803,55 @@ ngx_file_info_wrapper(ngx_str_t *name, n if (rc == NGX_FILE_ERROR) { of->err = ngx_errno; of->failed = ngx_file_info_n; - return NGX_FILE_ERROR; + return NGX_ERROR; } + return NGX_OK; + } + + rc = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, + NGX_FILE_OPEN, 0, pool); + if (rc != NGX_OK) { return rc; } - fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, - NGX_FILE_OPEN, 0, log); - - if (fd == NGX_INVALID_FILE) { - return NGX_FILE_ERROR; - } - - rc = ngx_fd_info(fd, fi); + rc = ngx_fd_info(of->fd, fi); if (rc == NGX_FILE_ERROR) { of->err = ngx_errno; of->failed = ngx_fd_info_n; } - if (ngx_close_file(fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + if (ngx_close_file(of->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, ngx_close_file_n " \"%V\" failed", name); } - return rc; + of->fd = NGX_INVALID_FILE; + + return rc == NGX_FILE_ERROR ? NGX_ERROR : NGX_OK; #endif } static ngx_int_t ngx_open_and_stat_file(ngx_str_t *name, ngx_open_file_info_t *of, - ngx_log_t *log) + ngx_pool_t *pool) { - ngx_fd_t fd; + ngx_int_t rc; ngx_file_info_t fi; if (of->fd != NGX_INVALID_FILE) { - if (ngx_file_info_wrapper(name, of, &fi, log) == NGX_FILE_ERROR) { + rc = ngx_file_info_wrapper(name, of, &fi, pool); + + if (rc == NGX_AGAIN) { + return NGX_AGAIN; + } + + if (rc != NGX_OK) { of->fd = NGX_INVALID_FILE; - return NGX_ERROR; + return rc; } if (of->uniq == ngx_file_uniq(&fi)) { @@ -856,9 +860,15 @@ ngx_open_and_stat_file(ngx_str_t *name, } else if (of->test_dir) { - if (ngx_file_info_wrapper(name, of, &fi, log) == NGX_FILE_ERROR) { + rc = ngx_file_info_wrapper(name, of, &fi, pool); + + if (rc == NGX_AGAIN) { + return NGX_AGAIN; + } + + if (rc != NGX_OK) { of->fd = NGX_INVALID_FILE; - return NGX_ERROR; + return rc; } if (ngx_is_dir(&fi)) { @@ -873,26 +883,25 @@ ngx_open_and_stat_file(ngx_str_t *name, * This flag has no effect on a regular files. */ - fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, - NGX_FILE_OPEN, 0, log); + rc = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, + NGX_FILE_OPEN, 0, pool); } else { - fd = ngx_open_file_wrapper(name, of, NGX_FILE_APPEND, + rc = ngx_open_file_wrapper(name, of, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN, - NGX_FILE_DEFAULT_ACCESS, log); + NGX_FILE_DEFAULT_ACCESS, pool); } - if (fd == NGX_INVALID_FILE) { - of->fd = NGX_INVALID_FILE; - return NGX_ERROR; + if (rc != NGX_OK) { + return rc; } - if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, + if (ngx_fd_info(of->fd, &fi) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, pool->log, ngx_errno, ngx_fd_info_n " \"%V\" failed", name); - if (ngx_close_file(fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + if (ngx_close_file(of->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, ngx_close_file_n " \"%V\" failed", name); } @@ -902,26 +911,24 @@ ngx_open_and_stat_file(ngx_str_t *name, } if (ngx_is_dir(&fi)) { - if (ngx_close_file(fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + if (ngx_close_file(of->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, ngx_close_file_n " \"%V\" failed", name); } of->fd = NGX_INVALID_FILE; } else { - of->fd = fd; - if (of->read_ahead && ngx_file_size(&fi) > NGX_MIN_READ_AHEAD) { - if (ngx_read_ahead(fd, of->read_ahead) == NGX_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + if (ngx_read_ahead(of->fd, of->read_ahead) == NGX_ERROR) { + ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, ngx_read_ahead_n " \"%V\" failed", name); } } if (of->directio <= ngx_file_size(&fi)) { - if (ngx_directio_on(fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + if (ngx_directio_on(of->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, ngx_directio_on_n " \"%V\" failed", name); } else {
# HG changeset patch # User Roman Arutyunyan <a...@nginx.com> # Date 1538644508 -10800 # Thu Oct 04 12:15:08 2018 +0300 # Node ID 82f2dea6f3c6e3edf78968ab9f623d7b92e074fd # Parent 1ebbfd3e3cd814e4428561b814a5684c69668ba4 Threaded open support in open file cache. diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h --- a/src/core/ngx_file.h +++ b/src/core/ngx_file.h @@ -17,6 +17,7 @@ struct ngx_file_s { ngx_fd_t fd; ngx_str_t name; ngx_file_info_t info; + ngx_err_t err; off_t offset; off_t sys_offset; diff --git a/src/core/ngx_open_file_cache.c b/src/core/ngx_open_file_cache.c --- a/src/core/ngx_open_file_cache.c +++ b/src/core/ngx_open_file_cache.c @@ -177,14 +177,21 @@ ngx_open_cached_file(ngx_open_file_cache return NGX_OK; } - cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t)); - if (cln == NULL) { - return NGX_ERROR; - } - rc = ngx_open_and_stat_file(name, of, pool); if (rc == NGX_OK && !of->is_dir) { + cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t)); + + if (cln == NULL) { + if (ngx_close_file(of->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", + name->data); + } + + return NGX_ERROR; + } + cln->handler = ngx_pool_cleanup_file; clnf = cln->data; @@ -196,6 +203,11 @@ ngx_open_cached_file(ngx_open_file_cache return rc; } +#if (NGX_THREADS) + /* disable thread open if cache is enabled */ + of->thread_handler = NULL; +#endif + cln = ngx_pool_cleanup_add(pool, sizeof(ngx_open_file_cache_cleanup_t)); if (cln == NULL) { return NGX_ERROR; @@ -613,6 +625,40 @@ static ngx_int_t ngx_open_file_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_pool_t *pool) { +#if (NGX_THREADS) + + if (of->thread_handler) { + ngx_int_t rc; + ngx_file_t file; + + ngx_memzero(&file, sizeof(ngx_file_t)); + + file.log = pool->log; + file.fd = NGX_INVALID_FILE; + file.thread_handler = of->thread_handler; + file.thread_ctx = of->thread_ctx; + file.thread_task = of->thread_task; + + rc = ngx_thread_open(&file, name->data, mode, create, access, pool); + + if (rc == NGX_AGAIN) { + of->thread_task = file.thread_task; + return NGX_AGAIN; + } + + if (rc != NGX_OK) { + of->err = file.err; + of->failed = ngx_open_file_n; + return NGX_ERROR; + } + + of->fd = file.fd; + + return NGX_OK; + } + +#endif + #if !(NGX_HAVE_OPENAT) of->fd = ngx_open_file(name->data, mode, create, access); diff --git a/src/core/ngx_open_file_cache.h b/src/core/ngx_open_file_cache.h --- a/src/core/ngx_open_file_cache.h +++ b/src/core/ngx_open_file_cache.h @@ -32,6 +32,13 @@ typedef struct { ngx_uint_t min_uses; +#if (NGX_THREADS || NGX_COMPAT) + ngx_int_t (*thread_handler)(ngx_thread_task_t *task, + ngx_file_t *file); + void *thread_ctx; + ngx_thread_task_t *thread_task; +#endif + #if (NGX_HAVE_OPENAT) size_t disable_symlinks_from; unsigned disable_symlinks:2; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -420,6 +420,13 @@ static ngx_command_t ngx_http_core_comm offsetof(ngx_http_core_loc_conf_t, aio_write), NULL }, + { ngx_string("aio_open"), + 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_open), + NULL }, + { ngx_string("read_ahead"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, @@ -3380,6 +3387,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t clcf->subrequest_output_buffer_size = NGX_CONF_UNSET_SIZE; clcf->aio = NGX_CONF_UNSET; clcf->aio_write = NGX_CONF_UNSET; + clcf->aio_open = NGX_CONF_UNSET; #if (NGX_THREADS) clcf->thread_pool = NGX_CONF_UNSET_PTR; clcf->thread_pool_value = NGX_CONF_UNSET_PTR; @@ -3605,6 +3613,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t (size_t) ngx_pagesize); ngx_conf_merge_value(conf->aio, prev->aio, NGX_HTTP_AIO_OFF); ngx_conf_merge_value(conf->aio_write, prev->aio_write, 0); + ngx_conf_merge_value(conf->aio_open, prev->aio_open, 0); #if (NGX_THREADS) ngx_conf_merge_ptr_value(conf->thread_pool, prev->thread_pool, NULL); ngx_conf_merge_ptr_value(conf->thread_pool_value, prev->thread_pool_value, diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -382,6 +382,7 @@ struct ngx_http_core_loc_conf_s { ngx_flag_t sendfile; /* sendfile */ ngx_flag_t aio; /* aio */ ngx_flag_t aio_write; /* aio_write */ + ngx_flag_t aio_open; /* aio_open */ ngx_flag_t tcp_nopush; /* tcp_nopush */ ngx_flag_t tcp_nodelay; /* tcp_nodelay */ ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */ diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -11,6 +11,7 @@ #if (NGX_THREADS) #include <ngx_thread_pool.h> +static void ngx_thread_open_handler(void *data, ngx_log_t *log); static void ngx_thread_read_handler(void *data, ngx_log_t *log); static void ngx_thread_write_chain_to_file_handler(void *data, ngx_log_t *log); #endif @@ -77,20 +78,112 @@ ngx_read_file(ngx_file_t *file, u_char * #if (NGX_THREADS) +typedef enum { + NGX_THREAD_FILE_OPEN = 1, + NGX_THREAD_FILE_READ, + NGX_THREAD_FILE_WRITE +} ngx_thread_file_op_e; + + typedef struct { ngx_fd_t fd; - ngx_uint_t write; /* unsigned write:1; */ + u_char *name; + ngx_uint_t op; /* ngx_thread_file_op_e */ u_char *buf; size_t size; ngx_chain_t *chain; off_t offset; + ngx_int_t mode; + ngx_int_t create; + ngx_int_t access; + size_t nbytes; ngx_err_t err; } ngx_thread_file_ctx_t; +ngx_int_t +ngx_thread_open(ngx_file_t *file, u_char *name, ngx_int_t mode, + ngx_int_t create, ngx_int_t access, ngx_pool_t *pool) +{ + ngx_thread_task_t *task; + ngx_thread_file_ctx_t *ctx; + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0, + "thread open: \"%s\"", name); + + task = file->thread_task; + + if (task == NULL) { + task = ngx_thread_task_alloc(pool, sizeof(ngx_thread_file_ctx_t)); + if (task == NULL) { + return NGX_ERROR; + } + + file->thread_task = task; + } + + ctx = task->ctx; + + if (task->event.complete) { + task->event.complete = 0; + + if (ctx->op != NGX_THREAD_FILE_OPEN) { + ngx_log_error(NGX_LOG_ALERT, file->log, 0, + "invalid thread operation, open expected"); + return NGX_ERROR; + } + + if (ctx->err) { + file->err = ctx->err; + return NGX_ERROR; + } + + file->fd = ctx->fd; + + return NGX_OK; + } + + task->handler = ngx_thread_open_handler; + + ctx->op = NGX_THREAD_FILE_OPEN; + + ctx->name = name; + ctx->mode = mode; + ctx->create = create; + ctx->access = access; + + if (file->thread_handler(task, file) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_AGAIN; +} + + +static void +ngx_thread_open_handler(void *data, ngx_log_t *log) +{ + ngx_thread_file_ctx_t *ctx = data; + + ngx_fd_t fd; + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "thread open handler"); + + fd = ngx_open_file(ctx->name, ctx->mode, ctx->create, ctx->access); + + if (fd == NGX_INVALID_FILE) { + ctx->err = ngx_errno; + + } else { + ctx->fd = fd; + ctx->err = 0; + } +} + + ssize_t ngx_thread_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, ngx_pool_t *pool) @@ -118,9 +211,9 @@ ngx_thread_read(ngx_file_t *file, u_char if (task->event.complete) { task->event.complete = 0; - if (ctx->write) { + if (ctx->op != NGX_THREAD_FILE_READ) { ngx_log_error(NGX_LOG_ALERT, file->log, 0, - "invalid thread call, read instead of write"); + "invalid thread operation, read expected"); return NGX_ERROR; } @@ -135,7 +228,7 @@ ngx_thread_read(ngx_file_t *file, u_char task->handler = ngx_thread_read_handler; - ctx->write = 0; + ctx->op = NGX_THREAD_FILE_READ; ctx->fd = file->fd; ctx->buf = buf; @@ -501,9 +594,9 @@ ngx_thread_write_chain_to_file(ngx_file_ if (task->event.complete) { task->event.complete = 0; - if (!ctx->write) { + if (ctx->op != NGX_THREAD_FILE_WRITE) { ngx_log_error(NGX_LOG_ALERT, file->log, 0, - "invalid thread call, write instead of read"); + "invalid thread operation, write expected"); return NGX_ERROR; } @@ -519,7 +612,7 @@ ngx_thread_write_chain_to_file(ngx_file_ task->handler = ngx_thread_write_chain_to_file_handler; - ctx->write = 1; + ctx->op = NGX_THREAD_FILE_WRITE; ctx->fd = file->fd; ctx->chain = cl; diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h --- a/src/os/unix/ngx_files.h +++ b/src/os/unix/ngx_files.h @@ -385,6 +385,8 @@ extern ngx_uint_t ngx_file_aio; #endif #if (NGX_THREADS) +ngx_int_t ngx_thread_open(ngx_file_t *file, u_char *name, + ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_pool_t *pool); ssize_t ngx_thread_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, ngx_pool_t *pool); ssize_t ngx_thread_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl,
# HG changeset patch # User Roman Arutyunyan <a...@nginx.com> # Date 1538403503 -10800 # Mon Oct 01 17:18:23 2018 +0300 # Node ID 68e2acd8c4cf81cdbe57c0a83bbafe43072cb9b5 # Parent 82f2dea6f3c6e3edf78968ab9f623d7b92e074fd Static: support for threaded open. diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -11,7 +11,21 @@ static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_static_send(ngx_http_request_t *r); static ngx_int_t ngx_http_static_init(ngx_conf_t *cf); +#if (NGX_THREADS) +static void ngx_http_static_write_event_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_static_thread_handler(ngx_thread_task_t *task, + ngx_file_t *file); +static void ngx_http_static_thread_event_handler(ngx_event_t *ev); +#endif + + +typedef struct { + u_char *last; + ngx_str_t path; + ngx_open_file_info_t of; +} ngx_http_static_ctx_t; static ngx_http_module_t ngx_http_static_module_ctx = { @@ -48,15 +62,9 @@ ngx_module_t ngx_http_static_module = { static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r) { - u_char *last, *location; - size_t root, len; - ngx_str_t path; + size_t root; ngx_int_t rc; - ngx_uint_t level; - ngx_log_t *log; - ngx_buf_t *b; - ngx_chain_t out; - ngx_open_file_info_t of; + ngx_http_static_ctx_t *ctx; ngx_http_core_loc_conf_t *clcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { @@ -67,42 +75,94 @@ ngx_http_static_handler(ngx_http_request return NGX_DECLINED; } - log = r->connection->log; + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_static_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_static_module); /* * ngx_http_map_uri_to_path() allocates memory for terminating '\0' * so we do not need to reserve memory for '/' for possible redirect */ - last = ngx_http_map_uri_to_path(r, &path, &root, 0); - if (last == NULL) { + ctx->last = ngx_http_map_uri_to_path(r, &ctx->path, &root, 0); + if (ctx->last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - path.len = last - path.data; + ctx->path.len = ctx->last - ctx->path.data; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "http filename: \"%s\"", path.data); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http filename: \"%s\"", ctx->path.data); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + ctx->of.read_ahead = clcf->read_ahead; + ctx->of.directio = clcf->directio; + ctx->of.valid = clcf->open_file_cache_valid; + ctx->of.min_uses = clcf->open_file_cache_min_uses; + ctx->of.errors = clcf->open_file_cache_errors; + ctx->of.events = clcf->open_file_cache_events; - of.read_ahead = clcf->read_ahead; - of.directio = clcf->directio; - of.valid = clcf->open_file_cache_valid; - of.min_uses = clcf->open_file_cache_min_uses; - of.errors = clcf->open_file_cache_errors; - of.events = clcf->open_file_cache_events; +#if (NGX_THREADS) + if (clcf->aio == NGX_HTTP_AIO_THREADS && clcf->aio_open) { + ctx->of.thread_handler = ngx_http_static_thread_handler; + ctx->of.thread_ctx = r; + } +#endif - if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { + if (ngx_http_set_disable_symlinks(r, clcf, &ctx->path, &ctx->of) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) - != NGX_OK) - { - switch (of.err) { + rc = ngx_http_static_send(r); + +#if (NGX_THREADS) + if (rc == NGX_DONE) { + r->main->count++; + r->write_event_handler = ngx_http_static_write_event_handler; + } +#endif + + return rc; +} + + +static ngx_int_t +ngx_http_static_send(ngx_http_request_t *r) +{ + u_char *location; + size_t len; + ngx_log_t *log; + ngx_int_t rc; + ngx_uint_t level; + ngx_buf_t *b; + ngx_chain_t out; + ngx_http_static_ctx_t *ctx; + ngx_http_core_loc_conf_t *clcf; + + ctx = ngx_http_get_module_ctx(r, ngx_http_static_module); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http static send: \"%s\"", ctx->path.data); + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + log = r->connection->log; + + rc = ngx_open_cached_file(clcf->open_file_cache, &ctx->path, &ctx->of, + r->pool); + +#if (NGX_THREADS) + if (rc == NGX_AGAIN) { + return NGX_DONE; + } +#endif + + if (rc != NGX_OK) { + switch (ctx->of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -133,8 +193,8 @@ ngx_http_static_handler(ngx_http_request } if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { - ngx_log_error(level, log, of.err, - "%s \"%s\" failed", of.failed, path.data); + ngx_log_error(level, log, ctx->of.err, + "%s \"%s\" failed", ctx->of.failed, ctx->path.data); } return rc; @@ -142,9 +202,10 @@ ngx_http_static_handler(ngx_http_request r->root_tested = !r->error_page; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", + ctx->of.fd); - if (of.is_dir) { + if (ctx->of.is_dir) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir"); @@ -158,9 +219,9 @@ ngx_http_static_handler(ngx_http_request len = r->uri.len + 1; if (!clcf->alias && clcf->root_lengths == NULL && r->args.len == 0) { - location = path.data + clcf->root.len; + location = ctx->path.data + clcf->root.len; - *last = '/'; + *ctx->last = '/'; } else { if (r->args.len) { @@ -173,13 +234,13 @@ ngx_http_static_handler(ngx_http_request return NGX_HTTP_INTERNAL_SERVER_ERROR; } - last = ngx_copy(location, r->uri.data, r->uri.len); + ctx->last = ngx_copy(location, r->uri.data, r->uri.len); - *last = '/'; + *ctx->last = '/'; if (r->args.len) { - *++last = '?'; - ngx_memcpy(++last, r->args.data, r->args.len); + *++ctx->last = '?'; + ngx_memcpy(++ctx->last, r->args.data, r->args.len); } } @@ -193,9 +254,9 @@ ngx_http_static_handler(ngx_http_request #if !(NGX_WIN32) /* the not regular files are probably Unix specific */ - if (!of.is_file) { + if (!ctx->of.is_file) { ngx_log_error(NGX_LOG_CRIT, log, 0, - "\"%s\" is not a regular file", path.data); + "\"%s\" is not a regular file", ctx->path.data); return NGX_HTTP_NOT_FOUND; } @@ -215,8 +276,8 @@ ngx_http_static_handler(ngx_http_request log->action = "sending response to client"; r->headers_out.status = NGX_HTTP_OK; - r->headers_out.content_length_n = of.size; - r->headers_out.last_modified_time = of.mtime; + r->headers_out.content_length_n = ctx->of.size; + r->headers_out.last_modified_time = ctx->of.mtime; if (ngx_http_set_etag(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -226,7 +287,7 @@ ngx_http_static_handler(ngx_http_request return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (r != r->main && of.size == 0) { + if (r != r->main && ctx->of.size == 0) { return ngx_http_send_header(r); } @@ -251,16 +312,16 @@ ngx_http_static_handler(ngx_http_request } b->file_pos = 0; - b->file_last = of.size; + b->file_last = ctx->of.size; b->in_file = b->file_last ? 1: 0; b->last_buf = (r == r->main) ? 1: 0; b->last_in_chain = 1; - b->file->fd = of.fd; - b->file->name = path; + b->file->fd = ctx->of.fd; + b->file->name = ctx->path; b->file->log = log; - b->file->directio = of.is_directio; + b->file->directio = ctx->of.is_directio; out.buf = b; out.next = NULL; @@ -269,6 +330,90 @@ ngx_http_static_handler(ngx_http_request } +#if (NGX_THREADS) + +static void +ngx_http_static_write_event_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + + rc = ngx_http_static_send(r); + + if (rc != NGX_DONE) { + ngx_http_finalize_request(r, rc); + } +} + + +static ngx_int_t +ngx_http_static_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) +{ + ngx_str_t name; + ngx_thread_pool_t *tp; + ngx_http_request_t *r; + ngx_http_core_loc_conf_t *clcf; + + r = file->thread_ctx; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + tp = clcf->thread_pool; + + if (tp == NULL) { + if (ngx_http_complex_value(r, clcf->thread_pool_value, &name) + != NGX_OK) + { + return NGX_ERROR; + } + + tp = ngx_thread_pool_get((ngx_cycle_t *) ngx_cycle, &name); + + if (tp == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "thread pool \"%V\" not found", &name); + return NGX_ERROR; + } + } + + task->event.data = r; + task->event.handler = ngx_http_static_thread_event_handler; + + if (ngx_thread_task_post(tp, task) != NGX_OK) { + return NGX_ERROR; + } + + r->main->blocked++; + r->aio = 1; + + return NGX_OK; +} + + +static void +ngx_http_static_thread_event_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + ngx_http_request_t *r; + + r = ev->data; + c = r->connection; + + ngx_http_set_log_request(c->log, r); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http static thread: \"%V?%V\"", &r->uri, &r->args); + + r->main->blocked--; + r->aio = 0; + + r->write_event_handler(r); + + ngx_http_run_posted_requests(c); +} + +#endif + + static ngx_int_t ngx_http_static_init(ngx_conf_t *cf) {
# HG changeset patch # User Roman Arutyunyan <a...@nginx.com> # Date 1538403511 -10800 # Mon Oct 01 17:18:31 2018 +0300 # Node ID 8f502ffdfbc032b30f45e6d4271b0822b01c2558 # Parent 68e2acd8c4cf81cdbe57c0a83bbafe43072cb9b5 Threaded open support in http file cache. diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h --- a/src/http/ngx_http_cache.h +++ b/src/http/ngx_http_cache.h @@ -69,6 +69,7 @@ struct ngx_http_cache_s { u_char key[NGX_HTTP_CACHE_KEY_LEN]; u_char main[NGX_HTTP_CACHE_KEY_LEN]; + ngx_open_file_info_t of; ngx_file_uniq_t uniq; time_t valid_sec; time_t updating_sec; diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -18,6 +18,8 @@ static void ngx_http_file_cache_lock_wai ngx_http_cache_t *c); static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c); +static ngx_int_t ngx_http_file_cache_aio_open(ngx_http_request_t *r, + ngx_http_cache_t *c); static ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c); #if (NGX_HAVE_FILE_AIO) @@ -264,13 +266,11 @@ ngx_http_file_cache_create_key(ngx_http_ ngx_int_t ngx_http_file_cache_open(ngx_http_request_t *r) { - ngx_int_t rc, rv; - ngx_uint_t test; - ngx_http_cache_t *c; - ngx_pool_cleanup_t *cln; - ngx_open_file_info_t of; - ngx_http_file_cache_t *cache; - ngx_http_core_loc_conf_t *clcf; + ngx_int_t rc; + ngx_uint_t test; + ngx_http_cache_t *c; + ngx_pool_cleanup_t *cln; + ngx_http_file_cache_t *cache; c = r->cache; @@ -315,7 +315,6 @@ ngx_http_file_cache_open(ngx_http_reques c->temp_file = 1; test = c->exists ? 1 : 0; - rv = NGX_DECLINED; } else { /* rc == NGX_DECLINED */ @@ -327,11 +326,10 @@ ngx_http_file_cache_open(ngx_http_reques return NGX_HTTP_CACHE_SCARCE; } - rv = NGX_HTTP_CACHE_SCARCE; + c->temp_file = 0; } else { c->temp_file = 1; - rv = NGX_DECLINED; } } @@ -340,62 +338,10 @@ ngx_http_file_cache_open(ngx_http_reques } if (!test) { - goto done; - } - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - ngx_memzero(&of, sizeof(ngx_open_file_info_t)); - - of.uniq = c->uniq; - of.valid = clcf->open_file_cache_valid; - of.min_uses = clcf->open_file_cache_min_uses; - of.events = clcf->open_file_cache_events; - of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; - of.read_ahead = clcf->read_ahead; - - if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool) - != NGX_OK) - { - switch (of.err) { - - case 0: - return NGX_ERROR; - - case NGX_ENOENT: - case NGX_ENOTDIR: - goto done; - - default: - ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, - ngx_open_file_n " \"%s\" failed", c->file.name.data); - return NGX_ERROR; - } - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http file cache fd: %d", of.fd); - - c->file.fd = of.fd; - c->file.log = r->connection->log; - c->uniq = of.uniq; - c->length = of.size; - c->fs_size = (of.fs_size + cache->bsize - 1) / cache->bsize; - - c->buf = ngx_create_temp_buf(r->pool, c->body_start); - if (c->buf == NULL) { - return NGX_ERROR; - } - - return ngx_http_file_cache_read(r, c); - -done: - - if (rv == NGX_DECLINED) { return ngx_http_file_cache_lock(r, c); } - return rv; + return ngx_http_file_cache_read(r, c); } @@ -405,6 +351,10 @@ ngx_http_file_cache_lock(ngx_http_reques ngx_msec_t now, timer; ngx_http_file_cache_t *cache; + if (!c->temp_file) { + return NGX_HTTP_CACHE_SCARCE; + } + if (!c->lock) { return NGX_DECLINED; } @@ -534,6 +484,12 @@ ngx_http_file_cache_read(ngx_http_reques ngx_http_file_cache_t *cache; ngx_http_file_cache_header_t *h; + rc = ngx_http_file_cache_aio_open(r, c); + + if (rc != NGX_OK) { + return rc; + } + n = ngx_http_file_cache_aio_read(r, c); if (n < 0) { @@ -663,6 +619,88 @@ ngx_http_file_cache_read(ngx_http_reques } +static ngx_int_t +ngx_http_file_cache_aio_open(ngx_http_request_t *r, ngx_http_cache_t *c) +{ + ngx_int_t rc; + ngx_http_file_cache_t *cache; + ngx_http_core_loc_conf_t *clcf; + + if (c->file.fd != NGX_INVALID_FILE) { + return NGX_OK; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (!c->reading) { + ngx_memzero(&c->of, sizeof(ngx_open_file_info_t)); + + c->of.uniq = c->uniq; + c->of.valid = clcf->open_file_cache_valid; + c->of.min_uses = clcf->open_file_cache_min_uses; + c->of.events = clcf->open_file_cache_events; + c->of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; + c->of.read_ahead = clcf->read_ahead; + +#if (NGX_THREADS) + if (clcf->aio == NGX_HTTP_AIO_THREADS && clcf->aio_open) { + c->of.thread_task = c->thread_task; + c->of.thread_handler = ngx_http_cache_thread_handler; + c->of.thread_ctx = r; + } +#endif + } + + rc = ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &c->of, + r->pool); + +#if (NGX_THREADS) + + if (rc == NGX_AGAIN) { + c->reading = 1; + return NGX_AGAIN; + } + + c->reading = 0; + +#endif + + if (rc != NGX_OK) { + switch (c->of.err) { + + case NGX_OK: + return NGX_ERROR; + + case NGX_ENOENT: + case NGX_ENOTDIR: + return ngx_http_file_cache_lock(r, c); + + default: + ngx_log_error(NGX_LOG_CRIT, r->connection->log, c->of.err, + ngx_open_file_n " \"%s\" failed", c->file.name.data); + return NGX_ERROR; + } + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache fd: %d", c->of.fd); + + cache = c->file_cache; + c->file.fd = c->of.fd; + c->file.log = r->connection->log; + c->uniq = c->of.uniq; + c->length = c->of.size; + c->fs_size = (c->of.fs_size + cache->bsize - 1) / cache->bsize; + + c->buf = ngx_create_temp_buf(r->pool, c->body_start); + if (c->buf == NULL) { + return NGX_ERROR; + } + + return NGX_OK; +} + + static ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c) { @@ -1229,6 +1267,7 @@ ngx_http_file_cache_reopen(ngx_http_requ ngx_shmtx_unlock(&cache->shpool->mutex); c->secondary = 1; + c->file.fd = NGX_INVALID_FILE; c->file.name.len = 0; c->body_start = c->buf->end - c->buf->start;
_______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel