# HG changeset patch # User Igor Sysoev # Date 1250452800 -14400 # Node ID 43cc6f0b77ce54e4e03b33189a34f99beecffe34 # Parent 16d97d9e72b799678af6811b1db5eb0d7a49f1a0 nginx 0.8.9 *) Feature: now the start cache loader runs in a separate process; this should improve large caches handling. *) Feature: now temporarily files and permanent storage area may reside at different file systems. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,13 @@ +Changes with nginx 0.8.9 17 Aug 2009 + + *) Feature: now the start cache loader runs in a separate process; this + should improve large caches handling. + + *) Feature: now temporarily files and permanent storage area may reside + at different file systems. + + Changes with nginx 0.8.8 10 Aug 2009 *) Bugfix: in handling FastCGI headers split in records. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,13 @@ +Изменения в nginx 0.8.9 17.08.2009 + + *) Добавление: теперь стартовый загрузчик кэша работает в отдельном + процесс; это должно улучшить обработку больших кэшей. + + *) Добавление: теперь временные файлы и постоянное место хранения могут + располагаться на разных файловых системах. + + Изменения в nginx 0.8.8 10.08.2009 *) Исправление: в обработке заголовков ответа, разделённых в diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,8 +8,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 8008 -#define NGINX_VERSION "0.8.8" +#define nginx_version 8009 +#define NGINX_VERSION "0.8.9" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -99,13 +99,7 @@ ngx_create_temp_file(ngx_file_t *file, n continue; } - if ((path->level[0] == 0) - || (err != NGX_ENOENT -#if (NGX_WIN32) - && err != NGX_ENOTDIR -#endif - )) - { + if ((path->level[0] == 0) || (err != NGX_ENOPATH)) { ngx_log_error(NGX_LOG_CRIT, file->log, err, ngx_open_tempfile_n " \"%s\" failed", file->name.data); @@ -264,7 +258,8 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, n } path->len = 0; - path->manager = (ngx_path_manager_pt) cmd->post; + path->manager = NULL; + path->loader = NULL; path->conf_file = cf->conf_file->file.name.data; path->line = cf->conf_file->line; @@ -325,6 +320,7 @@ ngx_conf_merge_path_value(ngx_conf_t *cf + init->level[2] + (init->level[2] ? 1 : 0); (*path)->manager = NULL; + (*path)->loader = NULL; (*path)->conf_file = NULL; if (ngx_add_path(cf, path) != NGX_OK) { @@ -528,7 +524,9 @@ ngx_create_pathes(ngx_cycle_t *cycle, ng ngx_int_t ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext) { - ngx_err_t err; + u_char *name; + ngx_err_t err; + ngx_copy_file_t cf; #if !(NGX_WIN32) @@ -558,14 +556,8 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_ err = ngx_errno; - if (err -#if (NGX_WIN32) - == ERROR_PATH_NOT_FOUND -#else - == NGX_ENOENT -#endif - ) - { + if (err == NGX_ENOPATH) { + if (!ext->create_path) { goto failed; } @@ -605,6 +597,44 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_ #endif + if (err == NGX_EXDEV) { + + cf.size = -1; + cf.buf_size = 0; + cf.access = ext->access; + cf.time = ext->time; + cf.log = ext->log; + + name = ngx_alloc(to->len + 1 + 10, ext->log); + if (name == NULL) { + return NGX_ERROR; + } + + (void) ngx_sprintf(name, "%*s.%010uD%Z", to->len - 1, to->data, + (uint32_t) ngx_next_temp_number(0)); + + if (ngx_copy_file(src->data, name, &cf) == NGX_OK) { + + if (ngx_rename_file(name, to->data) == NGX_FILE_ERROR) { + ngx_free(name); + goto failed; + } + + ngx_free(name); + + if (ngx_delete_file(src->data) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, + ngx_delete_file_n " \"%s\" failed", src->data); + + return NGX_ERROR; + } + + return NGX_OK; + } + + ngx_free(name); + } + failed: if (ext->delete_file) { @@ -614,15 +644,141 @@ failed: } } - if (err && ext->log_rename_error) { + if (err) { ngx_log_error(NGX_LOG_CRIT, ext->log, err, ngx_rename_file_n " \"%s\" to \"%s\" failed", src->data, to->data); } - ext->rename_error = err; + return NGX_ERROR; +} + + +ngx_int_t +ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf) +{ + char *buf; + off_t size; + size_t len; + ssize_t n; + ngx_fd_t fd, nfd; + ngx_int_t rc; + ngx_file_info_t fi; + + rc = NGX_ERROR; + buf = NULL; + nfd = NGX_INVALID_FILE; + + fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + + if (fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", from); + goto failed; + } + + if (cf->size != -1) { + size = cf->size; + + } else { + if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_fd_info_n " \"%s\" failed", from); + + goto failed; + } + + size = ngx_file_size(&fi); + } + + len = cf->buf_size ? cf->buf_size : 65536; + + if ((off_t) len > size) { + len = (size_t) size; + } + + buf = ngx_alloc(len, cf->log); + if (buf == NULL) { + goto failed; + } + + nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN, + cf->access); + + if (nfd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", to); + goto failed; + } + + while (size > 0) { - return NGX_ERROR; + if ((off_t) len > size) { + len = (size_t) size; + } + + n = ngx_read_fd(fd, buf, len); + + if (n == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_read_fd_n " \"%s\" failed", from); + goto failed; + } + + if ((size_t) n != len) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_read_fd_n " has read only %z of %uz from %s", + n, size, from); + goto failed; + } + + n = ngx_write_fd(nfd, buf, len); + + if (n == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_write_fd_n " \"%s\" failed", to); + goto failed; + } + + if ((size_t) n != len) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_write_fd_n " has written only %z of %uz to %s", + n, size, to); + goto failed; + } + + size -= n; + } + + if (ngx_set_file_time(to, nfd, cf->time) != NGX_OK) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_set_file_time_n " \"%s\" failed", to); + goto failed; + } + + rc = NGX_OK; + +failed: + + if (nfd != NGX_INVALID_FILE) { + if (ngx_close_file(nfd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", to); + } + } + + if (fd != NGX_INVALID_FILE) { + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", from); + } + } + + if (buf) { + ngx_free(buf); + } + + return rc; } 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 @@ -30,6 +30,7 @@ struct ngx_file_s { typedef time_t (*ngx_path_manager_pt) (void *data); +typedef void (*ngx_path_loader_pt) (void *data); typedef struct { @@ -38,6 +39,7 @@ typedef struct { size_t level[3]; ngx_path_manager_pt manager; + ngx_path_loader_pt loader; void *data; u_char *conf_file; @@ -71,16 +73,25 @@ typedef struct { ngx_uint_t path_access; time_t time; ngx_fd_t fd; - ngx_err_t rename_error; unsigned create_path:1; unsigned delete_file:1; - unsigned log_rename_error:1; ngx_log_t *log; } ngx_ext_rename_file_t; +typedef struct { + off_t size; + size_t buf_size; + + ngx_uint_t access; + time_t time; + + ngx_log_t *log; +} ngx_copy_file_t; + + typedef struct ngx_tree_ctx_s ngx_tree_ctx_t; typedef ngx_int_t (*ngx_tree_init_handler_pt) (void *ctx, void *prev); @@ -115,6 +126,7 @@ ngx_int_t ngx_add_path(ngx_conf_t *cf, n ngx_int_t ngx_create_pathes(ngx_cycle_t *cycle, ngx_uid_t user); ngx_int_t ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext); +ngx_int_t ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf); ngx_int_t ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree); void ngx_init_temp_number(void); diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -53,8 +53,6 @@ static ngx_int_t ngx_http_dav_copy_dir_t ngx_str_t *path); static ngx_int_t ngx_http_dav_copy_tree_file(ngx_tree_ctx_t *ctx, ngx_str_t *path); -static ngx_int_t ngx_http_dav_copy_file(ngx_tree_ctx_t *ctx, u_char *from, - u_char *to); static ngx_int_t ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt); static ngx_int_t ngx_http_dav_error(ngx_log_t *log, ngx_err_t err, @@ -249,7 +247,6 @@ ngx_http_dav_put_handler(ngx_http_reques ext.time = -1; ext.create_path = dlcf->create_full_put_path; ext.delete_file = 1; - ext.log_rename_error = 1; ext.log = r->connection->log; if (r->headers_in.date) { @@ -520,6 +517,7 @@ ngx_http_dav_copy_move_handler(ngx_http_ ngx_uint_t overwrite, slash, dir; ngx_str_t path, uri; ngx_tree_ctx_t tree; + ngx_copy_file_t cf; ngx_file_info_t fi; ngx_table_elt_t *dest, *over; ngx_ext_rename_file_t ext; @@ -791,43 +789,24 @@ overwrite_done: ext.time = -1; ext.create_path = 1; ext.delete_file = 0; - ext.log_rename_error = 0; ext.log = r->connection->log; if (ngx_ext_rename_file(&path, ©.path, &ext) == NGX_OK) { return NGX_HTTP_NO_CONTENT; } - if (ext.rename_error != NGX_EXDEV) { - - if (ext.rename_error) { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, - ext.rename_error, - ngx_rename_file_n " \"%s\" to \"%s\" failed", - path.data, copy.path.data); - } - - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } + return NGX_HTTP_INTERNAL_SERVER_ERROR; } dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); - tree.size = ngx_file_size(&fi); - tree.mtime = ngx_file_mtime(&fi); - tree.access = dlcf->access; - tree.log = r->connection->log; + cf.size = ngx_file_size(&fi); + cf.buf_size = 0; + cf.access = dlcf->access; + cf.time = ngx_file_mtime(&fi); + cf.log = r->connection->log; - if (ngx_http_dav_copy_file(&tree, path.data, copy.path.data) == NGX_OK) - { - if (r->method == NGX_HTTP_MOVE) { - rc = ngx_http_dav_delete_path(r, &path, 0); - - if (rc != NGX_OK) { - return rc; - } - } - + if (ngx_copy_file(path.data, copy.path.data, &cf) == NGX_OK) { return NGX_HTTP_NO_CONTENT; } } @@ -941,6 +920,7 @@ ngx_http_dav_copy_tree_file(ngx_tree_ctx { u_char *p, *file; size_t len; + ngx_copy_file_t cf; ngx_http_dav_copy_ctx_t *copy; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, @@ -961,7 +941,13 @@ ngx_http_dav_copy_tree_file(ngx_tree_ctx ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "http copy file to: \"%s\"", file); - (void) ngx_http_dav_copy_file(ctx, path->data, file); + cf.size = ctx->size; + cf.buf_size = 0; + cf.access = ctx->access; + cf.time = ctx->mtime; + cf.log = ctx->log; + + (void) ngx_copy_file(path->data, file, &cf); ngx_free(file); @@ -970,75 +956,6 @@ ngx_http_dav_copy_tree_file(ngx_tree_ctx static ngx_int_t -ngx_http_dav_copy_file(ngx_tree_ctx_t *ctx, u_char *from, u_char *to) -{ - off_t size; - ssize_t n; - ngx_fd_t fd, cfd; - ngx_int_t rc; - u_char buf[NGX_HTTP_DAV_COPY_BLOCK]; - - fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); - - if (fd == NGX_INVALID_FILE) { - (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n, - from); - return NGX_ERROR; - } - - cfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN, - ctx->access); - - rc = NGX_ERROR; - - if (cfd == NGX_INVALID_FILE) { - (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n, to); - goto failed; - } - - for (size = ctx->size; size > 0; size -= n) { - - n = ngx_read_fd(fd, buf, NGX_HTTP_DAV_COPY_BLOCK); - - if (n == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_read_fd_n " \"%s\" failed", from); - goto failed; - } - - if (ngx_write_fd(cfd, buf, n) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_write_fd_n " \"%s\" failed", to); - goto failed; - } - } - - if (ngx_set_file_time(to, cfd, ctx->mtime) != NGX_OK) { - ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_set_file_time_n " \"%s\" failed", to); - goto failed; - } - - if (ngx_close_file(cfd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", to); - goto failed; - } - - rc = NGX_OK; - -failed: - - if (ngx_close_file(fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", from); - } - - return rc; -} - - -static ngx_int_t ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt) { ngx_table_elt_t *depth; diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -1065,9 +1065,10 @@ ngx_http_fastcgi_reinit_request(ngx_http static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r) { - u_char *p, *start, *last, *part_start, *part_end; + u_char *p, *msg, *start, *last, + *part_start, *part_end; size_t size; - ngx_str_t *status_line, line, *pattern; + ngx_str_t *status_line, *pattern; ngx_int_t rc, status; ngx_buf_t buf; ngx_uint_t i; @@ -1151,40 +1152,39 @@ ngx_http_fastcgi_process_header(ngx_http if (f->type == NGX_HTTP_FASTCGI_STDERR) { if (f->length) { - line.data = u->buffer.pos; + msg = u->buffer.pos; if (u->buffer.pos + f->length <= u->buffer.last) { - line.len = f->length; u->buffer.pos += f->length; f->length = 0; f->state = ngx_http_fastcgi_st_padding; } else { - line.len = u->buffer.last - u->buffer.pos; f->length -= u->buffer.last - u->buffer.pos; u->buffer.pos = u->buffer.last; } - while (line.data[line.len - 1] == LF - || line.data[line.len - 1] == CR - || line.data[line.len - 1] == '.' - || line.data[line.len - 1] == ' ') - { - line.len--; + for (p = u->buffer.pos - 1; msg < p; p--) { + if (*p != LF && *p != CR && *p != '.' && *p != ' ') { + break; + } } + p++; + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "FastCGI sent in stderr: \"%V\"", &line); + "FastCGI sent in stderr: \"%*s\"", p - msg, msg); flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); if (flcf->catch_stderr) { pattern = flcf->catch_stderr->elts; - line.data[line.len - 1] = '\0'; - for (i = 0; i < flcf->catch_stderr->nelts; i++) { - if (ngx_strstr(line.data, pattern[i].data)) { + if (ngx_strnstr(msg, (char *) pattern[i].data, + p - msg) + != NULL) + { return NGX_HTTP_UPSTREAM_INVALID_HEADER; } } @@ -1452,9 +1452,9 @@ ngx_http_fastcgi_process_header(ngx_http static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) { + u_char *m, *msg; ngx_int_t rc; ngx_buf_t *b, **prev; - ngx_str_t line; ngx_chain_t *cl; ngx_http_request_t *r; ngx_http_fastcgi_ctx_t *f; @@ -1538,30 +1538,27 @@ ngx_http_fastcgi_input_filter(ngx_event_ break; } - line.data = f->pos; + msg = f->pos; if (f->pos + f->length <= f->last) { - line.len = f->length; f->pos += f->length; f->length = 0; f->state = ngx_http_fastcgi_st_padding; } else { - line.len = f->last - f->pos; f->length -= f->last - f->pos; f->pos = f->last; } - while (line.data[line.len - 1] == LF - || line.data[line.len - 1] == CR - || line.data[line.len - 1] == '.' - || line.data[line.len - 1] == ' ') - { - line.len--; + for (m = f->pos - 1; msg < m; m--) { + if (*m != LF && *m != CR && *m != '.' && *m != ' ') { + break; + } } ngx_log_error(NGX_LOG_ERR, p->log, 0, - "FastCGI sent in stderr: \"%V\"", &line); + "FastCGI sent in stderr: \"%*s\"", + m + 1 - msg, msg); if (f->pos == f->last) { break; diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -47,7 +47,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.8.8'; +our $VERSION = '0.8.9'; require XSLoader; XSLoader::load('nginx', $VERSION); 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 @@ -97,6 +97,7 @@ typedef struct { ngx_rbtree_node_t sentinel; ngx_queue_t queue; ngx_atomic_t cold; + ngx_atomic_t loading; off_t size; } ngx_http_file_cache_sh_t; 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 @@ -53,6 +53,7 @@ ngx_http_file_cache_init(ngx_shm_zone_t ngx_http_file_cache_t *ocache = data; size_t len; + ngx_uint_t n; ngx_http_file_cache_t *cache; cache = shm_zone->data; @@ -68,6 +69,15 @@ ngx_http_file_cache_init(ngx_shm_zone_t return NGX_ERROR; } + for (n = 0; n < 3; n++) { + if (cache->path->level[n] != ocache->path->level[n]) { + ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, + "cache \"%V\" had previously different levels", + &shm_zone->shm.name); + return NGX_ERROR; + } + } + cache->sh = ocache->sh; cache->shpool = ocache->shpool; @@ -75,6 +85,10 @@ ngx_http_file_cache_init(ngx_shm_zone_t cache->max_size /= cache->bsize; + if (!cache->sh->cold || cache->sh->loading) { + cache->path->loader = NULL; + } + return NGX_OK; } @@ -100,6 +114,7 @@ ngx_http_file_cache_init(ngx_shm_zone_t ngx_queue_init(&cache->sh->queue); cache->sh->cold = 1; + cache->sh->loading = 0; cache->sh->size = 0; cache->bsize = ngx_fs_bsize(cache->path->name.data); @@ -635,7 +650,6 @@ ngx_http_file_cache_update(ngx_http_requ ext.time = -1; ext.create_path = 1; ext.delete_file = 1; - ext.log_rename_error = 1; ext.log = r->connection->log; rc = ngx_ext_rename_file(&tf->file.name, &c->file.name, &ext); @@ -1026,39 +1040,8 @@ ngx_http_file_cache_manager(void *data) { ngx_http_file_cache_t *cache = data; - off_t size; - time_t next; - ngx_tree_ctx_t tree; - - if (cache->sh->cold) { - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "http file cache manager update"); - - tree.init_handler = NULL; - tree.file_handler = ngx_http_file_cache_manage_file; - tree.pre_tree_handler = ngx_http_file_cache_noop; - tree.post_tree_handler = ngx_http_file_cache_noop; - tree.spec_handler = ngx_http_file_cache_delete_file; - tree.data = cache; - tree.alloc = 0; - tree.log = ngx_cycle->log; - - cache->last = ngx_current_msec; - cache->files = 0; - - if (ngx_walk_tree(&tree, &cache->path->name) == NGX_ABORT) { - return 10; - } - - cache->sh->cold = 0; - - ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, - "http file cache: %V %.3fM, bsize: %uz", - &cache->path->name, - ((double) cache->sh->size * cache->bsize) / (1024 * 1024), - cache->bsize); - } + off_t size; + time_t next; next = ngx_http_file_cache_expire(cache); @@ -1088,6 +1071,52 @@ ngx_http_file_cache_manager(void *data) } +static void +ngx_http_file_cache_loader(void *data) +{ + ngx_http_file_cache_t *cache = data; + + ngx_tree_ctx_t tree; + + if (!cache->sh->cold || cache->sh->loading) { + return; + } + + if (!ngx_atomic_cmp_set(&cache->sh->loading, 0, ngx_pid)) { + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache loader"); + + tree.init_handler = NULL; + tree.file_handler = ngx_http_file_cache_manage_file; + tree.pre_tree_handler = ngx_http_file_cache_noop; + tree.post_tree_handler = ngx_http_file_cache_noop; + tree.spec_handler = ngx_http_file_cache_delete_file; + tree.data = cache; + tree.alloc = 0; + tree.log = ngx_cycle->log; + + cache->last = ngx_current_msec; + cache->files = 0; + + if (ngx_walk_tree(&tree, &cache->path->name) == NGX_ABORT) { + cache->sh->loading = 0; + return; + } + + cache->sh->cold = 0; + cache->sh->loading = 0; + + ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, + "http file cache: %V %.3fM, bsize: %uz", + &cache->path->name, + ((double) cache->sh->size * cache->bsize) / (1024 * 1024), + cache->bsize); +} + + static ngx_int_t ngx_http_file_cache_manager_sleep(ngx_http_file_cache_t *cache) { @@ -1468,6 +1497,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t } cache->path->manager = ngx_http_file_cache_manager; + cache->path->loader = ngx_http_file_cache_loader; cache->path->data = cache; if (ngx_add_path(cf, &cache->path) != NGX_OK) { diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -2635,7 +2635,6 @@ ngx_http_upstream_store(ngx_http_request ext.time = -1; ext.create_path = 1; ext.delete_file = 1; - ext.log_rename_error = 1; ext.log = r->connection->log; if (u->headers_in.last_modified) { diff --git a/src/os/unix/ngx_errno.h b/src/os/unix/ngx_errno.h --- a/src/os/unix/ngx_errno.h +++ b/src/os/unix/ngx_errno.h @@ -16,6 +16,7 @@ typedef int ngx_err_t; #define NGX_EPERM EPERM #define NGX_ENOENT ENOENT +#define NGX_ENOPATH ENOENT #define NGX_ESRCH ESRCH #define NGX_EINTR EINTR #define NGX_ECHILD ECHILD diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c --- a/src/os/unix/ngx_process.c +++ b/src/os/unix/ngx_process.c @@ -214,21 +214,33 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng switch (respawn) { + case NGX_PROCESS_NORESPAWN: + ngx_processes[s].respawn = 0; + ngx_processes[s].just_spawn = 0; + ngx_processes[s].detached = 0; + break; + + case NGX_PROCESS_JUST_SPAWN: + ngx_processes[s].respawn = 0; + ngx_processes[s].just_spawn = 1; + ngx_processes[s].detached = 0; + break; + case NGX_PROCESS_RESPAWN: ngx_processes[s].respawn = 1; - ngx_processes[s].just_respawn = 0; + ngx_processes[s].just_spawn = 0; ngx_processes[s].detached = 0; break; case NGX_PROCESS_JUST_RESPAWN: ngx_processes[s].respawn = 1; - ngx_processes[s].just_respawn = 1; + ngx_processes[s].just_spawn = 1; ngx_processes[s].detached = 0; break; case NGX_PROCESS_DETACHED: ngx_processes[s].respawn = 0; - ngx_processes[s].just_respawn = 0; + ngx_processes[s].just_spawn = 0; ngx_processes[s].detached = 1; break; } diff --git a/src/os/unix/ngx_process.h b/src/os/unix/ngx_process.h --- a/src/os/unix/ngx_process.h +++ b/src/os/unix/ngx_process.h @@ -27,7 +27,7 @@ typedef struct { char *name; unsigned respawn:1; - unsigned just_respawn:1; + unsigned just_spawn:1; unsigned detached:1; unsigned exiting:1; unsigned exited:1; @@ -45,9 +45,10 @@ typedef struct { #define NGX_MAX_PROCESSES 1024 #define NGX_PROCESS_NORESPAWN -1 -#define NGX_PROCESS_RESPAWN -2 -#define NGX_PROCESS_JUST_RESPAWN -3 -#define NGX_PROCESS_DETACHED -4 +#define NGX_PROCESS_JUST_SPAWN -2 +#define NGX_PROCESS_RESPAWN -3 +#define NGX_PROCESS_JUST_RESPAWN -4 +#define NGX_PROCESS_DETACHED -5 #define ngx_getpid getpid diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -12,7 +12,9 @@ static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type); -static void ngx_start_cache_manager_process(ngx_cycle_t *cycle, ngx_int_t type); +static void ngx_start_cache_manager_processes(ngx_cycle_t *cycle, + ngx_uint_t respawn); +static void ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch); static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo); static ngx_uint_t ngx_reap_children(ngx_cycle_t *cycle); static void ngx_master_process_exit(ngx_cycle_t *cycle); @@ -26,6 +28,7 @@ static ngx_thread_value_t ngx_worker_thr #endif static void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data); static void ngx_cache_manager_process_handler(ngx_event_t *ev); +static void ngx_cache_loader_process_handler(ngx_event_t *ev); ngx_uint_t ngx_process; @@ -61,6 +64,15 @@ u_long cpu_affinity; static u_char master_process[] = "master process"; +static ngx_cache_manager_ctx_t ngx_cache_manager_ctx = { + ngx_cache_manager_process_handler, "cache manager process", 0 +}; + +static ngx_cache_manager_ctx_t ngx_cache_loader_ctx = { + ngx_cache_loader_process_handler, "cache loader process", 60000 +}; + + static ngx_cycle_t ngx_exit_cycle; static ngx_log_t ngx_exit_log; static ngx_open_file_t ngx_exit_log_file; @@ -122,7 +134,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); - ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN); + ngx_start_cache_manager_processes(cycle, 0); ngx_new_binary = 0; delay = 0; @@ -203,7 +215,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy if (ngx_new_binary) { ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); - ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN); + ngx_start_cache_manager_processes(cycle, 0); ngx_noaccepting = 0; continue; @@ -222,7 +234,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy ngx_core_module); ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_JUST_RESPAWN); - ngx_start_cache_manager_process(cycle, NGX_PROCESS_JUST_RESPAWN); + ngx_start_cache_manager_processes(cycle, 1); live = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); @@ -232,7 +244,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy ngx_restart = 0; ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); - ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN); + ngx_start_cache_manager_processes(cycle, 0); live = 1; } @@ -317,7 +329,7 @@ ngx_single_process_cycle(ngx_cycle_t *cy static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type) { - ngx_int_t i, s; + ngx_int_t i; ngx_channel_t ch; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes"); @@ -335,58 +347,70 @@ ngx_start_worker_processes(ngx_cycle_t * ch.slot = ngx_process_slot; ch.fd = ngx_processes[ngx_process_slot].channel[0]; - for (s = 0; s < ngx_last_process; s++) { - - if (s == ngx_process_slot - || ngx_processes[s].pid == -1 - || ngx_processes[s].channel[0] == -1) - { - continue; - } - - ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0, - "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d", - ch.slot, ch.pid, ch.fd, - s, ngx_processes[s].pid, - ngx_processes[s].channel[0]); - - /* TODO: NGX_AGAIN */ - - ngx_write_channel(ngx_processes[s].channel[0], - &ch, sizeof(ngx_channel_t), cycle->log); - } + ngx_pass_open_channel(cycle, &ch); } } static void -ngx_start_cache_manager_process(ngx_cycle_t *cycle, ngx_int_t type) +ngx_start_cache_manager_processes(ngx_cycle_t *cycle, ngx_uint_t respawn) { - ngx_int_t i; - ngx_uint_t n; + ngx_uint_t i, manager, loader; ngx_path_t **path; ngx_channel_t ch; + manager = 0; + loader = 0; + path = ngx_cycle->pathes.elts; - for (n = 0; n < ngx_cycle->pathes.nelts; n++) { - if (path[n]->manager) { - goto start; + for (i = 0; i < ngx_cycle->pathes.nelts; i++) { + + if (path[i]->manager) { + manager = 1; + } + + if (path[i]->loader) { + loader = 1; } } - return; + if (manager == 0) { + return; + } -start: + ngx_spawn_process(cycle, ngx_cache_manager_process_cycle, + &ngx_cache_manager_ctx, "cache manager process", + respawn ? NGX_PROCESS_JUST_RESPAWN : NGX_PROCESS_RESPAWN); ch.command = NGX_CMD_OPEN_CHANNEL; - - ngx_spawn_process(cycle, ngx_cache_manager_process_cycle, NULL, - "cache manager process", type); - ch.pid = ngx_processes[ngx_process_slot].pid; ch.slot = ngx_process_slot; ch.fd = ngx_processes[ngx_process_slot].channel[0]; + ngx_pass_open_channel(cycle, &ch); + + if (loader == 0) { + return; + } + + ngx_spawn_process(cycle, ngx_cache_manager_process_cycle, + &ngx_cache_loader_ctx, "cache loader process", + respawn ? NGX_PROCESS_JUST_SPAWN : NGX_PROCESS_NORESPAWN); + + ch.command = NGX_CMD_OPEN_CHANNEL; + ch.pid = ngx_processes[ngx_process_slot].pid; + ch.slot = ngx_process_slot; + ch.fd = ngx_processes[ngx_process_slot].channel[0]; + + ngx_pass_open_channel(cycle, &ch); +} + + +static void +ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch) +{ + ngx_int_t i; + for (i = 0; i < ngx_last_process; i++) { if (i == ngx_process_slot @@ -398,14 +422,14 @@ start: ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0, "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d", - ch.slot, ch.pid, ch.fd, + ch->slot, ch->pid, ch->fd, i, ngx_processes[i].pid, ngx_processes[i].channel[0]); /* TODO: NGX_AGAIN */ ngx_write_channel(ngx_processes[i].channel[0], - &ch, sizeof(ngx_channel_t), cycle->log); + ch, sizeof(ngx_channel_t), cycle->log); } } @@ -456,14 +480,14 @@ ngx_signal_worker_processes(ngx_cycle_t ngx_processes[i].exited, ngx_processes[i].detached, ngx_processes[i].respawn, - ngx_processes[i].just_respawn); + ngx_processes[i].just_spawn); if (ngx_processes[i].detached || ngx_processes[i].pid == -1) { continue; } - if (ngx_processes[i].just_respawn) { - ngx_processes[i].just_respawn = 0; + if (ngx_processes[i].just_spawn) { + ngx_processes[i].just_spawn = 0; continue; } @@ -533,7 +557,7 @@ ngx_reap_children(ngx_cycle_t *cycle) ngx_processes[i].exited, ngx_processes[i].detached, ngx_processes[i].respawn, - ngx_processes[i].just_respawn); + ngx_processes[i].just_spawn); if (ngx_processes[i].pid == -1) { continue; @@ -590,26 +614,7 @@ ngx_reap_children(ngx_cycle_t *cycle) ch.slot = ngx_process_slot; ch.fd = ngx_processes[ngx_process_slot].channel[0]; - for (n = 0; n < ngx_last_process; n++) { - - if (n == ngx_process_slot - || ngx_processes[n].pid == -1 - || ngx_processes[n].channel[0] == -1) - { - continue; - } - - ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0, - "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d", - ch.slot, ch.pid, ch.fd, - n, ngx_processes[n].pid, - ngx_processes[n].channel[0]); - - /* TODO: NGX_AGAIN */ - - ngx_write_channel(ngx_processes[n].channel[0], - &ch, sizeof(ngx_channel_t), cycle->log); - } + ngx_pass_open_channel(cycle, &ch); live = 1; @@ -1012,13 +1017,14 @@ ngx_worker_process_exit(ngx_cycle_t *cyc && !c[i].read->resolver) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, - "open socket #%d left in connection %ui%s", - c[i].fd, i, ngx_debug_quit ? ", aborting" : ""); - ngx_debug_point(); + "open socket #%d left in connection %ui", + c[i].fd, i); + ngx_debug_quit = 1; } } if (ngx_debug_quit) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "aborting"); ngx_debug_point(); } } @@ -1265,6 +1271,8 @@ ngx_worker_thread_cycle(void *data) static void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data) { + ngx_cache_manager_ctx_t *ctx = data; + void *ident[4]; ngx_event_t ev; @@ -1275,16 +1283,16 @@ ngx_cache_manager_process_cycle(ngx_cycl ngx_close_listening_sockets(cycle); ngx_memzero(&ev, sizeof(ngx_event_t)); - ev.handler = ngx_cache_manager_process_handler; + ev.handler = ctx->handler; ev.data = ident; ev.log = cycle->log; ident[3] = (void *) -1; ngx_use_accept_mutex = 0; - ngx_setproctitle("cache manager process"); + ngx_setproctitle(ctx->name); - ngx_add_timer(&ev, 0); + ngx_add_timer(&ev, ctx->delay); for ( ;; ) { @@ -1331,3 +1339,29 @@ ngx_cache_manager_process_handler(ngx_ev ngx_add_timer(ev, next * 1000); } + + +static void +ngx_cache_loader_process_handler(ngx_event_t *ev) +{ + ngx_uint_t i; + ngx_path_t **path; + ngx_cycle_t *cycle; + + cycle = (ngx_cycle_t *) ngx_cycle; + + path = cycle->pathes.elts; + for (i = 0; i < cycle->pathes.nelts; i++) { + + if (ngx_terminate || ngx_quit) { + break; + } + + if (path[i]->loader) { + path[i]->loader(path[i]->data); + ngx_time_update(0, 0); + } + } + + exit(0); +} diff --git a/src/os/unix/ngx_process_cycle.h b/src/os/unix/ngx_process_cycle.h --- a/src/os/unix/ngx_process_cycle.h +++ b/src/os/unix/ngx_process_cycle.h @@ -25,6 +25,13 @@ #define NGX_PROCESS_SIGNALLER 3 +typedef struct { + ngx_event_handler_pt handler; + char *name; + ngx_msec_t delay; +} ngx_cache_manager_ctx_t; + + void ngx_master_process_cycle(ngx_cycle_t *cycle); void ngx_single_process_cycle(ngx_cycle_t *cycle);