# HG changeset patch # User Igor Sysoev # Date 1238356800 -14400 # Node ID 56baf312c1b57b425c331a325b7875fd92aff5b8 # Parent d46142e61c30efba1d32a08175c4e98845809846 nginx 0.7.46 *) Bugfix: the previous release tarball was incorrect. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,38 @@ +Changes with nginx 0.7.46 30 Mar 2009 + + *) Bugfix: the previous release tarball was incorrect. + + +Changes with nginx 0.7.45 30 Mar 2009 + + *) Change: now the "proxy_cache" and the "proxy_cache_valid" can be set + on different levels. + + *) Change: the "clean_time" parameter of the "proxy_cache_path" + directive is canceled. + + *) Feature: the "max_size" parameter of the "proxy_cache_path" + directive. + + *) Feature: the ngx_http_fastcgi_module preliminary cache support. + + *) Feature: now on shared memory allocation errors directive and zone + names are logged. + + *) Bugfix: the directive "add_header last-modified ''" did not delete a + "Last-Modified" response header line; the bug had appeared in 0.7.44. + + *) Bugfix: a relative path in the "auth_basic_user_file" directive + given without variables did not work; the bug had appeared in + 0.7.44. + Thanks to Jerome Loyet. + + *) Bugfix: in an "alias" directive given using variables without + references to captures of regular expressions; the bug had appeared + in 0.7.42. + + Changes with nginx 0.7.44 23 Mar 2009 *) Feature: the ngx_http_proxy_module preliminary cache support. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,36 @@ +Изменения в nginx 0.7.46 30.03.2009 + + *) Исправление: архив предыдущего релиза был неверным. + + +Изменения в nginx 0.7.45 30.03.2009 + + *) Изменение: теперь директивы proxy_cache и proxy_cache_valid можно + задавать на разных уровнях. + + *) Изменение: параметр clean_time в директиве proxy_cache_path удалён. + + *) Добавление: параметр max_size в директиве proxy_cache_path. + + *) Добавление: предварительная поддержка кэширования в модуле + ngx_http_fastcgi_module. + + *) Добавление: теперь при ошибках выделения в разделяемой памяти в логе + указываются названия директивы и зоны. + + *) Исправление: директива "add_header last-modified ''" не удаляла в + заголовке ответа строку "Last-Modified"; ошибка появилась в 0.7.44. + + *) Исправление: в директиве auth_basic_user_file не работал + относительный путь, заданный строкой без переменных; ошибка + появилась в 0.7.44. + Спасибо Jerome Loyet. + + *) Исправление: в директиве alias, заданной переменными без ссылок на + выделения в регулярных выражениях; ошибка появилась в 0.7.42. + + Изменения в nginx 0.7.44 23.03.2009 *) Добавление: предварительная поддержка кэширования в модуле diff --git a/auto/headers b/auto/headers --- a/auto/headers +++ b/auto/headers @@ -2,8 +2,10 @@ # Copyright (C) Igor Sysoev -ngx_include="unistd.h"; . auto/include -ngx_include="inttypes.h"; . auto/include -ngx_include="limits.h"; . auto/include -ngx_include="sys/filio.h"; . auto/include -ngx_include="crypt.h"; . auto/include +ngx_include="unistd.h"; . auto/include +ngx_include="inttypes.h"; . auto/include +ngx_include="limits.h"; . auto/include +ngx_include="sys/filio.h"; . auto/include +ngx_include="sys/mount.h"; . auto/include +ngx_include="sys/statvfs.h"; . auto/include +ngx_include="crypt.h"; . auto/include diff --git a/auto/os/features b/auto/os/features --- a/auto/os/features +++ b/auto/os/features @@ -205,3 +205,27 @@ ngx_feature_path= ngx_feature_libs= ngx_feature_test="directio(0, DIRECTIO_ON);" . auto/feature + + +ngx_feature="statfs()" +ngx_feature_name="NGX_HAVE_STATFS" +ngx_feature_run=no +ngx_feature_incs="$NGX_INCLUDE_SYS_MOUNT_H + $NGX_INCLUDE_SYS_VFS_H" +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="struct statfs fs; + statfs(NULL, &fs);" +. auto/feature + + +ngx_feature="statvfs()" +ngx_feature_name="NGX_HAVE_STATVFS" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="struct statvfs fs; + statvfs(NULL, &fs);" +. auto/feature diff --git a/auto/os/linux b/auto/os/linux --- a/auto/os/linux +++ b/auto/os/linux @@ -124,4 +124,7 @@ ngx_feature_test="long mask = 0; . auto/feature +ngx_include="sys/vfs.h"; . auto/include + + CC_AUX_FLAGS=$cc_aux_flags diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,8 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VERSION "0.7.45" +#define nginx_version 007046 +#define NGINX_VERSION "0.7.46" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_cpuinfo.c b/src/core/ngx_cpuinfo.c --- a/src/core/ngx_cpuinfo.c +++ b/src/core/ngx_cpuinfo.c @@ -72,7 +72,7 @@ void ngx_cpuinfo(void) { u_char *vendor; - uint32_t vbuf[5], cpu[4]; + uint32_t vbuf[5], cpu[4], model; vbuf[0] = 0; vbuf[1] = 0; @@ -103,8 +103,10 @@ ngx_cpuinfo(void) case 6: ngx_cacheline_size = 32; - if ((cpu[0] & 0xf0) >= 0xd0) { - /* Intel Core */ + model = ((cpu[0] & 0xf0000) >> 8) | (cpu[0] & 0xf0); + + if (model >= 0xd0) { + /* Intel Core, Core 2, Atom */ ngx_cacheline_size = 64; } 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 @@ -264,7 +264,7 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, n } path->len = 0; - path->cleaner = (ngx_path_cleaner_pt) cmd->post; + path->manager = (ngx_path_manager_pt) cmd->post; path->conf_file = cf->conf_file->file.name.data; path->line = cf->conf_file->line; @@ -324,7 +324,7 @@ ngx_conf_merge_path_value(ngx_conf_t *cf + init->level[1] + (init->level[1] ? 1 : 0) + init->level[2] + (init->level[2] ? 1 : 0); - (*path)->cleaner = NULL; + (*path)->manager = NULL; (*path)->conf_file = NULL; if (ngx_add_path(cf, path) != NGX_OK) { 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 @@ -29,7 +29,7 @@ struct ngx_file_s { #define NGX_MAX_PATH_LEVEL 3 -typedef time_t (*ngx_path_cleaner_pt) (void *data); +typedef time_t (*ngx_path_manager_pt) (void *data); typedef struct { @@ -37,7 +37,7 @@ typedef struct { size_t len; size_t level[3]; - ngx_path_cleaner_pt cleaner; + ngx_path_manager_pt manager; void *data; u_char *conf_file; diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c @@ -6,23 +6,6 @@ #include #include -/* - - 12 - 2048 2 11 - 1024 4 10 - 512 8 9 - 256 16 8 - - 128 32 4 32 7 - - 64 64 8 63 6 1 - 32 128 16 127 5 1 - 16 256 32 254 4 2 - 8 512 64 504 3 8 - - */ - #define NGX_SLAB_PAGE_MASK 3 #define NGX_SLAB_PAGE 0 @@ -80,6 +63,8 @@ static ngx_slab_page_t *ngx_slab_alloc_p ngx_uint_t pages); static void ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page, ngx_uint_t pages); +static void ngx_slab_error(ngx_slab_pool_t *pool, ngx_uint_t level, + char *text); static ngx_uint_t ngx_slab_max_size; @@ -147,11 +132,8 @@ ngx_slab_init(ngx_slab_pool_t *pool) pool->pages->slab = pages; } -#if 0 - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "slab: %p, %p, %ui, %d", - pool, pool->start, pages, - (pool->end - pool->start) / ngx_pagesize - pages); -#endif + pool->log_ctx = &pool->zero; + pool->zero = '\0'; } @@ -438,8 +420,7 @@ ngx_slab_free_locked(ngx_slab_pool_t *po ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab free: %p", p); if ((u_char *) p < pool->start || (u_char *) p > pool->end) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "ngx_slab_free(): outside of pool"); + ngx_slab_error(pool, NGX_LOG_ALERT, "ngx_slab_free(): outside of pool"); goto fail; } @@ -587,14 +568,14 @@ ngx_slab_free_locked(ngx_slab_pool_t *po } if (slab == NGX_SLAB_PAGE_FREE) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "ngx_slab_free(): page is already free"); + ngx_slab_error(pool, NGX_LOG_ALERT, + "ngx_slab_free(): page is already free"); goto fail; } if (slab == NGX_SLAB_PAGE_BUSY) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "ngx_slab_free(): pointer to wrong page"); + ngx_slab_error(pool, NGX_LOG_ALERT, + "ngx_slab_free(): pointer to wrong page"); goto fail; } @@ -620,15 +601,15 @@ done: wrong_chunk: - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "ngx_slab_free(): pointer to wrong chunk"); + ngx_slab_error(pool, NGX_LOG_ALERT, + "ngx_slab_free(): pointer to wrong chunk"); goto fail; chunk_already_free: - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "ngx_slab_free(): chunk is already free"); + ngx_slab_error(pool, NGX_LOG_ALERT, + "ngx_slab_free(): chunk is already free"); fail: @@ -679,8 +660,7 @@ ngx_slab_alloc_pages(ngx_slab_pool_t *po } } - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, NGX_ENOMEM, - "ngx_slab_alloc(): failed"); + ngx_slab_error(pool, NGX_LOG_CRIT, "ngx_slab_alloc() failed: no memory"); return NULL; } @@ -711,3 +691,10 @@ ngx_slab_free_pages(ngx_slab_pool_t *poo pool->free.next = page; } + + +static void +ngx_slab_error(ngx_slab_pool_t *pool, ngx_uint_t level, char *text) +{ + ngx_log_error(level, ngx_cycle->log, 0, "%s%s", text, pool->log_ctx); +} diff --git a/src/core/ngx_slab.h b/src/core/ngx_slab.h --- a/src/core/ngx_slab.h +++ b/src/core/ngx_slab.h @@ -34,6 +34,9 @@ typedef struct { u_char *end; ngx_shmtx_t mutex; + + u_char *log_ctx; + u_char zero; } ngx_slab_pool_t; diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -1412,6 +1412,7 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ng static ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data) { + size_t len; ngx_slab_pool_t *shpool; ngx_ssl_session_cache_t *cache; @@ -1432,6 +1433,16 @@ ngx_ssl_session_cache_init(ngx_shm_zone_ ngx_queue_init(&cache->expire_queue); + len = sizeof(" in SSL session shared cache \"\"") + shm_zone->name.len; + + shpool->log_ctx = ngx_slab_alloc(shpool, len); + if (shpool->log_ctx == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(shpool->log_ctx, " in SSL session shared cache \"%V\"%Z", + &shm_zone->name); + shm_zone->data = cache; return NGX_OK; diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c --- a/src/http/modules/ngx_http_limit_req_module.c +++ b/src/http/modules/ngx_http_limit_req_module.c @@ -224,11 +224,6 @@ ngx_http_limit_req_handler(ngx_http_requ node = ngx_slab_alloc_locked(ctx->shpool, n); if (node == NULL) { ngx_shmtx_unlock(&ctx->shpool->mutex); - - ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, - "could not allocate memory in zone \"%V\"", - &lrcf->shm_zone->name); - return NGX_HTTP_SERVICE_UNAVAILABLE; } } @@ -457,6 +452,7 @@ ngx_http_limit_req_init_zone(ngx_shm_zon { ngx_http_limit_req_ctx_t *octx = data; + size_t len; ngx_rbtree_node_t *sentinel; ngx_http_limit_req_ctx_t *ctx; @@ -500,6 +496,16 @@ ngx_http_limit_req_init_zone(ngx_shm_zon ngx_queue_init(ctx->queue); + len = sizeof(" in limit_req zone \"\"") + shm_zone->name.len; + + ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len); + if (ctx->shpool->log_ctx == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(ctx->shpool->log_ctx, " in limit_req zone \"%V\"%Z", + &shm_zone->name); + return NGX_OK; } diff --git a/src/http/modules/ngx_http_limit_zone_module.c b/src/http/modules/ngx_http_limit_zone_module.c --- a/src/http/modules/ngx_http_limit_zone_module.c +++ b/src/http/modules/ngx_http_limit_zone_module.c @@ -210,11 +210,6 @@ ngx_http_limit_zone_handler(ngx_http_req node = ngx_slab_alloc_locked(shpool, n); if (node == NULL) { ngx_shmtx_unlock(&shpool->mutex); - - ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, - "could not allocate memory in zone \"%V\"", - &lzcf->shm_zone->name); - return NGX_HTTP_SERVICE_UNAVAILABLE; } @@ -321,6 +316,7 @@ ngx_http_limit_zone_init_zone(ngx_shm_zo { ngx_http_limit_zone_ctx_t *octx = data; + size_t len; ngx_slab_pool_t *shpool; ngx_rbtree_node_t *sentinel; ngx_http_limit_zone_ctx_t *ctx; @@ -356,6 +352,15 @@ ngx_http_limit_zone_init_zone(ngx_shm_zo ngx_rbtree_init(ctx->rbtree, sentinel, ngx_http_limit_zone_rbtree_insert_value); + len = sizeof(" in limit_zone \"\"") + shm_zone->name.len; + + shpool->log_ctx = ngx_slab_alloc(shpool, len); + if (shpool->log_ctx == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(shpool->log_ctx, " in limit_zone \"%V\"%Z", &shm_zone->name); + return NGX_OK; } 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.7.45'; +our $VERSION = '0.7.46'; 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 @@ -48,6 +48,7 @@ typedef struct { time_t expire; time_t valid_sec; size_t body_start; + off_t length; } ngx_http_file_cache_node_t; @@ -100,10 +101,16 @@ struct ngx_http_file_cache_s { ngx_path_t *path; + ngx_atomic_t *cold; + off_t *size; + + off_t max_size; + size_t bsize; + time_t inactive; - time_t created; - time_t clean_time; - time_t next_clean_time; + + ngx_msec_t last; + ngx_uint_t files; ngx_shm_zone_t *shm_zone; }; 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 @@ -1695,7 +1695,15 @@ ngx_http_map_uri_to_path(ngx_http_reques last = ngx_copy(path->data, clcf->root.data, clcf->root.len); } else { - reserved += alias ? 1 : r->uri.len + 1; + +#if (NGX_PCRE) + ngx_uint_t captures; + + captures = alias && clcf->captures; + reserved += captures ? 1 : r->uri.len - alias + 1; +#else + reserved += r->uri.len - alias + 1; +#endif if (ngx_http_script_run(r, path, clcf->root_lengths->elts, reserved, clcf->root_values->elts) @@ -1711,10 +1719,12 @@ ngx_http_map_uri_to_path(ngx_http_reques *root_length = path->len - reserved; last = path->data + *root_length; - if (alias) { +#if (NGX_PCRE) + if (captures) { *last = '\0'; return last; } +#endif } last = ngx_cpystrn(last, r->uri.data + alias, r->uri.len - alias + 1); 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 @@ -10,18 +10,28 @@ #include -static ngx_int_t ngx_http_file_cache_exists(ngx_http_request_t *r, - 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); static ngx_http_file_cache_node_t * ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key); static void ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); static void ngx_http_file_cache_cleanup(void *data); -static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache, - ngx_uint_t force); -static ngx_int_t ngx_http_file_cache_clean_noop(ngx_tree_ctx_t *ctx, +static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache); +static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache); +static void ngx_http_file_cache_delete(ngx_http_file_cache_t *cache, + ngx_queue_t *q, u_char *name); +static ngx_int_t + ngx_http_file_cache_manager_sleep(ngx_http_file_cache_t *cache); +static ngx_int_t ngx_http_file_cache_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path); -static ngx_int_t ngx_http_file_cache_clean_file(ngx_tree_ctx_t *ctx, +static ngx_int_t ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx, + ngx_str_t *path); +static ngx_int_t ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx, + ngx_str_t *path); +static ngx_int_t ngx_http_file_cache_add(ngx_http_file_cache_t *cache, + ngx_http_cache_t *c); +static ngx_int_t ngx_http_file_cache_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path); @@ -33,6 +43,7 @@ ngx_http_file_cache_init(ngx_shm_zone_t { ngx_http_file_cache_t *ocache = data; + size_t len; ngx_rbtree_node_t *sentinel; ngx_http_file_cache_t *cache; @@ -52,7 +63,11 @@ ngx_http_file_cache_init(ngx_shm_zone_t cache->rbtree = ocache->rbtree; cache->queue = ocache->queue; cache->shpool = ocache->shpool; - cache->created = ocache->created; + cache->cold = ocache->cold; + cache->size = ocache->size; + cache->bsize = ocache->bsize; + + cache->max_size /= cache->bsize; return NGX_OK; } @@ -79,7 +94,33 @@ ngx_http_file_cache_init(ngx_shm_zone_t ngx_queue_init(cache->queue); - cache->created = ngx_time(); + cache->cold = ngx_slab_alloc(cache->shpool, sizeof(ngx_atomic_t)); + if (cache->cold == NULL) { + return NGX_ERROR; + } + + *cache->cold = 1; + + cache->size = ngx_slab_alloc(cache->shpool, sizeof(off_t)); + if (cache->size == NULL) { + return NGX_ERROR; + } + + *cache->size = 0; + + cache->bsize = ngx_fs_bsize(cache->path->name.data); + + cache->max_size /= cache->bsize; + + len = sizeof(" in cache keys zone \"\"") + shm_zone->name.len; + + cache->shpool->log_ctx = ngx_slab_alloc(cache->shpool, len); + if (cache->shpool->log_ctx == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(cache->shpool->log_ctx, " in cache keys zone \"%V\"%Z", + &shm_zone->name); return NGX_OK; } @@ -144,7 +185,7 @@ ngx_http_file_cache_open(ngx_http_reques return NGX_ERROR; } - rc = ngx_http_file_cache_exists(r, cache); + rc = ngx_http_file_cache_exists(cache, c); ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http file cache exists: %i u:%ui e:%d", @@ -161,9 +202,7 @@ ngx_http_file_cache_open(ngx_http_reques return rc; } - now = ngx_time(); - - cold = (now - cache->created < cache->inactive) ? 1 : 0; + cold = *cache->cold; if (rc == NGX_OK) { @@ -293,13 +332,19 @@ ngx_http_file_cache_open(ngx_http_reques ngx_shmtx_lock(&cache->shpool->mutex); - c->node->uses = c->min_uses; - c->node->body_start = c->body_start; - c->node->exists = 1; + if (!c->node->exists) { + c->node->uses = 1; + c->node->body_start = c->body_start; + c->node->exists = 1; + + *cache->size += (c->length + cache->bsize - 1) / cache->bsize; + } ngx_shmtx_unlock(&cache->shpool->mutex); } + now = ngx_time(); + if (c->valid_sec < now) { c->uses = c->min_uses; @@ -317,14 +362,14 @@ ngx_http_file_cache_open(ngx_http_reques static ngx_int_t -ngx_http_file_cache_exists(ngx_http_request_t *r, ngx_http_file_cache_t *cache) +ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) { ngx_int_t rc; ngx_http_file_cache_node_t *fcn; ngx_shmtx_lock(&cache->shpool->mutex); - fcn = ngx_http_file_cache_lookup(cache, r->cache->key); + fcn = ngx_http_file_cache_lookup(cache, c->key); if (fcn) { ngx_queue_remove(&fcn->queue); @@ -345,18 +390,18 @@ ngx_http_file_cache_exists(ngx_http_requ if (fcn->exists) { - r->cache->exists = fcn->exists; - r->cache->body_start = fcn->body_start; + c->exists = fcn->exists; + c->body_start = fcn->body_start; rc = NGX_OK; goto done; } - if (fcn->uses >= r->cache->min_uses) { + if (fcn->uses >= c->min_uses) { - r->cache->exists = fcn->exists; - r->cache->body_start = fcn->body_start; + c->exists = fcn->exists; + c->body_start = fcn->body_start; rc = NGX_OK; @@ -372,7 +417,7 @@ ngx_http_file_cache_exists(ngx_http_requ if (fcn == NULL) { ngx_shmtx_unlock(&cache->shpool->mutex); - (void) ngx_http_file_cache_expire(cache, 1); + ngx_http_file_cache_forced_expire(cache); ngx_shmtx_lock(&cache->shpool->mutex); @@ -384,10 +429,9 @@ ngx_http_file_cache_exists(ngx_http_requ } } - ngx_memcpy((u_char *) &fcn->node.key, r->cache->key, - sizeof(ngx_rbtree_key_t)); + ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t)); - ngx_memcpy(fcn->key, &r->cache->key[sizeof(ngx_rbtree_key_t)], + ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)], NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); ngx_rbtree_insert(cache->rbtree, &fcn->node); @@ -411,10 +455,10 @@ done: ngx_queue_insert_head(cache->queue, &fcn->queue); - r->cache->uniq = fcn->uniq; - r->cache->uses = fcn->uses; - r->cache->error = fcn->error; - r->cache->node = fcn; + c->uniq = fcn->uniq; + c->uses = fcn->uses; + c->error = fcn->error; + c->node = fcn; failed: @@ -556,6 +600,7 @@ ngx_http_file_cache_set_header(ngx_http_ void ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf) { + off_t size; ngx_int_t rc; ngx_file_uniq_t uniq; ngx_file_info_t fi; @@ -605,12 +650,20 @@ ngx_http_file_cache_update(ngx_http_requ } } + size = (c->length + cache->bsize - 1) / cache->bsize; + ngx_shmtx_lock(&cache->shpool->mutex); c->node->count--; c->node->uniq = uniq; c->node->body_start = c->body_start; + size = size - (c->node->length + cache->bsize - 1) / cache->bsize; + + c->node->length = c->length; + + *cache->size += size; + if (rc == NGX_OK) { c->node->exists = 1; } @@ -746,12 +799,84 @@ ngx_http_file_cache_cleanup(void *data) static time_t -ngx_http_file_cache_expire(ngx_http_file_cache_t *cache, ngx_uint_t forced) +ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache) +{ + u_char *name; + size_t len; + time_t wait; + ngx_uint_t tries; + ngx_path_t *path; + ngx_queue_t *q; + ngx_http_file_cache_node_t *fcn; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache forced expire"); + + path = cache->path; + len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; + + name = ngx_alloc(len + 1, ngx_cycle->log); + if (name == NULL) { + return 60; + } + + ngx_memcpy(name, path->name.data, path->name.len); + + wait = 60; + tries = 0; + + ngx_shmtx_lock(&cache->shpool->mutex); + + for (q = ngx_queue_last(cache->queue); + q != ngx_queue_sentinel(cache->queue); + q = ngx_queue_prev(q)) + { + fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); + + ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache forced expire: #%d %d %02xd%02xd%02xd%02xd", + fcn->count, fcn->exists, + fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]); + + if (fcn->count) { + + if (tries++ < 20) { + continue; + } + + wait = 1; + + break; + } + + if (!fcn->exists) { + + ngx_queue_remove(q); + ngx_rbtree_delete(cache->rbtree, &fcn->node); + ngx_slab_free_locked(cache->shpool, fcn); + + break; + } + + ngx_http_file_cache_delete(cache, q, name); + + break; + } + + ngx_shmtx_unlock(&cache->shpool->mutex); + + ngx_free(name); + + return wait; +} + + +static time_t +ngx_http_file_cache_expire(ngx_http_file_cache_t *cache) { u_char *name, *p; size_t len; time_t now, wait; - ngx_uint_t tries; ngx_path_t *path; ngx_queue_t *q; ngx_http_file_cache_node_t *fcn; @@ -763,16 +888,21 @@ ngx_http_file_cache_expire(ngx_http_file path = cache->path; len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; + name = ngx_alloc(len + 1, ngx_cycle->log); + if (name == NULL) { + return 60; + } + + ngx_memcpy(name, path->name.data, path->name.len); + now = ngx_time(); ngx_shmtx_lock(&cache->shpool->mutex); - tries = 0; - for ( ;; ) { if (ngx_queue_empty(cache->queue)) { - wait = cache->inactive; + wait = 60; break; } @@ -780,12 +910,11 @@ ngx_http_file_cache_expire(ngx_http_file fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); - if (!forced) { - wait = fcn->expire - now; + wait = fcn->expire - now; - if (wait > 0) { - break; - } + if (wait > 0) { + wait = wait > 60 ? 60 : wait; + break; } ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, @@ -795,198 +924,360 @@ ngx_http_file_cache_expire(ngx_http_file if (fcn->count) { - if (!forced) { + p = ngx_hex_dump(key, (u_char *) &fcn->node.key, + sizeof(ngx_rbtree_key_t)); - p = ngx_hex_dump(key, (u_char *) &fcn->node.key, - sizeof(ngx_rbtree_key_t)); - (void) ngx_hex_dump(p, fcn->key, - NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); + len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t); + (void) ngx_hex_dump(p, fcn->key, len); - /* - * abnormally exited workers may leave locked cache entries, - * and although it may be safe to remove them completely, - * we prefer to remove them from inactive queue and rbtree - * only, and to allow other leaks - */ + /* + * abnormally exited workers may leave locked cache entries, + * and although it may be safe to remove them completely, + * we prefer to remove them from inactive queue and rbtree + * only, and to allow other leaks + */ - ngx_queue_remove(q); + ngx_queue_remove(q); + ngx_rbtree_delete(cache->rbtree, &fcn->node); - ngx_rbtree_delete(cache->rbtree, &fcn->node); - - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "ignore long locked inactive cache entry %*s, count:%d", 2 * NGX_HTTP_CACHE_KEY_LEN, key, fcn->count); - } - if (tries++ < 10) { - continue; - } - - wait = 1; - break; + continue; } - forced = 0; - if (!fcn->exists) { ngx_queue_remove(q); - ngx_rbtree_delete(cache->rbtree, &fcn->node); - ngx_slab_free_locked(cache->shpool, fcn); continue; } - name = ngx_alloc(len + 1, ngx_cycle->log); - if (name == NULL) { - wait = 60; - break; - } - - ngx_memcpy(name, path->name.data, path->name.len); - - p = name + path->name.len + 1 + path->len; - p = ngx_hex_dump(p, (u_char *) &fcn->node.key, - sizeof(ngx_rbtree_key_t)); - p = ngx_hex_dump(p, fcn->key, - NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); - *p = '\0'; - - ngx_queue_remove(q); - - ngx_rbtree_delete(cache->rbtree, &fcn->node); - - ngx_slab_free_locked(cache->shpool, fcn); - - ngx_shmtx_unlock(&cache->shpool->mutex); - - ngx_create_hashed_filename(path, name, len); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "http file cache expire: \"%s\"", name); - - if (ngx_delete_file(name) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno, - ngx_delete_file_n " \"%s\" failed", name); - } - - ngx_free(name); - - ngx_shmtx_lock(&cache->shpool->mutex); + ngx_http_file_cache_delete(cache, q, name); } ngx_shmtx_unlock(&cache->shpool->mutex); + ngx_free(name); + return wait; } -time_t -ngx_http_file_cache_cleaner(void *data) +static void +ngx_http_file_cache_delete(ngx_http_file_cache_t *cache, ngx_queue_t *q, + u_char *name) +{ + u_char *p; + size_t len; + ngx_path_t *path; + ngx_http_file_cache_node_t *fcn; + + fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); + + *cache->size -= (fcn->length + cache->bsize - 1) / cache->bsize; + + path = cache->path; + + p = name + path->name.len + 1 + path->len; + + p = ngx_hex_dump(p, (u_char *) &fcn->node.key, sizeof(ngx_rbtree_key_t)); + + len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t); + p = ngx_hex_dump(p, fcn->key, len); + *p = '\0'; + + ngx_queue_remove(q); + + ngx_rbtree_delete(cache->rbtree, &fcn->node); + + ngx_slab_free_locked(cache->shpool, fcn); + + ngx_shmtx_unlock(&cache->shpool->mutex); + + len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; + + ngx_create_hashed_filename(path, name, len); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache expire: \"%s\"", name); + + if (ngx_delete_file(name) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno, + ngx_delete_file_n " \"%s\" failed", name); + } + + ngx_shmtx_lock(&cache->shpool->mutex); +} + + +static time_t +ngx_http_file_cache_manager(void *data) { ngx_http_file_cache_t *cache = data; - time_t now, next; + off_t size; + time_t next; ngx_tree_ctx_t tree; - now = ngx_time(); + if (*cache->cold) { - if (now >= cache->next_clean_time - && now >= cache->created + cache->inactive) - { - ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, - "clean unused cache files"); + 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_clean_file; - tree.pre_tree_handler = ngx_http_file_cache_clean_noop; - tree.post_tree_handler = ngx_http_file_cache_clean_noop; - tree.spec_handler = ngx_http_file_cache_clean_file; + 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; - (void) ngx_walk_tree(&tree, &cache->path->name); - - ngx_time_update(0, 0); + cache->last = ngx_current_msec; + cache->files = 0; - next = ngx_next_time(cache->clean_time); - - if (next == -1) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno, - ngx_next_time_n " failed"); + if (ngx_walk_tree(&tree, &cache->path->name) == NGX_ABORT) { return 60; } - cache->next_clean_time = next; + *cache->cold = 0; + + ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, + "http file cache: %V %.3fM, bsize: %uz", + &cache->path->name, + ((double) *cache->size * cache->bsize) / (1024 * 1024), + cache->bsize); } - next = ngx_http_file_cache_expire(cache, 0); + next = ngx_http_file_cache_expire(cache); + + cache->last = ngx_current_msec; + cache->files = 0; + + for ( ;; ) { + ngx_shmtx_lock(&cache->shpool->mutex); + + size = *cache->size; - now = ngx_time(); + ngx_shmtx_unlock(&cache->shpool->mutex); + + if (size < cache->max_size) { + return next; + } - return (now + next < cache->next_clean_time) ? next: - cache->next_clean_time - now; + next = ngx_http_file_cache_forced_expire(cache); + + if (ngx_http_file_cache_manager_sleep(cache) != NGX_OK) { + return next; + } + } } static ngx_int_t -ngx_http_file_cache_clean_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path) +ngx_http_file_cache_manager_sleep(ngx_http_file_cache_t *cache) +{ + ngx_msec_t elapsed; + + if (cache->files++ > 100) { + + ngx_time_update(0, 0); + + elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last)); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache manager time: %M", elapsed); + + if (elapsed > 200) { + + /* + * if processing 100 files takes more than 200ms, + * it seems that many operations require disk i/o, + * therefore sleep 200ms + */ + + ngx_msleep(200); + + ngx_time_update(0, 0); + } + + cache->last = ngx_current_msec; + cache->files = 0; + } + + return (ngx_quit || ngx_terminate) ? NGX_ABORT : NGX_OK; +} + + +static ngx_int_t +ngx_http_file_cache_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path) { return NGX_OK; } static ngx_int_t -ngx_http_file_cache_clean_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) +ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) { - u_char *p, key[2 * NGX_HTTP_CACHE_KEY_LEN]; - ngx_int_t n; - ngx_uint_t i; - ngx_http_file_cache_t *cache; - ngx_http_file_cache_node_t *node; + ngx_http_file_cache_t *cache; + + cache = ctx->data; + + if (ngx_http_file_cache_add_file(ctx, path) != NGX_OK) { + (void) ngx_http_file_cache_delete_file(ctx, path); + } + + return ngx_http_file_cache_manager_sleep(cache); +} + - if (path->len < 2 * NGX_HTTP_CACHE_KEY_LEN) { - goto clean; +static ngx_int_t +ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx, ngx_str_t *name) +{ + u_char *p; + ngx_fd_t fd; + ngx_int_t n; + ngx_uint_t i; + ngx_file_info_t fi; + ngx_http_cache_t c; + ngx_http_file_cache_t *cache; + ngx_http_file_cache_header_t h; + + if (name->len < 2 * NGX_HTTP_CACHE_KEY_LEN) { + return NGX_ERROR; } - p = &path->data[path->len - 2 * NGX_HTTP_CACHE_KEY_LEN]; + ngx_memzero(&c, sizeof(ngx_http_cache_t)); + + fd = ngx_open_file(name->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + + if (fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", name->data); + return NGX_ERROR; + } + + c.file.fd = fd; + c.file.name = *name; + c.file.log = ctx->log; + + n = ngx_read_file(&c.file, (u_char *) &h, + sizeof(ngx_http_file_cache_header_t), 0); + if (n == NGX_ERROR) { + return NGX_ERROR; + } + + if ((size_t) n < sizeof(ngx_http_file_cache_header_t)) { + ngx_log_error(NGX_LOG_CRIT, ctx->log, 0, + "cache file \"%s\" is too small", name->data); + return NGX_ERROR; + } + + if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, + ngx_fd_info_n " \"%s\" failed", name->data); + + } else { + c.uniq = ngx_file_uniq(&fi); + c.valid_sec = h.valid_sec; + c.valid_msec = h.valid_msec; + c.body_start = h.body_start; + c.length = ngx_file_size(&fi); + } + + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", name->data); + } + + if (c.body_start == 0) { + return NGX_ERROR; + } + + p = &name->data[name->len - 2 * NGX_HTTP_CACHE_KEY_LEN]; for (i = 0; i < NGX_HTTP_CACHE_KEY_LEN; i++) { n = ngx_hextoi(p, 2); if (n == NGX_ERROR) { - goto clean; + return NGX_ERROR; } p += 2; - key[i] = (u_char) n; + c.key[i] = (u_char) n; } cache = ctx->data; + return ngx_http_file_cache_add(cache, &c); +} + + +static ngx_int_t +ngx_http_file_cache_add(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) +{ + ngx_http_file_cache_node_t *fcn; + ngx_shmtx_lock(&cache->shpool->mutex); - node = ngx_http_file_cache_lookup(cache, key); + fcn = ngx_http_file_cache_lookup(cache, c->key); + + if (fcn == NULL) { + + fcn = ngx_slab_alloc_locked(cache->shpool, + sizeof(ngx_http_file_cache_node_t)); + if (fcn == NULL) { + ngx_shmtx_unlock(&cache->shpool->mutex); + return NGX_ERROR; + } + + ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t)); + + ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)], + NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); + + ngx_rbtree_insert(cache->rbtree, &fcn->node); + + fcn->uses = 1; + fcn->count = 0; + fcn->valid_msec = c->valid_msec; + fcn->error = 0; + fcn->exists = 1; + fcn->uniq = c->uniq; + fcn->valid_sec = c->valid_sec; + fcn->body_start = c->body_start; + fcn->length = c->length; + + *cache->size += (c->length + cache->bsize - 1) / cache->bsize; + + } else { + ngx_queue_remove(&fcn->queue); + } + + fcn->expire = ngx_time() + cache->inactive; + + ngx_queue_insert_head(cache->queue, &fcn->queue); ngx_shmtx_unlock(&cache->shpool->mutex); - if (node) { - return NGX_OK; - } + return NGX_OK; +} + -clean: - +static ngx_int_t +ngx_http_file_cache_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) +{ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, - "http file cache clean: \"%s\"", path->data); + "http file cache delete: \"%s\"", path->data); if (ngx_delete_file(path->data) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, ngx_delete_file_n " \"%s\" failed", path->data); - return NGX_ERROR; } return NGX_OK; @@ -1018,8 +1309,9 @@ ngx_http_file_cache_valid(ngx_array_t *c char * ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + off_t max_size; u_char *last, *p; - time_t inactive, clean_time, next; + time_t inactive; ssize_t size; ngx_str_t s, name, *value; ngx_uint_t i, n; @@ -1036,10 +1328,10 @@ ngx_http_file_cache_set_slot(ngx_conf_t } inactive = 600; - clean_time = 5 * 60 * 60; name.len = 0; size = 0; + max_size = NGX_MAX_OFF_T_VALUE; value = cf->args->elts; @@ -1142,15 +1434,15 @@ ngx_http_file_cache_set_slot(ngx_conf_t continue; } - if (ngx_strncmp(value[i].data, "clean_time=", 11) == 0) { + if (ngx_strncmp(value[i].data, "max_size=", 9) == 0) { - s.len = value[i].len - 11; - s.data = value[i].data + 11; + s.len = value[i].len - 9; + s.data = value[i].data + 9; - clean_time = ngx_parse_time(&s, 1); - if (clean_time < 0 || clean_time > 24 * 60 * 60) { + max_size = ngx_parse_offset(&s); + if (max_size < 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid clean_time value \"%V\"", &value[i]); + "invalid max_size value \"%V\"", &value[i]); return NGX_CONF_ERROR; } @@ -1169,7 +1461,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t return NGX_CONF_ERROR; } - cache->path->cleaner = ngx_http_file_cache_cleaner; + cache->path->manager = ngx_http_file_cache_manager; cache->path->data = cache; if (ngx_add_path(cf, &cache->path) != NGX_OK) { @@ -1187,20 +1479,12 @@ ngx_http_file_cache_set_slot(ngx_conf_t return NGX_CONF_ERROR; } - next = ngx_next_time(clean_time); - - if (next == -1) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, - ngx_next_time_n " failed"); - return NGX_CONF_ERROR; - } cache->shm_zone->init = ngx_http_file_cache_init; cache->shm_zone->data = cache; cache->inactive = inactive; - cache->clean_time = clean_time; - cache->next_clean_time = next; + cache->max_size = max_size; return NGX_CONF_OK; } diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -32,7 +32,7 @@ static uintptr_t ngx_http_script_exit_co void -ngx_http_scrip_flush_complex_value(ngx_http_request_t *r, +ngx_http_script_flush_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val) { ngx_uint_t *index; @@ -67,7 +67,7 @@ ngx_http_complex_value(ngx_http_request_ return NGX_OK; } - ngx_http_scrip_flush_complex_value(r, val); + ngx_http_script_flush_complex_value(r, val); ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); @@ -118,11 +118,6 @@ ngx_http_compile_complex_value(ngx_http_ return NGX_ERROR; } - ccv->complex_value->value = *v; - ccv->complex_value->flushes = NULL; - ccv->complex_value->lengths = NULL; - ccv->complex_value->values = NULL; - nv = 0; nc = 0; @@ -147,6 +142,11 @@ ngx_http_compile_complex_value(ngx_http_ ccv->root_prefix = 0; } + ccv->complex_value->value = *v; + ccv->complex_value->flushes = NULL; + ccv->complex_value->lengths = NULL; + ccv->complex_value->values = NULL; + if (nv == 0 && nc == 0) { return NGX_OK; } diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h @@ -203,7 +203,7 @@ typedef struct { } ngx_http_script_value_code_t; -void ngx_http_scrip_flush_complex_value(ngx_http_request_t *r, +void ngx_http_script_flush_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val); ngx_int_t ngx_http_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val, ngx_str_t *value); 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 @@ -416,3 +416,50 @@ ngx_directio_off(ngx_fd_t fd) } #endif + + +#if (NGX_HAVE_STATFS) + +size_t +ngx_fs_bsize(u_char *name) +{ + struct statfs fs; + + if (statfs((char *) name, &fs) == -1) { + return 512; + } + + if ((fs.f_bsize % 512) != 0) { + return 512; + } + + return (size_t) fs.f_bsize; +} + +#elif (NGX_HAVE_STATVFS) + +size_t +ngx_fs_bsize(u_char *name) +{ + struct statvfs fs; + + if (statvfs((char *) name, &fs) == -1) { + return 512; + } + + if ((fs.f_frsize % 512) != 0) { + return 512; + } + + return (size_t) fs.f_frsize; +} + +#else + +size_t +ngx_fs_bsize(u_char *name) +{ + return 512; +} + +#endif 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 @@ -274,4 +274,7 @@ ngx_int_t ngx_directio_off(ngx_fd_t fd); #endif +size_t ngx_fs_bsize(u_char *name); + + #endif /* _NGX_FILES_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h --- a/src/os/unix/ngx_freebsd_config.h +++ b/src/os/unix/ngx_freebsd_config.h @@ -22,6 +22,7 @@ #include #include #include +#include /* statfs() */ #include /* FIONBIO */ #include diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h --- a/src/os/unix/ngx_linux_config.h +++ b/src/os/unix/ngx_linux_config.h @@ -28,6 +28,7 @@ #include #include #include +#include /* statfs() */ #include #include diff --git a/src/os/unix/ngx_posix_config.h b/src/os/unix/ngx_posix_config.h --- a/src/os/unix/ngx_posix_config.h +++ b/src/os/unix/ngx_posix_config.h @@ -44,6 +44,12 @@ #include #include #include +#if (NGX_HAVE_SYS_MOUNT_H) +#include /* statfs() */ +#endif +#if (NGX_HAVE_SYS_STATVFS_H) +#include /* statvfs() */ +#endif #if (NGX_HAVE_SYS_FILIO_H) #include /* FIONBIO */ 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,7 @@ static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type); -static void ngx_start_cleaner_process(ngx_cycle_t *cycle, ngx_int_t type); +static void ngx_start_cache_manager_process(ngx_cycle_t *cycle, ngx_int_t type); 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); @@ -24,8 +24,8 @@ static void ngx_channel_handler(ngx_even static void ngx_wakeup_worker_threads(ngx_cycle_t *cycle); static ngx_thread_value_t ngx_worker_thread_cycle(void *data); #endif -static void ngx_cleaner_process_cycle(ngx_cycle_t *cycle, void *data); -static void ngx_cleaner_process_handler(ngx_event_t *ev); +static void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data); +static void ngx_cache_manager_process_handler(ngx_event_t *ev); ngx_uint_t ngx_process; @@ -122,7 +122,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); - ngx_start_cleaner_process(cycle, NGX_PROCESS_RESPAWN); + ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN); ngx_new_binary = 0; delay = 0; @@ -203,7 +203,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_cleaner_process(cycle, NGX_PROCESS_RESPAWN); + ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN); ngx_noaccepting = 0; continue; @@ -222,7 +222,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_cleaner_process(cycle, NGX_PROCESS_JUST_RESPAWN); + ngx_start_cache_manager_process(cycle, NGX_PROCESS_JUST_RESPAWN); live = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); @@ -232,7 +232,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_cleaner_process(cycle, NGX_PROCESS_RESPAWN); + ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN); live = 1; } @@ -360,7 +360,7 @@ ngx_start_worker_processes(ngx_cycle_t * static void -ngx_start_cleaner_process(ngx_cycle_t *cycle, ngx_int_t type) +ngx_start_cache_manager_process(ngx_cycle_t *cycle, ngx_int_t type) { ngx_int_t i; ngx_uint_t n; @@ -369,7 +369,7 @@ ngx_start_cleaner_process(ngx_cycle_t *c path = ngx_cycle->pathes.elts; for (n = 0; n < ngx_cycle->pathes.nelts; n++) { - if (path[n]->cleaner) { + if (path[n]->manager) { goto start; } } @@ -380,8 +380,8 @@ start: ch.command = NGX_CMD_OPEN_CHANNEL; - ngx_spawn_process(cycle, ngx_cleaner_process_cycle, NULL, - "cleaner process", type); + 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; @@ -1263,7 +1263,7 @@ ngx_worker_thread_cycle(void *data) static void -ngx_cleaner_process_cycle(ngx_cycle_t *cycle, void *data) +ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data) { void *ident[4]; ngx_event_t ev; @@ -1275,14 +1275,14 @@ ngx_cleaner_process_cycle(ngx_cycle_t *c ngx_close_listening_sockets(cycle); ngx_memzero(&ev, sizeof(ngx_event_t)); - ev.handler = ngx_cleaner_process_handler; + ev.handler = ngx_cache_manager_process_handler; ev.data = ident; ev.log = cycle->log; ident[3] = (void *) -1; ngx_use_accept_mutex = 0; - ngx_setproctitle("cleaner process"); + ngx_setproctitle("cache manager process"); ngx_add_timer(&ev, 0); @@ -1305,7 +1305,7 @@ ngx_cleaner_process_cycle(ngx_cycle_t *c static void -ngx_cleaner_process_handler(ngx_event_t *ev) +ngx_cache_manager_process_handler(ngx_event_t *ev) { time_t next, n; ngx_uint_t i; @@ -1316,8 +1316,8 @@ ngx_cleaner_process_handler(ngx_event_t path = ngx_cycle->pathes.elts; for (i = 0; i < ngx_cycle->pathes.nelts; i++) { - if (path[i]->cleaner) { - n = path[i]->cleaner(path[i]->data); + if (path[i]->manager) { + n = path[i]->manager(path[i]->data); next = (n <= next) ? n : next; diff --git a/src/os/unix/ngx_solaris_config.h b/src/os/unix/ngx_solaris_config.h --- a/src/os/unix/ngx_solaris_config.h +++ b/src/os/unix/ngx_solaris_config.h @@ -28,6 +28,7 @@ #include #include #include +#include /* statvfs() */ #include /* FIONBIO */ #include