| From | Sent On | Attachments |
|---|---|---|
| Peter Schüller | Oct 9, 2009 1:46 am | .gz, .diff |
| W-Mark Kubacki | Oct 9, 2009 2:28 am | |
| Peter Schüller | Oct 9, 2009 3:09 am | |
| bit bull | Oct 9, 2009 7:59 pm | |
| Peter Schüller | Oct 27, 2009 3:13 am | |
| Chieu | Nov 1, 2009 12:45 am | |
| Peter Schüller | Nov 3, 2009 9:45 am |
| Subject: | DHT upstream module + nginx patches | |
|---|---|---|
| From: | Peter Schüller (sco...@spotify.com) | |
| Date: | Oct 9, 2009 1:46:22 am | |
| List: | ru.sysoev.nginx | |
| Attachments: | ![]() spdht.tar.gz - 16k | |
Hello,
We have been doing some nginx development for internal use. Tommie has already sent the statistics module to the list yesterday separately, because it was very self-contained. However, we have additional changes that are not suitable for submission for inclusion, but we still want to publish the code in the hope that it may be useful to someone and to elicit feedback from interested people.
I am attaching two things; a module (spdht) which implements DHT based routing of requests to multiple upstream servers, and a patchset for nginx itself (against 0.7.61) that are needed, in part, in order to use the module.
In both cases, it is unpolished in terms of its release, and we realize it is not directly applicable to any user of nginx. However even so we would rather release it than not, and at least interested people may look at the code. Some parts may be suitable for selective inclusion.
The spdh module routes requests based on the hash of the URL being requested. It needs some configuration in nginx itself (an example nginx.conf is included in the tarball). In addition the DHT ring is configured through DNS. For a simple case with only two hosts (for brevity), DNS is configured similar to this:
; DHT cluster options - replication level for each collection, and hash algorithm config._service-name._http TXT "slaves=stuff:2 otherstuff:1" "hash=sha1"
; SRV records for the service _service-name._http SRV 1000 1000 80 host1 _service-name._http SRV 1000 1000 80 host2
; TXT records containing DHT tokens tokens.80.host1 TXT "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" tokens.80.host2 TXT "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
This puts host1 and host2 into the ring, each responsible for half of the keyspace.
For a given path P, the set of hosts responsible for that path is is calculated by hashing the path N times for N levels of redundancy (note that the config TXT record specifies slave count; this is actually a misnomer since the slave role does not exist; 1 slave -> 2 copies of a file).
In case of duplicate hosts, hashing continues (with some limit) until N unique hosts have been found.
Now, in terms of the patches to nginx itself, a short summary of the approximate feature set is:
* Add support for SHA1 in the caching module. * Support multi-threaded (one thread per disk) traversal of the cache during cache manager start up. * Some tempfile allocation fixes, avoiding an infinite loop in certain failure modes (e.g. broken disk). * Additional statistics (as submitted separately, but included here too). * Support failing quickly when workers are exhausted (e.g. due to broken disks, overload) rather than causing slow modes of failure (max_active_workers). * A posix_fdatasync()/posix_fadvise() hack to avoid buffer cache thrashing when pulling data into the cache (synchronous call - will block unrelated requests in the same worker). * Cache module uses prefix instead of postfix directory structure. * When allocating temp files, pass a prefix onto the tempfile so that the tempfile ends up in the same directory as the final file. This allows the prefix tree to by a symlink farm pointing to distinct drives, without breaking atomic rename() semantics.
-- / Peter Schuller aka scode
diff -uNr 0.7.61/auto/modules trunk/auto/modules --- 0.7.61/auto/modules 2009-10-09 09:53:17.000000000 +0200 +++ trunk/auto/modules 2009-10-09 09:53:26.000000000 +0200 @@ -325,6 +325,10 @@ HTTP_SRCS="$HTTP_SRCS src/http/modules/ngx_http_stub_status_module.c" fi
+have=NGX_STATISTICS . auto/have +HTTP_MODULES="$HTTP_MODULES ngx_http_statistics_module" +HTTP_SRCS="$HTTP_SRCS src/http/modules/ngx_http_statistics_module.c" + #if [ -r $NGX_OBJS/auto ]; then # . $NGX_OBJS/auto #fi diff -uNr 0.7.61/auto/options trunk/auto/options --- 0.7.61/auto/options 2009-10-09 09:53:17.000000000 +0200 +++ trunk/auto/options 2009-10-09 09:53:26.000000000 +0200 @@ -110,7 +110,7 @@ MD5_OPT= MD5_ASM=NO
-USE_SHA1=NO +USE_SHA1=YES SHA1=NONE SHA1_OPT= SHA1_ASM=NO @@ -166,8 +166,8 @@ --without-poll_module) EVENT_POLL=NONE ;; --with-aio_module) EVENT_AIO=YES ;;
- #--with-threads=*) USE_THREADS="$value" ;; - #--with-threads) USE_THREADS="pthreads" ;; + --with-threads=*) USE_THREADS="$value" ;; + --with-threads) USE_THREADS="pthreads" ;;
--with-ipv6) NGX_IPV6=YES ;;
@@ -394,6 +394,8 @@
--with-openssl=DIR set path to OpenSSL library sources
--with-openssl-opt=OPTIONS set additional options for OpenSSL
building
+ --with-threads enable threads + --with-debug enable the debugging logging
END diff -uNr 0.7.61/auto/sources trunk/auto/sources --- 0.7.61/auto/sources 2009-10-09 09:53:17.000000000 +0200 +++ trunk/auto/sources 2009-10-09 09:53:26.000000000 +0200 @@ -2,7 +2,7 @@ # Copyright (C) Igor Sysoev
-CORE_MODULES="ngx_core_module ngx_errlog_module ngx_conf_module"
+CORE_MODULES="ngx_core_module ngx_errlog_module ngx_conf_module
ngx_statistics_module"
CORE_INCS="src/core"
@@ -31,6 +31,7 @@ src/core/ngx_shmtx.h \ src/core/ngx_connection.h \ src/core/ngx_cycle.h \ + src/core/ngx_statistics.h \ src/core/ngx_conf_file.h \ src/core/ngx_resolver.h \ src/core/ngx_open_file_cache.h" @@ -58,6 +59,7 @@ src/core/ngx_connection.c \ src/core/ngx_cycle.c \ src/core/ngx_spinlock.c \ + src/core/ngx_statistics.c \ src/core/ngx_cpuinfo.c \ src/core/ngx_conf_file.c \ src/core/ngx_resolver.c \ diff -uNr 0.7.61/auto/summary trunk/auto/summary --- 0.7.61/auto/summary 2009-10-09 09:53:17.000000000 +0200 +++ trunk/auto/summary 2009-10-09 09:53:26.000000000 +0200 @@ -2,34 +2,19 @@ # Copyright (C) Igor Sysoev
-### STUB - -if [ $USE_THREADS != NO ]; then - -cat << END - -$0: error: the threads support is broken now. - -END - exit 1 - fi - -### - - echo echo "Configuration summary"
-#case $USE_THREADS in -# rfork) echo " + using rfork()ed threads" ;; -# pthreads) echo " + using libpthread threads library" ;; -# libthr) echo " + using FreeBSD libthr threads library" ;; -# libc_r) echo " + using FreeBSD libc_r threads library" ;; -# linuxthreads) echo " + using FreeBSD LinuxThreads port library" ;; -# NO) echo " + threads are not used" ;; -# *) echo " + using lib$USE_THREADS threads library" ;; -#esac +case $USE_THREADS in + rfork) echo " + using rfork()ed threads" ;; + pthreads) echo " + using libpthread threads library" ;; + libthr) echo " + using FreeBSD libthr threads library" ;; + libc_r) echo " + using FreeBSD libc_r threads library" ;; + linuxthreads) echo " + using FreeBSD LinuxThreads port library" ;; + NO) echo " + threads are not used" ;; + *) echo " + using lib$USE_THREADS threads library" ;; +esac
if [ $USE_PCRE = DISABLED ]; then echo " + PCRE library is disabled" diff -uNr 0.7.61/auto/threads trunk/auto/threads --- 0.7.61/auto/threads 2009-10-09 09:53:17.000000000 +0200 +++ trunk/auto/threads 2009-10-09 09:53:26.000000000 +0200 @@ -4,7 +4,7 @@
case $USE_THREADS in rfork) - have=NGX_THREADS . auto/have + have=NGX_CAN_HAZ_THREADS . auto/have have=NGX_USE_RFORK . auto/have CORE_DEPS="$CORE_DEPS $FREEBSD_RFORK_DEPS" CORE_SRCS="$CORE_SRCS $FREEBSD_RFORK_SRCS" @@ -21,19 +21,19 @@ ;;
pthreads) - have=NGX_THREADS . auto/have + have=NGX_CAN_HAZ_THREADS . auto/have CORE_SRCS="$CORE_SRCS $PTHREAD_SRCS" CORE_LIBS="$CORE_LIBS -lpthread" ;;
libthr) - have=NGX_THREADS . auto/have + have=NGX_CAN_HAZ_THREADS . auto/have CORE_SRCS="$CORE_SRCS $PTHREAD_SRCS" CORE_LIBS="$CORE_LIBS -lthr" ;;
linuxthreads) - have=NGX_THREADS . auto/have + have=NGX_CAN_HAZ_THREADS . auto/have have=NGX_LINUXTHREADS . auto/have CFLAGS="$CFLAGS -D_THREAD_SAFE" CFLAGS="$CFLAGS -I /usr/local/include/pthread/linuxthreads" @@ -44,14 +44,14 @@ libc_r) case "$NGX_PLATFORM" in FreeBSD:[34]*) - have=NGX_THREADS . auto/have + have=NGX_CAN_HAZ_THREADS . auto/have CFLAGS="$CFLAGS -pthread" CORE_SRCS="$CORE_SRCS $PTHREAD_SRCS" CORE_LIBS="$CORE_LIBS -pthread" ;;
FreeBSD:[56]*) - have=NGX_THREADS . auto/have + have=NGX_CAN_HAZ_THREADS . auto/have CORE_SRCS="$CORE_SRCS $PTHREAD_SRCS" CORE_LIBS="$CORE_LIBS -lc_r" ;; @@ -62,7 +62,7 @@ ;;
*) - have=NGX_THREADS . auto/have + have=NGX_CAN_HAZ_THREADS . auto/have CORE_SRCS="$CORE_SRCS $PTHREAD_SRCS" CORE_LIBS="$CORE_LIBS -l$USE_THREADS" ;; diff -uNr 0.7.61/src/core/nginx.c trunk/src/core/nginx.c --- 0.7.61/src/core/nginx.c 2009-10-09 09:53:16.000000000 +0200 +++ trunk/src/core/nginx.c 2009-10-09 09:53:25.000000000 +0200 @@ -136,7 +136,7 @@ 0, NULL },
-#if (NGX_THREADS) +#if (NGX_THREADS) || (NGX_CAN_HAZ_THREADS)
{ ngx_string("worker_threads"), NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, @@ -928,7 +928,7 @@ ccf->user = (ngx_uid_t) NGX_CONF_UNSET_UINT; ccf->group = (ngx_gid_t) NGX_CONF_UNSET_UINT;
-#if (NGX_THREADS) +#if (NGX_THREADS) || (NGX_CAN_HAZ_THREADS) ccf->worker_threads = NGX_CONF_UNSET; ccf->thread_stack_size = NGX_CONF_UNSET_SIZE; #endif @@ -971,6 +971,7 @@
#if (NGX_THREADS)
+#error the threads support is broken now. ngx_conf_init_value(ccf->worker_threads, 0); ngx_threads_n = ccf->worker_threads; ngx_conf_init_size_value(ccf->thread_stack_size, 2 * 1024 * 1024); diff -uNr 0.7.61/src/core/ngx_array.c trunk/src/core/ngx_array.c --- 0.7.61/src/core/ngx_array.c 2009-10-09 09:53:16.000000000 +0200 +++ trunk/src/core/ngx_array.c 2009-10-09 09:53:25.000000000 +0200 @@ -78,14 +78,14 @@ } else { /* allocate a new array */
- new = ngx_palloc(p, 2 * size); + new = ngx_palloc(p, (2 * size) + (size == 0 ? a->size : 0)); if (new == NULL) { return NULL; }
ngx_memcpy(new, a->elts, size); a->elts = new; - a->nalloc *= 2; + a->nalloc = (a->nalloc * 2) + (size == 0 ? 1 : 0); } }
diff -uNr 0.7.61/src/core/ngx_core.h trunk/src/core/ngx_core.h --- 0.7.61/src/core/ngx_core.h 2009-10-09 09:53:16.000000000 +0200 +++ trunk/src/core/ngx_core.h 2009-10-09 09:53:25.000000000 +0200 @@ -83,6 +83,7 @@
#define ngx_abs(value) (((value) >= 0) ? (value) : - (value)) +#define ngx_max(a, b) (((a) > (b)) ? (a) : (b))
void ngx_cpuinfo(void);
diff -uNr 0.7.61/src/core/ngx_cycle.h trunk/src/core/ngx_cycle.h --- 0.7.61/src/core/ngx_cycle.h 2009-10-09 09:53:16.000000000 +0200 +++ trunk/src/core/ngx_cycle.h 2009-10-09 09:53:25.000000000 +0200 @@ -98,7 +98,7 @@ ngx_array_t env; char **environment;
-#if (NGX_THREADS) +#if (NGX_THREADS) || (NGX_CAN_HAZ_THREADS) ngx_int_t worker_threads; size_t thread_stack_size; #endif diff -uNr 0.7.61/src/core/ngx_file.c trunk/src/core/ngx_file.c --- 0.7.61/src/core/ngx_file.c 2009-10-09 09:53:16.000000000 +0200 +++ trunk/src/core/ngx_file.c 2009-10-09 09:53:25.000000000 +0200 @@ -19,7 +19,7 @@
if (tf->file.fd == NGX_INVALID_FILE) {
rc = ngx_create_temp_file(&tf->file, tf->path, tf->pool,
- tf->persistent, tf->clean, tf->access);
+ tf->persistent, tf->clean, tf->access,
tf->prefix);
if (rc == NGX_ERROR || rc == NGX_AGAIN) { return rc; @@ -37,14 +37,17 @@
ngx_int_t
ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool,
- ngx_uint_t persistent, ngx_uint_t clean, ngx_uint_t access)
+ ngx_uint_t persistent, ngx_uint_t clean, ngx_uint_t access, ngx_uint_t
prefix)
{
uint32_t n;
ngx_err_t err;
ngx_pool_cleanup_t *cln;
ngx_pool_cleanup_file_t *clnf;
+ uint32_t collisions = 0;
+ uint32_t failures = 0;
- file->name.len = path->name.len + 1 + path->len + 10; + /* 8 for prefix, dash, 10 for the temporary number and 4 for .tmp */ + file->name.len = path->name.len + 1 + path->len + 8 + 1 + 10 + 4;
file->name.data = ngx_pnalloc(pool, file->name.len + 1); if (file->name.data == NULL) { @@ -68,7 +71,7 @@
for ( ;; ) { (void) ngx_sprintf(file->name.data + path->name.len + 1 + path->len, - "%010uD%Z", n); + "%08xuD-%010uD.tmp%Z", prefix, n);
ngx_create_hashed_filename(path, file->name.data, file->name.len);
@@ -95,6 +98,12 @@ err = ngx_errno;
if (err == NGX_EEXIST) { + if (++collisions > 7) { + ngx_log_error(NGX_LOG_CRIT, file->log, err, + ngx_open_tempfile_n " \"%s\" collision fail", + file->name.data); + return NGX_ERROR; + } n = (uint32_t) ngx_next_temp_number(1); continue; } @@ -115,6 +124,13 @@ if (ngx_create_path(file, path) == NGX_ERROR) { return NGX_ERROR; } + + if (++failures > 7) { + ngx_log_error(NGX_LOG_CRIT, file->log, err, + ngx_open_tempfile_n " \"%s\" multi fail", + file->name.data); + return NGX_ERROR; + } } }
@@ -122,10 +138,11 @@ void ngx_create_hashed_filename(ngx_path_t *path, u_char *file, size_t len) { - size_t i, level; + size_t i, j, level; ngx_uint_t n;
i = path->name.len + 1; + j = path->name.len + path->len + 1;
file[path->name.len + path->len] = '/';
@@ -138,8 +155,9 @@
len -= level; file[i - 1] = '/'; - ngx_memcpy(&file[i], &file[len], level); + ngx_memcpy(&file[i], &file[j], level); i += level + 1; + j += level; } }
@@ -626,6 +644,70 @@ }
+ngx_int_t +ngx_walk_tree_descend(ngx_tree_ctx_t *ctx, ngx_str_t *file) +{ + ngx_uint_t access; + time_t mtime; + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, + "tree enter dir \"%s\"", file->data); + + access = ctx->access; + mtime = ctx->mtime; + + ctx->depth += 1; + + if (ctx->pre_tree_handler(ctx, file) == NGX_ABORT) { + return NGX_ABORT; + } + + if (ngx_walk_tree(ctx, file) == NGX_ABORT) { + return NGX_ABORT; + } + + ctx->access = access; + ctx->mtime = mtime; + + if (ctx->post_tree_handler(ctx, file) == NGX_ABORT) { + return NGX_ABORT; + } + + ctx->depth -= 1; + + return NGX_OK; +} + + +#if (NGX_CAN_HAZ_THREADS) + +ngx_thread_value_t ngx_walk_tree_task_run(void *arg) +{ + ngx_walk_tree_task_t *task; + ngx_walk_tree_sub_t *sub; + ngx_uint_t i, rc; + + task = arg; + task->result = NGX_OK; + + for (i = 0; i < task->subs->nelts; i++) { + + sub = (ngx_walk_tree_sub_t *)task->subs->elts + i; + + rc = ngx_walk_tree_descend(&sub->ctx, &sub->file); + + if (rc != NGX_OK) { + task->result = rc; + break; + } + } + + return NULL; +} + +#endif /* NGX_CAN_HAZ_THREADS */ + + /* * ctx->init_handler() - see ctx->alloc * ctx->file_handler() - file handler @@ -647,13 +729,21 @@ ngx_int_t ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree) { - void *data, *prev; - u_char *p, *name; - size_t len; - ngx_int_t rc; - ngx_err_t err; - ngx_str_t file, buf; - ngx_dir_t dir; + void *data, *prev; + u_char *p, *name; + size_t len; + ngx_int_t rc; + ngx_err_t err; + ngx_str_t file, buf; + ngx_dir_t dir; +#if (NGX_CAN_HAZ_THREADS) + ngx_walk_tree_task_t *task, **tasks; + ngx_walk_tree_sub_t *sub; + ngx_fsid_t fsid, *fsidp, *fsids, lfsid; + ngx_uint_t i, j, lpool; +#endif + + rc = NGX_OK;
buf.len = 0; buf.data = NULL; @@ -667,16 +757,40 @@ return NGX_ERROR; }
+#if (NGX_CAN_HAZ_THREADS) + + if (ngx_fs_id(tree->data, &lfsid) != NGX_OK) { + return NGX_ABORT; + } + + lpool = 0; + + if (ctx->depth == 0) { + ctx->tasks = NULL; + ctx->fsids = NULL; + + if (ctx->pool == NULL) { + lpool = 1; + ctx->pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, ctx->log); + + if (ctx->pool == NULL) { + return NGX_ABORT; + } + } + } + +#endif + prev = ctx->data;
- if (ctx->alloc) { + if (rc == NGX_OK && ctx->alloc) { data = ngx_alloc(ctx->alloc, ctx->log); if (data == NULL) { - goto failed; - } + rc = NGX_ABORT;
- if (ctx->init_handler(data, prev) == NGX_ABORT) { - goto failed; + } else if (ctx->init_handler(data, prev) == NGX_ABORT) { + + rc = NGX_ABORT; }
ctx->data = data; @@ -685,7 +799,7 @@ data = NULL; }
- for ( ;; ) { + while( rc == NGX_OK ) {
ngx_set_errno(0);
@@ -701,14 +815,14 @@ rc = NGX_ERROR; }
- goto done; + break; }
len = ngx_de_namelen(&dir); name = ngx_de_name(&dir);
ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0,
- "tree name %uz:\"%s\"", len, name);
+ "tree name %uz:\"%s\", depth %d", len, name,
ctx->depth);
if (len == 1 && name[0] == '.') { continue; @@ -730,7 +844,8 @@
buf.data = ngx_alloc(buf.len + 1, ctx->log); if (buf.data == NULL) { - goto failed; + rc = NGX_ABORT; + break; } }
@@ -751,59 +866,229 @@ } }
+ ctx->access = ngx_de_access(&dir); + ctx->mtime = ngx_de_mtime(&dir); + if (ngx_de_is_file(&dir)) {
ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree file \"%s\"", file.data);
ctx->size = ngx_de_size(&dir); - ctx->access = ngx_de_access(&dir); - ctx->mtime = ngx_de_mtime(&dir);
if (ctx->file_handler(ctx, &file) == NGX_ABORT) { - goto failed; + rc = NGX_ABORT; + break; }
} else if (ngx_de_is_dir(&dir)) {
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, - "tree enter dir \"%s\"", file.data); - - ctx->access = ngx_de_access(&dir); - ctx->mtime = ngx_de_mtime(&dir); +#if ! (NGX_CAN_HAZ_THREADS)
- if (ctx->pre_tree_handler(ctx, &file) == NGX_ABORT) { - goto failed; + if (ngx_walk_tree_descend(ctx, &file) != NGX_OK) { + rc = NGX_ABORT; + break; }
- if (ngx_walk_tree(ctx, &file) == NGX_ABORT) { - goto failed; - } +#else + + /* If dir within thread_depth and on a different file system, + * assign dir to a separate thread (as a ngx_walk_tree_sub_t added + * the appropriate ngx_walk_tree_task_t) + */ + if (ctx->depth >= ctx->thread_depth) { + + if (ngx_walk_tree_descend(ctx, &file) == NGX_ABORT) { + rc = NGX_ABORT; + break; + } + + } else { + + if (ngx_fs_id(file.data, &fsid) != NGX_OK) { + rc = NGX_ABORT; + break; + } + + if (ngx_fsid_t_cmp(&fsid, &lfsid) == 0) { + + if (ngx_walk_tree_descend(ctx, &file) != NGX_OK) { + rc = NGX_ABORT; + break; + } + + } else { + + if (ctx->tasks == NULL) { + + ctx->tasks = ngx_array_create(ctx->pool, 1, + sizeof(ngx_walk_tree_task_t *)); + ctx->fsids = ngx_array_create(ctx->pool, 1, + sizeof(ngx_fsid_t)); + + if (ctx->tasks == NULL || ctx->fsids == NULL) { + rc = NGX_ABORT; + break; + } + } + + fsids = (ngx_fsid_t *)ctx->fsids->elts; + tasks = (ngx_walk_tree_task_t **)ctx->tasks->elts; + + fsidp = (ngx_fsid_t *)bsearch(&fsid, fsids, + ctx->fsids->nelts, + sizeof(ngx_fsid_t), + ngx_fsid_t_cmp); + if (fsidp == NULL) { + + if (ngx_array_push(ctx->fsids) == NULL || + ngx_array_push(ctx->tasks) == NULL) { + rc = NGX_ABORT; + break; + } + tasks = (ngx_walk_tree_task_t **)ctx->tasks->elts; + fsids = (ngx_fsid_t *)ctx->fsids->elts; + + task = ngx_palloc(ctx->pool, + sizeof(ngx_walk_tree_task_t)); + tasks[ctx->tasks->nelts - 1] = task; + + if (task == NULL) { + rc = NGX_ABORT; + break; + } + + task->in_thread = 0; + task->subs = ngx_array_create(ctx->pool, 1, + sizeof(ngx_walk_tree_sub_t)); + if (task->subs == NULL) { + rc = NGX_ABORT; + break; + } + + fsids[ctx->fsids->nelts - 1] = fsid; + + /* bubble up */ + fsids = (ngx_fsid_t *)ctx->fsids->elts; + for (i = ctx->fsids->nelts - 1; i > 0; i--) { + + if (ngx_fsid_t_cmp(&fsids[i-1], &fsids[i]) < 0) { + break; + } + fsid = fsids[i-1]; + task = tasks[i-1]; + fsids[i-1] = fsids[i]; + tasks[i-1] = tasks[i]; + fsids[i] = fsid; + tasks[i] = task; + } + fsidp = &fsids[i]; + } + + i = fsidp - (ngx_fsid_t *) ctx->fsids->elts; + task = tasks[i]; + + sub = ngx_array_push(task->subs); + if (sub == NULL) { + rc = NGX_ABORT; + break; + }
- ctx->access = ngx_de_access(&dir); - ctx->mtime = ngx_de_mtime(&dir); + ngx_memcpy(&sub->ctx, ctx, sizeof(ngx_tree_ctx_t)); + sub->ctx.thread_depth = 0; + sub->file.len = file.len; + sub->file.data = ngx_palloc(ctx->pool, file.len + 1); + ngx_memcpy(sub->file.data, file.data, file.len + 1);
- if (ctx->post_tree_handler(ctx, &file) == NGX_ABORT) { - goto failed; + } }
+#endif /* NGX_CAN_HAZ_THREADS */ + } else {
ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree special \"%s\"", file.data);
if (ctx->spec_handler(ctx, &file) == NGX_ABORT) { - goto failed; + rc = NGX_ABORT; + break; } } }
-failed: +#if (NGX_CAN_HAZ_THREADS) + + if (ctx->depth == 0 && ctx->tasks != NULL) { + if (rc == NGX_OK) { + + if (ctx->tasks->nelts == 1) { + task = *(ngx_walk_tree_task_t **)ctx->tasks->elts; + + ngx_walk_tree_task_run(task); + rc = task->result; + + } else { + + for (i = 0; i < ctx->tasks->nelts; i ++) { + task = *((ngx_walk_tree_task_t **)ctx->tasks->elts + i); + + task->in_thread = 1; + + if (ngx_create_thread(&task->thread.tid, + ngx_walk_tree_task_run, + task, ctx->log) != NGX_OK) { + + task->in_thread = 0; + ngx_walk_tree_task_run(task); + + if (task->result != NGX_OK) { + break; + } + } + } + + for(i = 0; i < ctx->tasks->nelts; i++) { + task = *((ngx_walk_tree_task_t **)ctx->tasks->elts + i);
- rc = NGX_ABORT; + if (task->in_thread) { + ngx_errno = 0; + if (ngx_thread_join(task->thread.tid, NULL)) { + ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, + ngx_thread_join_n " failed");
-done: + } + } + + if (task->result != NGX_OK) { + rc = task->result; + } + } + } + } + + for (i = 0; i < ctx->tasks->nelts; i++) { + task = *((ngx_walk_tree_task_t **)ctx->tasks->elts + i); + + for (j = 0; j < task->subs->nelts; j++) { + sub = (ngx_walk_tree_sub_t *)task->subs->elts + j; + ngx_pfree(ctx->pool, sub->file.data); + } + + ngx_array_destroy(task->subs); + ngx_pfree(ctx->pool, task); + } + + ngx_array_destroy(ctx->tasks); + ngx_array_destroy(ctx->fsids); + } + + if (lpool) { + ngx_destroy_pool(ctx->pool); + ctx->pool = NULL; + }
+#endif /* NGX_CAN_HAZ_THREADS */ if (buf.len) { ngx_free(buf.data); } diff -uNr 0.7.61/src/core/ngx_file.h trunk/src/core/ngx_file.h --- 0.7.61/src/core/ngx_file.h 2009-10-09 09:53:16.000000000 +0200 +++ trunk/src/core/ngx_file.h 2009-10-09 09:53:25.000000000 +0200 @@ -63,6 +63,7 @@ unsigned log_level:8; unsigned persistent:1; unsigned clean:1; + ngx_uint_t prefix; } ngx_temp_file_t;
@@ -100,14 +101,43 @@ void *data; size_t alloc;
+ ngx_uint_t depth; + +#if (NGX_CAN_HAZ_THREADS) + ngx_array_t *tasks; + ngx_array_t *fsids; + ngx_pool_t *pool; + ngx_uint_t thread_depth; +#endif + ngx_log_t *log; };
+#if (NGX_CAN_HAZ_THREADS) + +typedef struct ngx_walk_tree_task_s ngx_walk_tree_task_t; +typedef struct ngx_walk_tree_sub_s ngx_walk_tree_sub_t; + + +struct ngx_walk_tree_sub_s { + ngx_tree_ctx_t ctx; + ngx_str_t file; +}; + + +struct ngx_walk_tree_task_s { + ngx_array_t *subs; + ngx_uint_t result; + ngx_thread_t thread; + ngx_uint_t in_thread; +}; + +#endif
ssize_t ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain);
ngx_int_t ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path,
ngx_pool_t *pool, ngx_uint_t persistent, ngx_uint_t clean,
- ngx_uint_t access);
+ ngx_uint_t access, ngx_uint_t prefix);
void ngx_create_hashed_filename(ngx_path_t *path, u_char *file, size_t len);
ngx_int_t ngx_create_path(ngx_file_t *file, ngx_path_t *path);
ngx_err_t ngx_create_full_path(u_char *dir, ngx_uint_t access);
diff -uNr 0.7.61/src/core/ngx_statistics.c trunk/src/core/ngx_statistics.c
--- 0.7.61/src/core/ngx_statistics.c 1970-01-01 01:00:00.000000000 +0100
+++ trunk/src/core/ngx_statistics.c 2009-10-09 09:53:25.000000000 +0200
@@ -0,0 +1,375 @@
+/*
+ * @todo implement the histogram stuff.
+ */
+#include <ngx_statistics.h>
+
+
+/* --- Macros --- */
+#define ngx_statistics_lock_entry(e) ngx_spinlock(&(e), ngx_pid, 1024)
+#define ngx_statistics_unlock_entry(e) (void) ngx_atomic_cmp_set(&(e),
ngx_pid, 0)
+#define cacheline_size 128
+
+
+/* --- Types --- */
+typedef struct {
+ const ngx_statistics_descr_t *descr;
+ size_t size;
+ ngx_statistics_type_t type;
+ ngx_atomic_t lock; // Used for non-atomic types
+
+ union {
+ ngx_atomic_uint_t i;
+ ngx_str_t s;
+ ngx_atomic_uint_t *histo;
+ } value;
+
+ u_char data[0];
+} ngx_statistics_entry_t;
+
+typedef struct {
+ ngx_atomic_t create_lock; // Only used for creation
+ ngx_statistics_entry_t *end; // End of entries list
+ ngx_statistics_entry_t entries[0];
+} ngx_statistics_t;
+
+
+
+/* --- Data --- */
+static const ngx_int_t M[] = { 1, 2, 5 };
+static const ngx_int_t BASE = 10;
+
+static ngx_shm_t shm;
+static ngx_statistics_t *ngx_statistics;
+
+
+
+void ngx_statistics_add_int(ngx_stat_key_t key, ngx_int_t delta)
+{
+ ngx_statistics_entry_t *entry = (void*) (((u_char*) (ngx_statistics + 1)) +
key);
+ ngx_int_t bucket;
+
+ if (!ngx_statistics || key == NGX_STAT_KEY_INVALID || entry >=
ngx_statistics->end)
+ return;
+
+ if (entry->type != ngx_statistics_int)
+ return;
+
+ switch (entry->descr->histo) {
+ case ngx_statistics_invalid_histo:
+ ngx_atomic_fetch_add(&entry->value.i, delta);
+ return;
+
+ case ngx_statistics_linear:
+ if (delta < entry->descr->min) bucket = 0;
+ else if (delta >= entry->descr->max) bucket = entry->descr->num_buckets - 1;
+ else bucket = (delta - entry->descr->min) * entry->descr->num_buckets /
(entry->descr->max - entry->descr->min);
+ break;
+
+ case ngx_statistics_exponential:
+ {
+ ngx_int_t k = 0;
+ ngx_int_t p = 1;
+
+ for (bucket = 0; M[k] * p < delta - entry->descr->min && bucket <
entry->descr->num_buckets - 1; ++bucket) {
+ if (++k == sizeof(M) / sizeof(*M)) {
+ k = 0;
+ p *= BASE;
+ }
+ }
+ }
+
+ break;
+
+ default:
+ return;
+ }
+
+ ngx_atomic_fetch_add(&entry->value.histo[bucket], 1);
+}
+
+ngx_int_t ngx_statistics_get_int(ngx_stat_key_t key, ngx_int_t *value)
+{
+ ngx_statistics_entry_t *entry = (void*) (((u_char*) (ngx_statistics + 1)) +
key);
+
+ if (!ngx_statistics || key == NGX_STAT_KEY_INVALID || entry >=
ngx_statistics->end)
+ return NGX_ERROR;
+
+ if (entry->type != ngx_statistics_int)
+ return NGX_ERROR;
+
+ if (entry->descr->histo != ngx_statistics_invalid_histo)
+ return NGX_ERROR;
+
+ *value = entry->value.i;
+ return NGX_OK;
+}
+
+void ngx_statistics_set_int(ngx_stat_key_t key, ngx_int_t value)
+{
+ ngx_statistics_entry_t *entry = (void*) (((u_char*) (ngx_statistics + 1)) +
key);
+
+ if (!ngx_statistics || key == NGX_STAT_KEY_INVALID || entry >=
ngx_statistics->end)
+ return;
+
+ if (entry->type != ngx_statistics_int)
+ return;
+
+ switch (entry->descr->histo) {
+ case ngx_statistics_invalid_histo:
+ ngx_atomic_cmp_set(&entry->value.i, entry->value.i, value);
+ break;
+
+ case ngx_statistics_linear:
+ case ngx_statistics_exponential:
+ // For histograms, set is the same as add.
+ ngx_statistics_add_int(key, value);
+ break;
+ }
+}
+
+void ngx_statistics_set_str(ngx_stat_key_t key, ngx_str_t *value)
+{
+ ngx_statistics_entry_t *entry = (void*) (((u_char*) (ngx_statistics + 1)) +
key);
+
+ if (!ngx_statistics || key == NGX_STAT_KEY_INVALID || entry >=
ngx_statistics->end)
+ return;
+
+ if (entry->type != ngx_statistics_str)
+ return;
+
+ ngx_statistics_lock_entry(entry->lock);
+
+ if (value->len <= entry->size - sizeof(*entry))
+ entry->value.s.len = value->len;
+ else
+ entry->value.s.len = entry->size - sizeof(*entry);
+
+ ngx_memcpy(entry->value.s.data, value->data, entry->value.s.len);
+
+ ngx_statistics_unlock_entry(entry->lock);
+}
+
+static ngx_stat_key_t ngx_statistics_alloc(const ngx_statistics_descr_t *descr,
ngx_statistics_type_t type, size_t size, ngx_statistics_entry_t **entryp)
+{
+ ngx_statistics_entry_t *entry = ngx_statistics->entries;
+
+ if (size < sizeof(*entry))
+ return NGX_STAT_KEY_INVALID;
+
+ while (entry < ngx_statistics->end) {
+ if (descr == entry->descr) {
+ if (type != entry->type || size != entry->size)
+ return NGX_STAT_KEY_INVALID;
+
+ if (entryp) *entryp = entry;
+
+ return (u_char*) ngx_statistics->entries - (u_char*) entry;
+ }
+
+ entry = (ngx_statistics_entry_t*) ((u_char*) entry + entry->size);
+ }
+
+ if (entry != ngx_statistics->end)
+ return NGX_STAT_KEY_INVALID;
+
+ entry->descr = descr;
+ entry->size = size;
+ entry->type = type;
+ entry->lock = 0;
+
+ // entry->value is initialized by _create_*()
+
+ ngx_statistics->end = (ngx_statistics_entry_t*) ((u_char*) ngx_statistics->end
+ size);
+
+ if (entryp) *entryp = entry;
+
+ return (u_char*) entry - (u_char*) ngx_statistics->entries;
+}
+
+ngx_stat_key_t ngx_statistics_create_int(const ngx_statistics_descr_t *descr,
ngx_int_t initial)
+{
+ ngx_stat_key_t ret;
+ ngx_statistics_entry_t *entry;
+ ngx_int_t i;
+
+ if (!ngx_statistics)
+ return NGX_STAT_KEY_INVALID;
+
+ if (descr->histo == ngx_statistics_invalid_histo && descr->num_buckets != 1)
+ return NGX_STAT_KEY_INVALID;
+
+ ngx_spinlock(&ngx_statistics->create_lock, ngx_pid, 1024);
+
+ ret = ngx_statistics_alloc(descr, ngx_statistics_int,
sizeof(ngx_statistics_entry_t) + sizeof(ngx_int_t) * descr->num_buckets,
&entry);
+
+ if (ret == NGX_STAT_KEY_INVALID) {
+ (void) ngx_atomic_cmp_set(&ngx_statistics->create_lock, ngx_pid, 0);
+
+ return ret;
+ }
+
+ if (descr->histo != ngx_statistics_invalid_histo) {
+ entry->value.histo = (ngx_atomic_uint_t*) entry->data;
+
+ for (i = 0; i < descr->num_buckets; ++i)
+ entry->value.histo[i] = initial;
+ } else {
+ entry->value.i = initial;
+ }
+
+ (void) ngx_atomic_cmp_set(&ngx_statistics->create_lock, ngx_pid, 0);
+
+ return ret;
+}
+
+ngx_stat_key_t ngx_statistics_create_str(const ngx_statistics_descr_t *descr,
ngx_int_t max_size, ngx_str_t *initial)
+{
+ ngx_stat_key_t ret;
+ ngx_statistics_entry_t *entry;
+
+ if (!ngx_statistics)
+ return NGX_STAT_KEY_INVALID;
+
+ if (descr->histo != ngx_statistics_invalid_histo)
+ return NGX_STAT_KEY_INVALID;
+
+ ngx_spinlock(&ngx_statistics->create_lock, ngx_pid, 1024);
+
+ ret = ngx_statistics_alloc(descr, ngx_statistics_str,
sizeof(ngx_statistics_entry_t) + max_size + 1, &entry);
+
+ if (ret == NGX_STAT_KEY_INVALID) {
+ (void) ngx_atomic_cmp_set(&ngx_statistics->create_lock, ngx_pid, 0);
+
+ return ret;
+ }
+
+ entry->value.s.len = initial->len;
+ entry->value.s.data = entry->data;
+ ngx_memcpy(entry->value.s.data, initial->data, initial->len);
+
+ (void) ngx_atomic_cmp_set(&ngx_statistics->create_lock, ngx_pid, 0);
+
+ return ret;
+}
+
+ngx_statistics_type_t ngx_statistics_entry(ngx_stat_iter_t it, const
ngx_statistics_descr_t **descr, void **value)
+{
+ ngx_statistics_entry_t *entry = (void*) (((u_char*) ngx_statistics->entries) +
it);
+
+ if (!ngx_statistics_valid(it))
+ return ngx_statistics_invalid_type;
+
+ if (descr) *descr = entry->descr;
+
+ if (value) {
+ if (entry->descr->histo == ngx_statistics_invalid_histo)
+ *value = &entry->value;
+ else
+ *value = entry->value.histo;
+ }
+
+ return entry->type;
+}
+
+ngx_stat_iter_t ngx_statistics_iter(void)
+{
+ return 0;
+}
+
+ngx_stat_iter_t ngx_statistics_next(ngx_stat_iter_t it)
+{
+ ngx_statistics_entry_t *entry = (void*) (((u_char*) ngx_statistics->entries) +
it);
+
+ if (!ngx_statistics_valid(it))
+ return it;
+
+ return it + entry->size;
+}
+
+ngx_int_t ngx_statistics_valid(ngx_stat_iter_t it)
+{
+ return ngx_statistics && (u_char*) ngx_statistics->entries + it < (u_char*)
ngx_statistics->end;
+}
+
+static ngx_int_t powi(ngx_int_t base, ngx_int_t exp)
+{
+ ngx_int_t ret = 1;
+
+ while (exp--) ret *= base;
+
+ return ret;
+}
+
+ngx_int_t ngx_statistics_bucket_lower(const ngx_statistics_descr_t *descr,
ngx_int_t bucket)
+{
+ switch (descr->histo) {
+ case ngx_statistics_invalid_histo:
+ return descr->min;
+
+ case ngx_statistics_linear:
+ return descr->min + (descr->max - descr->min) * bucket / descr->num_buckets;
+
+ case ngx_statistics_exponential:
+ if (!bucket) return descr->min;
+
+ --bucket;
+
+ return descr->min + M[bucket % (sizeof(M) / sizeof(*M))] * powi(BASE, bucket
/ 3);
+ }
+
+ return -1;
+}
+
+
+static ngx_int_t ngx_statistics_module_init(ngx_cycle_t *cycle)
+{
+ /* This would fit around 64 entries */
+ shm.size = 64 * cacheline_size;
+ shm.log = cycle->log;
+ shm.name.len = sizeof("ngx_statistics");
+ shm.name.data = (u_char*) "ngx_statistics";
+
+ if (ngx_shm_alloc(&shm) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ ngx_statistics = (ngx_statistics_t*) shm.addr;
+
+ ngx_statistics->create_lock = 0;
+ ngx_statistics->end = ngx_statistics->entries;
+
+ return NGX_OK;
+}
+
+static void ngx_statistics_module_exit_process(ngx_cycle_t *cycle)
+{
+ ngx_shm_free(&shm);
+ ngx_statistics = NULL;
+}
+
+static void ngx_statistics_module_exit(ngx_cycle_t *cycle)
+{
+ ngx_statistics_module_exit_process(cycle);
+}
+
+
+static ngx_core_module_t ngx_statistics_module_ctx = {
+ ngx_string("statistics"),
+ NULL,
+ NULL
+};
+
+ngx_module_t ngx_statistics_module = {
+ NGX_MODULE_V1,
+ &ngx_statistics_module_ctx, /* module context */
+ NULL, /* module directives */
+ NGX_CORE_MODULE, /* module type */
+ NULL, /* init master */
+ ngx_statistics_module_init, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ ngx_statistics_module_exit_process, /* exit process */
+ ngx_statistics_module_exit, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
diff -uNr 0.7.61/src/core/ngx_statistics.h trunk/src/core/ngx_statistics.h
--- 0.7.61/src/core/ngx_statistics.h 1970-01-01 01:00:00.000000000 +0100
+++ trunk/src/core/ngx_statistics.h 2009-10-09 09:53:25.000000000 +0200
@@ -0,0 +1,61 @@
+#ifndef _NGX_STATISTICS_H_INCLUDED_
+#define _NGX_STATISTICS_H_INCLUDED_
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+/* --- Macros --- */
+#define NGX_STAT_KEY_INVALID ((ngx_stat_key_t) -1)
+
+
+/* --- Types --- */
+typedef ngx_int_t ngx_stat_key_t;
+typedef size_t ngx_stat_iter_t;
+
+typedef enum {
+ ngx_statistics_invalid_type = 0,
+ ngx_statistics_int,
+ ngx_statistics_str
+} ngx_statistics_type_t;
+
+typedef enum {
+ ngx_statistics_invalid_histo = 0,
+ ngx_statistics_linear,
+ ngx_statistics_exponential
+} ngx_statistics_histo_t;
+
+typedef struct {
+ ngx_str_t label;
+ ngx_str_t name;
+ ngx_str_t unit;
+ float scale;
+ int num_decimals;
+ ngx_int_t min;
+ ngx_int_t max;
+ ngx_int_t num_buckets;
+ ngx_statistics_histo_t histo;
+} ngx_statistics_descr_t;
+
+
+/* --- Functions --- */
+// Creators
+ngx_stat_key_t ngx_statistics_create_int(const ngx_statistics_descr_t *descr,
ngx_int_t initial);
+ngx_stat_key_t ngx_statistics_create_str(const ngx_statistics_descr_t *descr,
ngx_int_t max_size, ngx_str_t *initial);
+
+// Accessors
+ngx_int_t ngx_statistics_get_int(ngx_stat_key_t key, ngx_int_t *value);
+
+// Mutators
+void ngx_statistics_add_int(ngx_stat_key_t key, ngx_int_t delta);
+void ngx_statistics_set_int(ngx_stat_key_t key, ngx_int_t value);
+void ngx_statistics_set_str(ngx_stat_key_t key, ngx_str_t *value);
+
+// Iterators
+ngx_statistics_type_t ngx_statistics_entry(ngx_stat_iter_t it, const
ngx_statistics_descr_t **descr, void **value);
+ngx_stat_iter_t ngx_statistics_iter(void);
+ngx_stat_iter_t ngx_statistics_next(ngx_stat_iter_t it);
+ngx_int_t ngx_statistics_valid(ngx_stat_iter_t it);
+
+ngx_int_t ngx_statistics_bucket_lower(const ngx_statistics_descr_t *descr,
ngx_int_t bucket);
+
+#endif /* _NGX_STATISTICS_H_INCLUDED_ */
diff -uNr 0.7.61/src/core/ngx_string.c trunk/src/core/ngx_string.c
--- 0.7.61/src/core/ngx_string.c 2009-10-09 09:53:16.000000000 +0200
+++ trunk/src/core/ngx_string.c 2009-10-09 09:53:25.000000000 +0200
@@ -201,8 +201,13 @@
case '.':
fmt++;
- while (*fmt >= '0' && *fmt <= '9') { - frac_width = frac_width * 10 + *fmt++ - '0'; + if (*fmt == '*') { + frac_width = va_arg(args, size_t); + fmt++; + } else { + while (*fmt >= '0' && *fmt <= '9') { + frac_width = frac_width * 10 + *fmt++ - '0'; + } }
break; diff -uNr 0.7.61/src/core/ngx_times.c trunk/src/core/ngx_times.c --- 0.7.61/src/core/ngx_times.c 2009-10-09 09:53:16.000000000 +0200 +++ trunk/src/core/ngx_times.c 2009-10-09 09:53:25.000000000 +0200 @@ -30,7 +30,7 @@
static ngx_time_t cached_time[NGX_TIME_SLOTS]; static u_char cached_err_log_time[NGX_TIME_SLOTS] - [sizeof("1970/09/28 12:00:00")]; + [sizeof("1970/09/28 12:00:00.000")]; static u_char cached_http_time[NGX_TIME_SLOTS] [sizeof("Mon, 28 Sep 1970 06:00:00 GMT")]; static u_char cached_http_log_time[NGX_TIME_SLOTS] @@ -44,7 +44,7 @@ void ngx_time_init(void) { - ngx_cached_err_log_time.len = sizeof("1970/09/28 12:00:00") - 1; + ngx_cached_err_log_time.len = sizeof("1970/09/28 12:00:00.000") - 1; ngx_cached_http_time.len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1; ngx_cached_http_log_time.len = sizeof("28/Sep/1970:12:00:00 +0600") - 1;
@@ -124,10 +124,10 @@
p1 = &cached_err_log_time[slot][0];
- (void) ngx_sprintf(p1, "%4d/%02d/%02d %02d:%02d:%02d", + (void) ngx_sprintf(p1, "%4d/%02d/%02d %02d:%02d:%02d.%03d", tm.ngx_tm_year, tm.ngx_tm_mon, tm.ngx_tm_mday, tm.ngx_tm_hour, - tm.ngx_tm_min, tm.ngx_tm_sec); + tm.ngx_tm_min, tm.ngx_tm_sec, msec);
p2 = &cached_http_log_time[slot][0]; diff -uNr 0.7.61/src/event/ngx_event_accept.c trunk/src/event/ngx_event_accept.c --- 0.7.61/src/event/ngx_event_accept.c 2009-10-09 09:53:16.000000000 +0200 +++ trunk/src/event/ngx_event_accept.c 2009-10-09 09:53:24.000000000 +0200 @@ -77,6 +77,9 @@ #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1); #endif +#if (NGX_STATISTICS) + (void) ngx_statistics_add_int(ngx_stat_accepted_key, 1); +#endif
ngx_accept_disabled = ngx_cycle->connection_n / 8 - ngx_cycle->free_connection_n; @@ -95,6 +98,9 @@ #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_active, 1); #endif +#if (NGX_STATISTICS) + (void) ngx_statistics_add_int(ngx_stat_active_key, 1); +#endif
c->pool = ngx_create_pool(ls->pool_size, ev->log); if (c->pool == NULL) { @@ -190,6 +196,9 @@ #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_handled, 1); #endif +#if (NGX_STATISTICS) + (void) ngx_statistics_add_int(ngx_stat_handled_key, 1); +#endif
#if (NGX_THREADS) rev->lock = &c->lock; @@ -381,6 +390,9 @@ #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_active, -1); #endif +#if (NGX_STATISTICS) + (void) ngx_statistics_add_int(ngx_stat_active_key, 1); +#endif }
diff -uNr 0.7.61/src/event/ngx_event.c trunk/src/event/ngx_event.c --- 0.7.61/src/event/ngx_event.c 2009-10-09 09:53:16.000000000 +0200 +++ trunk/src/event/ngx_event.c 2009-10-09 09:53:24.000000000 +0200 @@ -72,6 +72,21 @@ ngx_atomic_t ngx_stat_writing0; ngx_atomic_t *ngx_stat_writing = &ngx_stat_writing0;
+ngx_atomic_t ngx_stat_range0[15]; +ngx_atomic_t *ngx_stat_range = ngx_stat_range0; +ngx_atomic_t ngx_stat_time0[15]; +ngx_atomic_t *ngx_stat_time = ngx_stat_time0; +ngx_atomic_t ngx_stat_upstream0; +ngx_atomic_t *ngx_stat_upstream = &ngx_stat_upstream0; +ngx_atomic_t ngx_stat_cache0; +ngx_atomic_t *ngx_stat_cache = &ngx_stat_cache0; + +#endif + +#if (NGX_STATISTICS) +ngx_stat_key_t ngx_stat_accepted_key = NGX_STAT_KEY_INVALID; +ngx_stat_key_t ngx_stat_active_key = NGX_STAT_KEY_INVALID; +ngx_stat_key_t ngx_stat_handled_key = NGX_STAT_KEY_INVALID; #endif
@@ -501,7 +516,11 @@ + cl /* ngx_stat_requests */ + cl /* ngx_stat_active */ + cl /* ngx_stat_reading */ - + cl; /* ngx_stat_writing */ + + cl /* ngx_stat_writing */ + + 15 * cl /* ngx_stat_range */ + + 15 * cl /* ngx_stat_time */ + + cl /* ngx_stat_upstream */ + + cl; /* ngx_stat_cache */
#endif
@@ -534,9 +553,42 @@ ngx_stat_active = (ngx_atomic_t *) (shared + 5 * cl); ngx_stat_reading = (ngx_atomic_t *) (shared + 6 * cl); ngx_stat_writing = (ngx_atomic_t *) (shared + 7 * cl); + ngx_stat_range = (ngx_atomic_t *) (shared + 8 * cl); /* 15 */ + ngx_stat_time = (ngx_atomic_t *) (shared + 23 * cl); /* 15 */ + ngx_stat_upstream = (ngx_atomic_t *) (shared + 38 * cl); + ngx_stat_cache = (ngx_atomic_t *) (shared + 39 * cl);
#endif
+#if (NGX_STATISTICS) + { + static const ngx_statistics_descr_t ACCEPTED = { + ngx_string("Event-Accepted"), + ngx_string("Accepted Connections"), + ngx_string("connections"), + 1.0f, 0, + 0, 0, 1, ngx_statistics_invalid_histo }; + + static const ngx_statistics_descr_t ACTIVE = { + ngx_string("Event-Active"), + ngx_string("Active Connections"), + ngx_string("connections"), + 1.0f, 0, + 0, 0, 1, ngx_statistics_invalid_histo }; + + static const ngx_statistics_descr_t HANDLED = { + ngx_string("Event-Handled"), + ngx_string("Handled Connections"), + ngx_string("connections"), + 1.0f, 0, + 0, 0, 1, ngx_statistics_invalid_histo }; + + ngx_stat_accepted_key = ngx_statistics_create_int(&ACCEPTED, 0); + ngx_stat_active_key = ngx_statistics_create_int(&ACTIVE, 0); + ngx_stat_handled_key = ngx_statistics_create_int(&HANDLED, 0); + } +#endif + (void) ngx_atomic_cmp_set(ngx_connection_counter, 0, 1);
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, diff -uNr 0.7.61/src/event/ngx_event.h trunk/src/event/ngx_event.h --- 0.7.61/src/event/ngx_event.h 2009-10-09 09:53:16.000000000 +0200 +++ trunk/src/event/ngx_event.h 2009-10-09 09:53:24.000000000 +0200 @@ -10,6 +10,7 @@
#include <ngx_config.h> #include <ngx_core.h> +#include <ngx_statistics.h>
#define NGX_INVALID_INDEX 0xd0d0d0d0 @@ -486,6 +487,17 @@ extern ngx_atomic_t *ngx_stat_reading; extern ngx_atomic_t *ngx_stat_writing;
+extern ngx_atomic_t *ngx_stat_range; +extern ngx_atomic_t *ngx_stat_time; +extern ngx_atomic_t *ngx_stat_upstream; +extern ngx_atomic_t *ngx_stat_cache; + +#endif + +#if (NGX_STATISTICS) +extern ngx_stat_key_t ngx_stat_accepted_key; +extern ngx_stat_key_t ngx_stat_active_key; +extern ngx_stat_key_t ngx_stat_handled_key; #endif
diff -uNr 0.7.61/src/http/modules/ngx_http_dav_module.c
trunk/src/http/modules/ngx_http_dav_module.c
--- 0.7.61/src/http/modules/ngx_http_dav_module.c 2009-10-09 09:53:15.000000000
+0200
+++ trunk/src/http/modules/ngx_http_dav_module.c 2009-10-09 09:53:24.000000000
+0200
@@ -399,6 +399,11 @@
tree.data = NULL;
tree.alloc = 0;
tree.log = r->connection->log;
+ tree.depth = 0;
+#if (NGX_CAN_HAZ_THREADS)
+ tree.thread_depth = 0;
+ tree.pool = NULL;
+#endif
/* TODO: 207 */
@@ -766,6 +771,11 @@ tree.data = © tree.alloc = 0; tree.log = r->connection->log; + tree.depth = 0; +#if (NGX_CAN_HAZ_THREADS) + tree.thread_depth = 0; + tree.pool = NULL; +#endif
if (ngx_walk_tree(&tree, &path) == NGX_OK) {
diff -uNr 0.7.61/src/http/modules/ngx_http_proxy_module.c
trunk/src/http/modules/ngx_http_proxy_module.c
--- 0.7.61/src/http/modules/ngx_http_proxy_module.c 2009-10-09
09:53:15.000000000 +0200
+++ trunk/src/http/modules/ngx_http_proxy_module.c 2009-10-09 09:53:24.000000000
+0200
@@ -781,6 +781,8 @@
ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+ /* XXX we do not want to hash on the root (uncommented for now) */ +/* key = ngx_array_push(&r->cache->keys); if (key == NULL) { return NGX_ERROR; @@ -796,6 +798,7 @@ }
*key = ctx->vars.key_start; +*/
key = ngx_array_push(&r->cache->keys);
if (key == NULL) {
@@ -984,7 +987,8 @@
if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash,
header[i].lowcase_key, header[i].key.len))
{
- continue;
+ if (u->cacheable || !(header[i].key.len == 5 &&
ngx_strncmp(header[i].lowcase_key, "range", 5) == 0))
+ continue;
}
len += header[i].key.len + sizeof(": ") - 1
@@ -1102,7 +1106,8 @@
if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash,
header[i].lowcase_key, header[i].key.len))
{
- continue;
+ if (u->cacheable || !(header[i].key.len == 5 &&
ngx_strncmp(header[i].lowcase_key, "range", 5) == 0))
+ continue;
}
b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
diff -uNr 0.7.61/src/http/modules/ngx_http_range_filter_module.c
trunk/src/http/modules/ngx_http_range_filter_module.c
--- 0.7.61/src/http/modules/ngx_http_range_filter_module.c 2009-10-09
09:53:15.000000000 +0200
+++ trunk/src/http/modules/ngx_http_range_filter_module.c 2009-10-09
09:53:24.000000000 +0200
@@ -58,6 +58,7 @@
} ngx_http_range_filter_ctx_t;
+static ngx_int_t ngx_http_range_filter_module_init(ngx_cycle_t *cycle); ngx_int_t ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx); static ngx_int_t ngx_http_range_singlepart_header(ngx_http_request_t *r, @@ -128,7 +129,7 @@ NULL, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ - NULL, /* init module */ + ngx_http_range_filter_module_init, /* init module */ NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ @@ -141,6 +142,28 @@ static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
+#if (NGX_STATISTICS) +ngx_stat_key_t ngx_stat_http_range_start_key = NGX_STAT_KEY_INVALID; +#endif + + +static ngx_int_t +ngx_http_range_filter_module_init(ngx_cycle_t *cycle) +{ +#if (NGX_STATISTICS) + static const ngx_statistics_descr_t START = { + ngx_string("Http-Range-Start"), + ngx_string("HTTP Range Start"), + ngx_string("bytes"), + 1.0f, 0, + -131071, 15*131072-131071, 15, ngx_statistics_linear }; + + ngx_stat_http_range_start_key = ngx_statistics_create_int(&START, 0); +#endif + + return NGX_OK; +} +
static ngx_int_t ngx_http_range_header_filter(ngx_http_request_t *r) @@ -201,6 +224,20 @@ r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; r->headers_out.status_line.len = 0;
+#if (NGX_STAT_STUB)
+ /* range statistics in 128k blocks */
+ ngx_uint_t start = ((ngx_http_range_t *) ctx->ranges.elts)->start;
+ ngx_uint_t range_category = start == 0 ? 0 : (start >> 17) + 1;
+ if (range_category > 14) {
+ range_category = 14;
+ }
+ ngx_atomic_t *stat = ngx_stat_range + range_category;
+ (void) ngx_atomic_fetch_add(stat, 1);
+#endif
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_http_range_start_key,
((ngx_http_range_t *) ctx->ranges.elts)->start);
+#endif
+
if (ctx->ranges.nelts == 1) {
return ngx_http_range_singlepart_header(r, ctx);
}
diff -uNr 0.7.61/src/http/modules/ngx_http_statistics_module.c
trunk/src/http/modules/ngx_http_statistics_module.c
--- 0.7.61/src/http/modules/ngx_http_statistics_module.c 1970-01-01
01:00:00.000000000 +0100
+++ trunk/src/http/modules/ngx_http_statistics_module.c 2009-10-09
09:53:24.000000000 +0200
@@ -0,0 +1,315 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+static char *ngx_http_set_statistics(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+
+static ngx_command_t ngx_http_statistics_commands[] = {
+
+ { ngx_string("statistics"),
+ NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_http_set_statistics,
+ 0,
+ 0,
+ NULL },
+
+ ngx_null_command
+};
+
+
+
+static ngx_http_module_t ngx_http_statistics_module_ctx = {
+ NULL, /* preconfiguration */
+ NULL, /* postconfiguration */
+
+ NULL, /* create main configuration */
+ NULL, /* init main configuration */
+
+ NULL, /* create server configuration */
+ NULL, /* merge server configuration */
+
+ NULL, /* create location configuration */
+ NULL /* merge location configuration */
+};
+
+
+ngx_module_t ngx_http_statistics_module = {
+ NGX_MODULE_V1,
+ &ngx_http_statistics_module_ctx, /* module context */
+ ngx_http_statistics_commands, /* module directives */
+ NGX_HTTP_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_buf_t* ngx_http_statistics_html_handler(ngx_http_request_t *r)
+{
+ static ngx_str_t HEADER = ngx_string(
+ "<html>\r\n"
+ "\t<head>\r\n"
+ "\t\t<title>Nginx Statistics</title>\r\n"
+ "\t\t<style>\r\n"
+ "\t\t\t.int { text-align: right; }\r\n"
+ "\t\t\tTH { text-align: left; }\r\n"
+ "\t\t\tTABLE.histogram { width: 100%; }\r\n"
+ "\t\t</style>\r\n"
+ "\t</head>\r\n"
+ "\t<body>\r\n"
+ "\t\t<h1>Nginx Statistics</h1>\r\n"
+ "\t\t<table class=\"stats\" border=\"1\" cellspacing=\"0\">\r\n");
+
+ static ngx_str_t FOOTER = ngx_string(
+ "\t\t</table>\r\n"
+ "\t</body>\r\n"
+ "</html>\r\n");
+
+ ngx_buf_t *b;
+ size_t size = HEADER.len + FOOTER.len;
+ ngx_stat_iter_t it;
+
+ for (it = ngx_statistics_iter(); ngx_statistics_valid(it); it =
ngx_statistics_next(it)) {
+ const ngx_statistics_descr_t *descr;
+ void *value;
+
+ switch (ngx_statistics_entry(it, &descr, &value)) {
+ case ngx_statistics_int:
+ size += 27 + 27 + (160 + NGX_ATOMIC_T_LEN * 3) * descr->num_buckets + 11;
+ break;
+
+ case ngx_statistics_str:
+ size += 13 + ((ngx_str_t*) value)->len;
+ break;
+
+ default:
+ break;
+ }
+
+ size += 11 + descr->name.len + 8 + 22 + descr->unit.len + 12;
+ }
+
+ b = ngx_create_temp_buf(r->pool, size);
+
+ if (b == NULL) return NULL;
+
+ b->last = ngx_sprintf(b->last, "%V", &HEADER);
+
+ for (it = ngx_statistics_iter(); ngx_statistics_valid(it); it =
ngx_statistics_next(it)) {
+ const ngx_statistics_descr_t *descr;
+ void *value;
+ ngx_int_t i;
+ ngx_statistics_type_t type = ngx_statistics_entry(it, &descr, &value);
+
+ b->last = ngx_sprintf(b->last, "\t\t\t<tr><th>%V</th><td", &descr->name);
+
+ switch (type) {
+ case ngx_statistics_int:
+ if (descr->histo != ngx_statistics_invalid_histo) {
+ ngx_int_t sum = 0;
+
+ b->last = ngx_sprintf(b->last, " class=\"histo\" width=\"50%%\">");
+
+ for (i = 0; i < descr->num_buckets; ++i)
+ sum += ((ngx_atomic_uint_t*) value)[i];
+
+ if (sum) {
+ b->last = ngx_sprintf(b->last, "<table class=\"histogram\">\r\n");
+
+ for (i = 0; i < descr->num_buckets; ++i) {
+ b->last = ngx_sprintf(b->last, "\t\t\t\t<tr><th class=\"int\">");
+ if (i + 1 < descr->num_buckets)
+ b->last = ngx_sprintf(b->last, "<%.*f", descr->num_decimals,
descr->scale * ngx_statistics_bucket_lower(descr, i + 1));
+ else
+ b->last = ngx_sprintf(b->last, "More");
+ b->last = ngx_sprintf(b->last, "</th><td width=\"100%%\"><div
style=\"float:left;background:black;width:%i%%\"> </div></td><td
class=\"int\">%i</td></tr>\r\n", 100 * ((ngx_atomic_uint_t*) value)[i] / sum,
((ngx_atomic_uint_t*) value)[i]);
+ }
+
+ b->last = ngx_sprintf(b->last, "\t\t\t</table>");
+ }
+ } else {
+ b->last = ngx_sprintf(b->last, " class=\"int\">%.*f", descr->num_decimals,
descr->scale * *(ngx_atomic_uint_t*) value);
+ }
+
+
+ break;
+
+ case ngx_statistics_str:
+ b->last = ngx_sprintf(b->last, " class=\"str\">%V", (ngx_str_t*) value);
+ break;
+
+ default:
+ break;
+ }
+
+ b->last = ngx_sprintf(b->last, "</td><td class=\"unit\">%V</td></tr>\r\n",
&descr->unit);
+ }
+
+ b->last = ngx_sprintf(b->last, "%V", &FOOTER);
+
+ return b;
+}
+
+
+static ngx_buf_t* ngx_http_statistics_plain_handler(ngx_http_request_t *r)
+{
+ ngx_buf_t *b;
+ size_t size = 0;
+ ngx_stat_iter_t it;
+
+ for (it = ngx_statistics_iter(); ngx_statistics_valid(it); it =
ngx_statistics_next(it)) {
+ const ngx_statistics_descr_t *descr;
+ void *value;
+
+ switch (ngx_statistics_entry(it, &descr, &value)) {
+ case ngx_statistics_int:
+ size += (1 + NGX_ATOMIC_T_LEN + 1 + NGX_ATOMIC_T_LEN + 2) *
descr->num_buckets;
+ break;
+
+ case ngx_statistics_str:
+ size += ((ngx_str_t*) value)->len;
+ break;
+
+ default:
+ break;
+ }
+
+ size += descr->label.len + 2 + 2;
+ }
+
+ b = ngx_create_temp_buf(r->pool, size);
+
+ if (b == NULL) return NULL;
+
+ for (it = ngx_statistics_iter(); ngx_statistics_valid(it); it =
ngx_statistics_next(it)) {
+ const ngx_statistics_descr_t *descr;
+ void *value;
+ ngx_int_t i;
+ ngx_statistics_type_t type = ngx_statistics_entry(it, &descr, &value);
+
+ b->last = ngx_sprintf(b->last, "%V:", &descr->label);
+
+ switch (type) {
+ case ngx_statistics_int:
+ if (descr->histo != ngx_statistics_invalid_histo) {
+ b->last = ngx_sprintf(b->last, "\r\n");
+
+ for (i = 0; i < descr->num_buckets; ++i) {
+ *b->last++ = '\t';
+ if (i > 0)
+ b->last = ngx_sprintf(b->last, "%i", ngx_statistics_bucket_lower(descr,
i));
+ *b->last++ = '-';
+ if (i + 1 < descr->num_buckets)
+ b->last = ngx_sprintf(b->last, "%i", ngx_statistics_bucket_lower(descr, i
+ 1) - 1);
+ b->last = ngx_sprintf(b->last, "=%i\r\n", ((ngx_atomic_uint_t*)
value)[i]);
+ }
+ } else {
+ b->last = ngx_sprintf(b->last, " %i\r\n", *(ngx_atomic_uint_t*) value);
+ }
+
+
+ break;
+
+ case ngx_statistics_str:
+ b->last = ngx_sprintf(b->last, " %V\r\n", (ngx_str_t*) value);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return b;
+}
+
+
+static ngx_int_t ngx_http_statistics_handler(ngx_http_request_t *r)
+{
+ ngx_int_t rc;
+ ngx_buf_t *b;
+ ngx_chain_t out;
+ ngx_str_t content_type = ngx_string("text/plain");
+ ngx_buf_t* (*handler)(ngx_http_request_t*) =
ngx_http_statistics_plain_handler;
+
+ if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
+ return NGX_HTTP_NOT_ALLOWED;
+ }
+
+ rc = ngx_http_discard_request_body(r);
+
+ if (rc != NGX_OK) {
+ return rc;
+ }
+
+ // XXX: Handle Accept in addition to ?type=
+ if (r->args.len > sizeof("type=") - 1 && !ngx_memcmp(r->args.data, "type=",
sizeof("type=") - 1)) {
+ ngx_str_t TEXT_PLAIN = ngx_string("text/plain");
+ ngx_str_t TEXT_HTML = ngx_string("text/html");
+
+ if (r->args.len - (sizeof("type=") - 1) == TEXT_PLAIN.len &&
!ngx_memcmp(r->args.data + (sizeof("type=") - 1), TEXT_PLAIN.data,
TEXT_PLAIN.len)) {
+ content_type = TEXT_PLAIN;
+ handler = ngx_http_statistics_plain_handler;
+ } else if (r->args.len - (sizeof("type=") - 1) == TEXT_HTML.len &&
!ngx_memcmp(r->args.data + (sizeof("type=") - 1), TEXT_HTML.data,
TEXT_HTML.len)) {
+ content_type = TEXT_HTML;
+ handler = ngx_http_statistics_html_handler;
+ }
+ }
+
+ r->headers_out.content_type = content_type;
+
+ if (r->method == NGX_HTTP_HEAD) {
+ r->headers_out.status = NGX_HTTP_OK;
+
+ rc = ngx_http_send_header(r);
+
+ if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+ return rc;
+ }
+ }
+
+ b = handler(r);
+
+ if (b == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ out.buf = b;
+ out.next = NULL;
+
+ r->headers_out.status = NGX_HTTP_OK;
+ r->headers_out.content_length_n = b->last - b->pos;
+
+ b->last_buf = 1;
+
+ rc = ngx_http_send_header(r);
+
+ if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+ return rc;
+ }
+
+ return ngx_http_output_filter(r, &out);
+}
+
+
+static char *ngx_http_set_statistics(ngx_conf_t *cf, ngx_command_t *cmd, void
*conf)
+{
+ ngx_http_core_loc_conf_t *clcf;
+
+ clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
+ clcf->handler = ngx_http_statistics_handler;
+
+ return NGX_CONF_OK;
+}
diff -uNr 0.7.61/src/http/modules/ngx_http_stub_status_module.c
trunk/src/http/modules/ngx_http_stub_status_module.c
--- 0.7.61/src/http/modules/ngx_http_stub_status_module.c 2009-10-09
09:53:15.000000000 +0200
+++ trunk/src/http/modules/ngx_http_stub_status_module.c 2009-10-09
09:53:24.000000000 +0200
@@ -60,7 +60,7 @@
static ngx_int_t ngx_http_status_handler(ngx_http_request_t *r)
{
size_t size;
- ngx_int_t rc;
+ ngx_int_t rc, i;
ngx_buf_t *b;
ngx_chain_t out;
ngx_atomic_int_t ap, hn, ac, rq, rd, wr;
@@ -91,7 +91,10 @@
size = sizeof("Active connections: \n") + NGX_ATOMIC_T_LEN
+ sizeof("server accepts handled requests\n") - 1
+ 6 + 3 * NGX_ATOMIC_T_LEN
- + sizeof("Reading: Writing: Waiting: \n") + 3 * NGX_ATOMIC_T_LEN;
+ + sizeof("Reading: Writing: Waiting: \n") + 3 * NGX_ATOMIC_T_LEN
+ + sizeof("Range: \n") + 15 * NGX_ATOMIC_T_LEN + 15
+ + sizeof("Time: \n") + 15 * NGX_ATOMIC_T_LEN + 15
+ + sizeof("Upstream: \n") + 2 * NGX_ATOMIC_T_LEN;
b = ngx_create_temp_buf(r->pool, size); if (b == NULL) { @@ -117,6 +120,15 @@
b->last = ngx_sprintf(b->last, "Reading: %uA Writing: %uA Waiting: %uA \n",
rd, wr, ac - (rd + wr));
+ b->last = ngx_sprintf(b->last, "Range: ");
+ for (i = 0; i < 15; ++i)
+ b->last = ngx_sprintf(b->last, "%uA ", ngx_stat_range[i]);
+ b->last = ngx_sprintf(b->last, "\n");
+ b->last = ngx_sprintf(b->last, "Time: ");
+ for (i = 0; i < 15; ++i)
+ b->last = ngx_sprintf(b->last, "%uA ", ngx_stat_time[i]);
+ b->last = ngx_sprintf(b->last, "\n");
+ b->last = ngx_sprintf(b->last, "Upstream: %uA %uA \n", *ngx_stat_upstream,
*ngx_stat_cache);
r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = b->last - b->pos; diff -uNr 0.7.61/src/http/ngx_http_cache.h trunk/src/http/ngx_http_cache.h --- 0.7.61/src/http/ngx_http_cache.h 2009-10-09 09:53:15.000000000 +0200 +++ trunk/src/http/ngx_http_cache.h 2009-10-09 09:53:24.000000000 +0200 @@ -16,7 +16,7 @@ #define NGX_HTTP_CACHE_STALE 1 #define NGX_HTTP_CACHE_UPDATING 2
-#define NGX_HTTP_CACHE_KEY_LEN 16 +#define NGX_HTTP_CACHE_MAX_KEY_LEN 20
typedef struct { @@ -29,7 +29,7 @@ ngx_rbtree_node_t node; ngx_queue_t queue;
- u_char key[NGX_HTTP_CACHE_KEY_LEN + u_char key[NGX_HTTP_CACHE_MAX_KEY_LEN - sizeof(ngx_rbtree_key_t)];
unsigned count:20; @@ -52,7 +52,7 @@ ngx_file_t file; ngx_array_t keys; uint32_t crc32; - u_char key[NGX_HTTP_CACHE_KEY_LEN]; + u_char key[NGX_HTTP_CACHE_MAX_KEY_LEN];
ngx_file_uniq_t uniq; time_t valid_sec; @@ -98,12 +98,20 @@ } ngx_http_file_cache_sh_t;
+typedef enum { + ngx_http_file_cache_hash_md5, + ngx_http_file_cache_hash_sha1, +} ngx_http_file_cache_hash_t; + + struct ngx_http_file_cache_s { ngx_http_file_cache_sh_t *sh; ngx_slab_pool_t *shpool;
ngx_path_t *path;
+ ngx_http_file_cache_hash_t hash; + off_t max_size; size_t bsize;
diff -uNr 0.7.61/src/http/ngx_http_core_module.c
trunk/src/http/ngx_http_core_module.c
--- 0.7.61/src/http/ngx_http_core_module.c 2009-10-09 09:53:15.000000000 +0200
+++ trunk/src/http/ngx_http_core_module.c 2009-10-09 09:53:24.000000000 +0200
@@ -20,6 +20,8 @@
#define NGX_HTTP_REQUEST_BODY_FILE_CLEAN 2
+static ngx_int_t ngx_http_core_module_init(ngx_cycle_t *cycle); + static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r); static ngx_int_t ngx_http_core_find_static_location(ngx_http_request_t *r, ngx_http_location_tree_node_t *node); @@ -153,6 +155,16 @@
#endif
+#if (NGX_STATISTICS) +ngx_stat_key_t ngx_stat_http_reading_key = NGX_STAT_KEY_INVALID; +ngx_stat_key_t ngx_stat_http_writing_key = NGX_STAT_KEY_INVALID; +ngx_stat_key_t ngx_stat_http_requests_key = NGX_STAT_KEY_INVALID; +ngx_stat_key_t ngx_stat_http_request_time_key = NGX_STAT_KEY_INVALID; +ngx_stat_key_t ngx_stat_http_active_requests_key = NGX_STAT_KEY_INVALID; +ngx_stat_key_t ngx_stat_http_writing_file_key = NGX_STAT_KEY_INVALID; +ngx_stat_key_t ngx_stat_http_unavailable_key = NGX_STAT_KEY_INVALID; +#endif +
static ngx_command_t ngx_http_core_commands[] = {
@@ -670,6 +682,17 @@
#endif
+#if (NGX_STATISTICS) + + { ngx_string("max_active_requests"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, max_active_requests), + NULL }, + +#endif + ngx_null_command };
@@ -695,7 +718,7 @@ ngx_http_core_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ - NULL, /* init module */ + ngx_http_core_module_init, /* init module */ NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ @@ -708,6 +731,73 @@ ngx_str_t ngx_http_core_get_method = { 3, (u_char *) "GET " };
+static ngx_int_t
+ngx_http_core_module_init(ngx_cycle_t *cycle)
+{
+#if (NGX_STATISTICS)
+ static const ngx_statistics_descr_t READING = {
+ ngx_string("Http-Requests-Reading"),
+ ngx_string("HTTP Requests Currently Reading"),
+ ngx_string("requests"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+ static const ngx_statistics_descr_t WRITING = {
+ ngx_string("Http-Requests-Writing"),
+ ngx_string("HTTP Requests Currently Writing"),
+ ngx_string("requests"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+ static const ngx_statistics_descr_t REQUESTS = {
+ ngx_string("Http-Requests-Total"),
+ ngx_string("Processed HTTP Requests Since Start"),
+ ngx_string("requests"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+ static const ngx_statistics_descr_t REQUEST_TIME = {
+ ngx_string("Http-Time-Request"),
+ ngx_string("Total Time of HTTP Request"),
+ ngx_string("s"),
+ 0.001f, 3,
+ 0, 0, 15, ngx_statistics_exponential };
+
+ static const ngx_statistics_descr_t ACTIVE_REQUESTS = {
+ ngx_string("Http-Requests-Active"),
+ ngx_string("HTTP Requests Currently Active"),
+ ngx_string("requests"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+ static const ngx_statistics_descr_t WRITING_FILE = {
+ ngx_string("Http-Requests-Writing-File"),
+ ngx_string("HTTP Requests Currently Writing File"),
+ ngx_string("requests"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+ static const ngx_statistics_descr_t UNAVAILABLE = {
+ ngx_string("Http-Requests-Unavailable"),
+ ngx_string("HTTP Requests Unavailable Since Start"),
+ ngx_string("requests"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+
+ ngx_stat_http_reading_key = ngx_statistics_create_int(&READING, 0);
+ ngx_stat_http_writing_key = ngx_statistics_create_int(&WRITING, 0);
+ ngx_stat_http_requests_key = ngx_statistics_create_int(&REQUESTS, 0);
+ ngx_stat_http_request_time_key = ngx_statistics_create_int(&REQUEST_TIME,
0);
+ ngx_stat_http_active_requests_key =
ngx_statistics_create_int(&ACTIVE_REQUESTS, 0);
+ ngx_stat_http_writing_file_key = ngx_statistics_create_int(&WRITING_FILE,
0);
+ ngx_stat_http_unavailable_key = ngx_statistics_create_int(&UNAVAILABLE, 0);
+#endif
+
+ return NGX_OK;
+}
+
+
void
ngx_http_handler(ngx_http_request_t *r)
{
@@ -2956,6 +3046,7 @@
lcf->gzip_disable_msie6 = 3;
#endif
#endif
+ lcf->max_active_requests = NGX_CONF_UNSET_UINT;
return lcf; } @@ -3208,6 +3299,9 @@
#endif
+ ngx_conf_merge_uint_value(conf->max_active_requests, + prev->max_active_requests, NGX_CONF_UNSET_UINT); + return NGX_CONF_OK; }
diff -uNr 0.7.61/src/http/ngx_http_core_module.h
trunk/src/http/ngx_http_core_module.h
--- 0.7.61/src/http/ngx_http_core_module.h 2009-10-09 09:53:15.000000000 +0200
+++ trunk/src/http/ngx_http_core_module.h 2009-10-09 09:53:24.000000000 +0200
@@ -369,6 +369,8 @@
#endif
#endif
+ ngx_uint_t max_active_requests; /* max_active_requests */ + ngx_array_t *error_pages; /* error_page */ ngx_http_try_file_t *try_files; /* try_files */
@@ -472,6 +474,16 @@
extern ngx_str_t ngx_http_core_get_method;
+#if (NGX_STATISTICS) +extern ngx_stat_key_t ngx_stat_http_reading_key; +extern ngx_stat_key_t ngx_stat_http_writing_key; +extern ngx_stat_key_t ngx_stat_http_requests_key; +extern ngx_stat_key_t ngx_stat_http_request_time_key; +extern ngx_stat_key_t ngx_stat_http_active_requests_key; +extern ngx_stat_key_t ngx_stat_http_writing_file_key; +extern ngx_stat_key_t ngx_stat_http_unavailable_key; +#endif +
#define ngx_http_clear_content_length(r) \
\
diff -uNr 0.7.61/src/http/ngx_http_file_cache.c
trunk/src/http/ngx_http_file_cache.c
--- 0.7.61/src/http/ngx_http_file_cache.c 2009-10-09 09:53:15.000000000 +0200
+++ trunk/src/http/ngx_http_file_cache.c 2009-10-09 09:53:24.000000000 +0200
@@ -8,7 +8,9 @@
#include <ngx_core.h>
#include <ngx_http.h>
#include <ngx_md5.h>
+#include <ngx_sha1.h>
+static ngx_uint_t hash_len(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); @@ -37,6 +39,9 @@
static u_char ngx_http_file_cache_key[] = { LF, 'K', 'E', 'Y', ':', ' ' };
+#if (NGX_CAN_HAZ_THREADS) +static ngx_mutex_t *file_cache_mutex = NULL; +#endif
static ngx_int_t ngx_http_file_cache_init(ngx_shm_zone_t *shm_zone, void *data) @@ -110,6 +115,18 @@ return NGX_OK; }
+static ngx_uint_t +hash_len(ngx_http_file_cache_t *cache) { + ngx_http_file_cache_hash_t hash; + hash = cache->hash; + switch (hash) { + case ngx_http_file_cache_hash_md5: + return 16; + case ngx_http_file_cache_hash_sha1: + return 20; + } + return 0; +}
void ngx_http_file_cache_create_key(ngx_http_request_t *r) @@ -117,15 +134,27 @@ size_t len; ngx_str_t *key; ngx_uint_t i; - ngx_md5_t md5; + union { + ngx_md5_t md5; + ngx_sha1_t sha1; + } hasher; ngx_http_cache_t *c; + ngx_http_file_cache_hash_t hash;
c = r->cache; + hash = c->file_cache->hash;
len = 0;
ngx_crc32_init(c->crc32); - ngx_md5_init(&md5); + switch (hash) { + case ngx_http_file_cache_hash_md5: + ngx_md5_init(&hasher.md5); + break; + case ngx_http_file_cache_hash_sha1: + ngx_sha1_init(&hasher.sha1); + break; + }
key = c->keys.elts; for (i = 0; i < c->keys.nelts; i++) { @@ -135,14 +164,28 @@ len += key[i].len;
ngx_crc32_update(&c->crc32, key[i].data, key[i].len); - ngx_md5_update(&md5, key[i].data, key[i].len); + switch (hash) { + case ngx_http_file_cache_hash_md5: + ngx_md5_update(&hasher.md5, key[i].data, key[i].len); + break; + case ngx_http_file_cache_hash_sha1: + ngx_sha1_update(&hasher.sha1, key[i].data, key[i].len); + break; + } }
c->header_start = sizeof(ngx_http_file_cache_header_t) + sizeof(ngx_http_file_cache_key) + len + 1;
ngx_crc32_final(c->crc32); - ngx_md5_final(c->key, &md5); + switch (hash) { + case ngx_http_file_cache_hash_md5: + ngx_md5_final(c->key, &hasher.md5); + break; + case ngx_http_file_cache_hash_sha1: + ngx_sha1_final(c->key, &hasher.sha1); + break; + } }
@@ -219,7 +262,7 @@ path = cache->path;
c->file.name.len = path->name.len + 1 + path->len - + 2 * NGX_HTTP_CACHE_KEY_LEN; + + 2 * hash_len(cache);
c->file.name.data = ngx_pnalloc(r->pool, c->file.name.len + 1); if (c->file.name.data == NULL) { @@ -229,7 +272,7 @@ ngx_memcpy(c->file.name.data, path->name.data, path->name.len);
p = c->file.name.data + path->name.len + 1 + path->len; - p = ngx_hex_dump(p, c->key, NGX_HTTP_CACHE_KEY_LEN); + p = ngx_hex_dump(p, c->key, hash_len(cache)); *p = '\0';
ngx_create_hashed_filename(path, c->file.name.data, c->file.name.len); @@ -426,7 +469,8 @@ 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));
+ hash_len(cache) - sizeof(ngx_rbtree_key_t));
+ ngx_memzero(fcn->key + hash_len(cache) - sizeof(ngx_rbtree_key_t),
NGX_HTTP_CACHE_MAX_KEY_LEN - hash_len(cache));
ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node);
@@ -493,7 +537,7 @@ fcn = (ngx_http_file_cache_node_t *) node;
rc = ngx_memcmp(&key[sizeof(ngx_rbtree_key_t)], fcn->key, - NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); + hash_len(cache) - sizeof(ngx_rbtree_key_t));
if (rc == 0) { return fcn; @@ -535,7 +579,7 @@ cnt = (ngx_http_file_cache_node_t *) temp;
p = (ngx_memcmp(cn->key, cnt->key,
- NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t))
+ NGX_HTTP_CACHE_MAX_KEY_LEN -
sizeof(ngx_rbtree_key_t))
< 0)
? &temp->left : &temp->right;
}
@@ -621,14 +665,33 @@
"http file cache rename: \"%s\" to \"%s\"",
tf->file.name.data, c->file.name.data);
- ext.access = NGX_FILE_OWNER_ACCESS; - ext.path_access = NGX_FILE_OWNER_ACCESS; + ext.access = NGX_FILE_GROUP_ACCESS; + ext.path_access = NGX_FILE_GROUP_ACCESS; ext.time = -1; ext.create_path = 1; ext.delete_file = 1; ext.log_rename_error = 1; ext.log = r->connection->log;
+ /* Dragging in tail material in the nginx cache completely
+ thrashes the buffer cache real quick for large files. So we
+ want to tell the kernel we do not care about anything above
+ 64kb. Ideally we should use whatever number of bytes the
+ originating client actually asked for. However, posix_fadvise()
+ does not cause any remembrance so in order to make sure that
+ kernel is able to throw the data away at the point of our call,
+ we must first sync to make sure it's on disk; otherwise we'd
+ normally never have an effect. It's written in the stars
+ whether or not this synchronous and very-likely-to-take-time
+ call will completely screw up performance and block other
+ independent requests. */
+ fdatasync(tf->file.fd);
+ if (posix_fadvise(tf->file.fd, 64*1024, 0, POSIX_FADV_DONTNEED) != 0) {
+ ngx_log_debug1(NGX_LOG_ERR, r->connection->log, 0,
+ "temporary cache file could not be posix_fadvised() - buffer cache will
churn (file: \"%s\")",
+ tf->file.name.data);
+ }
+
rc = ngx_ext_rename_file(&tf->file.name, &c->file.name, &ext);
if (rc == NGX_OK) {
@@ -643,8 +706,18 @@
uniq = ngx_file_uniq(&fi);
}
}
+ else {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+ "ngx_ext_rename_file \"%s\" to \"%s\" failed",
tf->file.name.data, c->file.name.data);
+ ngx_memset(&fi, 0, sizeof(fi));
+ if (ngx_delete_file(tf->file.name.data) != NGX_OK) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+ ngx_delete_file_n " \"%s\" failed",
tf->file.name.data);
+ }
+ }
- size = (c->length + cache->bsize - 1) / cache->bsize; + /* c->length contains only range size, use fi.st_size instead */ + size = (fi.st_size + cache->bsize - 1) / cache->bsize;
ngx_shmtx_lock(&cache->shpool->mutex);
@@ -654,7 +727,8 @@
size = size - (c->node->length + cache->bsize - 1) / cache->bsize;
- c->node->length = c->length; + /* c->length contains only range size, use fi.st_size instead */ + c->node->length = fi.st_size;
cache->sh->size += size;
@@ -811,7 +885,7 @@ "http file cache forced expire");
path = cache->path; - len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; + len = path->name.len + 1 + path->len + 2 * hash_len(cache);
name = ngx_alloc(len + 1, ngx_cycle->log); if (name == NULL) { @@ -878,13 +952,13 @@ ngx_path_t *path; ngx_queue_t *q; ngx_http_file_cache_node_t *fcn; - u_char key[2 * NGX_HTTP_CACHE_KEY_LEN]; + u_char key[2 * NGX_HTTP_CACHE_MAX_KEY_LEN];
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "http file cache expire");
path = cache->path; - len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; + len = path->name.len + 1 + path->len + hash_len(cache);
name = ngx_alloc(len + 1, ngx_cycle->log); if (name == NULL) { @@ -925,7 +999,7 @@ p = ngx_hex_dump(key, (u_char *) &fcn->node.key, sizeof(ngx_rbtree_key_t));
- len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t); + len = hash_len(cache) - sizeof(ngx_rbtree_key_t); (void) ngx_hex_dump(p, fcn->key, len);
/* @@ -940,7 +1014,7 @@
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); + 2 * hash_len(cache), key, fcn->count);
continue; } @@ -984,7 +1058,7 @@
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); + len = hash_len(cache) - sizeof(ngx_rbtree_key_t); p = ngx_hex_dump(p, fcn->key, len); *p = '\0';
@@ -996,7 +1070,7 @@
ngx_shmtx_unlock(&cache->shpool->mutex);
- len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; + len = path->name.len + 1 + path->len + 2 * hash_len(cache);
ngx_create_hashed_filename(path, name, len);
@@ -1034,6 +1108,14 @@ tree.data = cache; tree.alloc = 0; tree.log = ngx_cycle->log; + tree.depth = 0; +#if (NGX_CAN_HAZ_THREADS) + tree.thread_depth = 2; + tree.pool = NULL; + if (file_cache_mutex == NULL) { + file_cache_mutex = ngx_mutex_init(ngx_cycle->log, 0); + } +#endif
cache->last = ngx_current_msec; cache->files = 0; @@ -1084,6 +1166,12 @@ { ngx_msec_t elapsed;
+#if (NGX_CAN_HAZ_THREADS) + if (file_cache_mutex) { + ngx_mutex_lock_sp(file_cache_mutex); + } +#endif + if (cache->files++ > 100) {
ngx_time_update(0, 0); @@ -1110,6 +1198,12 @@ cache->files = 0; }
+#if (NGX_CAN_HAZ_THREADS) + if (file_cache_mutex) { + ngx_mutex_unlock_sp(file_cache_mutex); + } +#endif + return (ngx_quit || ngx_terminate) ? NGX_ABORT : NGX_OK; }
@@ -1132,6 +1226,9 @@ (void) ngx_http_file_cache_delete_file(ctx, path); }
+ /* per-thread sleep of 3; ideally we should be more intelligent. */ + ngx_msleep(3); + return ngx_http_file_cache_manager_sleep(cache); }
@@ -1148,7 +1245,9 @@ ngx_http_file_cache_t *cache; ngx_http_file_cache_header_t h;
- if (name->len < 2 * NGX_HTTP_CACHE_KEY_LEN) { + cache = ctx->data; + + if (name->len < 2 * hash_len(cache)) { return NGX_ERROR; }
@@ -1199,9 +1298,9 @@ return NGX_ERROR; }
- p = &name->data[name->len - 2 * NGX_HTTP_CACHE_KEY_LEN]; + p = &name->data[name->len - 2 * hash_len(cache)];
- for (i = 0; i < NGX_HTTP_CACHE_KEY_LEN; i++) { + for (i = 0; i < hash_len(cache); i++) { n = ngx_hextoi(p, 2);
if (n == NGX_ERROR) { @@ -1213,8 +1312,6 @@ c.key[i] = (u_char) n; }
- cache = ctx->data; - return ngx_http_file_cache_add(cache, &c); }
@@ -1224,6 +1321,10 @@ { ngx_http_file_cache_node_t *fcn;
+#if (NGX_CAN_HAZ_THREADS) + if (file_cache_mutex) + ngx_mutex_lock_sp(file_cache_mutex); +#endif ngx_shmtx_lock(&cache->shpool->mutex);
fcn = ngx_http_file_cache_lookup(cache, c->key); @@ -1234,13 +1335,20 @@ sizeof(ngx_http_file_cache_node_t)); if (fcn == NULL) { ngx_shmtx_unlock(&cache->shpool->mutex); +#if (NGX_CAN_HAZ_THREADS) + if (file_cache_mutex) { + ngx_mutex_unlock_sp(file_cache_mutex); + } +#endif + 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));
+ hash_len(cache) - sizeof(ngx_rbtree_key_t));
+ ngx_memzero(fcn->key + hash_len(cache) - sizeof(ngx_rbtree_key_t),
NGX_HTTP_CACHE_MAX_KEY_LEN - hash_len(cache));
ngx_rbtree_insert(&cache->sh->rbtree, &fcn->node);
@@ -1266,6 +1374,12 @@
ngx_shmtx_unlock(&cache->shpool->mutex);
+#if (NGX_CAN_HAZ_THREADS) + if (file_cache_mutex) { + ngx_mutex_unlock_sp(file_cache_mutex); + } +#endif + return NGX_OK; }
@@ -1318,6 +1432,7 @@ u_char *last, *p; time_t inactive; ssize_t size; + ngx_http_file_cache_hash_t hash; ngx_str_t s, name, *value; ngx_uint_t i, n; ngx_http_file_cache_t *cache; @@ -1337,6 +1452,7 @@ name.len = 0; size = 0; max_size = NGX_MAX_OFF_T_VALUE; + hash = ngx_http_file_cache_hash_md5;
value = cf->args->elts;
@@ -1446,6 +1562,21 @@ continue; }
+ if (ngx_strncmp(value[i].data, "hash=", 5) == 0) { + + s.len = value[i].len - 5; + s.data = value[i].data + 5; + + if (ngx_strcmp(s.data, "md5") == 0) { + hash = ngx_http_file_cache_hash_md5; + continue; + } + else if (ngx_strcmp(s.data, "sha1") == 0) { + hash = ngx_http_file_cache_hash_sha1; + continue; + } + } + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[i]); return NGX_CONF_ERROR; @@ -1482,6 +1613,7 @@
cache->inactive = inactive; cache->max_size = max_size; + cache->hash = hash;
return NGX_CONF_OK;
}
diff -uNr 0.7.61/src/http/ngx_http_request_body.c
trunk/src/http/ngx_http_request_body.c
--- 0.7.61/src/http/ngx_http_request_body.c 2009-10-09 09:53:15.000000000 +0200
+++ trunk/src/http/ngx_http_request_body.c 2009-10-09 09:53:24.000000000 +0200
@@ -84,7 +84,7 @@
rb->temp_file = tf;
if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
- tf->persistent, tf->clean, tf->access)
+ tf->persistent, tf->clean, tf->access,
tf->prefix)
!= NGX_OK)
{
return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -414,7 +414,13 @@
rb->temp_file = tf;
}
+#if (NGX_STATISTICS) + (void) ngx_statistics_add_int(ngx_stat_http_writing_file_key, 1); +#endif n = ngx_write_chain_to_temp_file(rb->temp_file, body); +#if (NGX_STATISTICS) + (void) ngx_statistics_add_int(ngx_stat_http_writing_file_key, -1); +#endif
/* TODO: n == 0 or not complete and level event */
diff -uNr 0.7.61/src/http/ngx_http_request.c trunk/src/http/ngx_http_request.c --- 0.7.61/src/http/ngx_http_request.c 2009-10-09 09:53:15.000000000 +0200 +++ trunk/src/http/ngx_http_request.c 2009-10-09 09:53:24.000000000 +0200 @@ -9,6 +9,9 @@ #include <ngx_http.h>
+#define NGX_HTTP_REQUEST_TIME_ALWAYS_UPDATE 1 + + static void ngx_http_init_request(ngx_event_t *ev); static void ngx_http_process_request_line(ngx_event_t *rev); static void ngx_http_process_request_headers(ngx_event_t *rev); @@ -200,6 +203,9 @@ #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_reading, 1); #endif +#if (NGX_STATISTICS) + (void) ngx_statistics_add_int(ngx_stat_http_reading_key, 1); +#endif
if (rev->ready) { /* the deferred accept(), rtsig, aio, iocp */ @@ -219,6 +225,9 @@ #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_reading, -1); #endif +#if (NGX_STATISTICS) + (void) ngx_statistics_add_int(ngx_stat_http_reading_key, -1); +#endif ngx_http_close_connection(c); return; } @@ -249,6 +258,9 @@ #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_reading, -1); #endif +#if (NGX_STATISTICS) + (void) ngx_statistics_add_int(ngx_stat_http_reading_key, -1); +#endif
c = rev->data;
@@ -446,6 +458,7 @@ return; }
+ r->main = r;
if (ngx_list_init(&r->headers_out.headers, r->pool, 20, sizeof(ngx_table_elt_t)) @@ -470,11 +483,26 @@ return; }
+#if (NGX_STATISTICS)
+ if (clcf->max_active_requests != NGX_CONF_UNSET_UINT) {
+ ngx_int_t active;
+ if (ngx_statistics_get_int(ngx_stat_http_active_requests_key, &active)
== NGX_OK) {
+ if (active > 0 && (ngx_uint_t) active > clcf->max_active_requests)
{
+ ngx_log_error(NGX_LOG_WARN, c->log, 0, "max_active_requests
reached");
+ (void) ngx_statistics_add_int(ngx_stat_http_unavailable_key,
1);
+ ngx_http_close_request(r, NGX_HTTP_SERVICE_UNAVAILABLE);
+ return;
+ }
+ }
+ }
+#endif
+
c->single_connection = 1;
c->destroyed = 0;
- r->main = r; - +#if (NGX_HTTP_REQUEST_TIME_ALWAYS_UPDATE) + ngx_time_update(0, 0); +#endif tp = ngx_timeofday(); r->start_sec = tp->sec; r->start_msec = tp->msec; @@ -501,6 +529,12 @@ r->stat_reading = 1; (void) ngx_atomic_fetch_add(ngx_stat_requests, 1); #endif +#if (NGX_STATISTICS) + (void) ngx_statistics_add_int(ngx_stat_http_reading_key, 1); + r->stat_reading = 1; + (void) ngx_statistics_add_int(ngx_stat_http_requests_key, 1); + (void) ngx_statistics_add_int(ngx_stat_http_active_requests_key, 1); +#endif
rev->handler(rev); } @@ -1549,6 +1583,12 @@ (void) ngx_atomic_fetch_add(ngx_stat_writing, 1); r->stat_writing = 1; #endif +#if (NGX_STATISTICS) + (void) ngx_statistics_add_int(ngx_stat_http_reading_key, -1); + r->stat_reading = 0; + (void) ngx_statistics_add_int(ngx_stat_http_writing_key, 1); + r->stat_writing = 1; +#endif
c->read->handler = ngx_http_request_handler; c->write->handler = ngx_http_request_handler; @@ -2318,6 +2358,9 @@ #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_reading, 1); #endif +#if (NGX_STATISTICS) + (void) ngx_statistics_add_int(ngx_stat_http_reading_key, 1); +#endif
hc->pipeline = 1; c->log->action = "reading client pipelined request line"; @@ -2548,6 +2591,9 @@ #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_reading, 1); #endif +#if (NGX_STATISTICS) + (void) ngx_statistics_add_int(ngx_stat_http_reading_key, 1); +#endif
c->log->handler = ngx_http_log_error; c->log->action = "reading client request line"; @@ -2783,6 +2829,47 @@ }
#endif
+#if (NGX_STATISTICS)
+ if (r->stat_reading)
+ (void) ngx_statistics_add_int(ngx_stat_http_reading_key, -1);
+
+ if (r->stat_writing)
+ (void) ngx_statistics_add_int(ngx_stat_http_writing_key, -1);
+
+ if (r->stat_reading || r->stat_writing)
+ (void) ngx_statistics_add_int(ngx_stat_http_active_requests_key, -1);
+#endif
+
+#if (NGX_STAT_STUB)
+ ngx_time_t *tp;
+ ngx_uint_t millis;
+ ngx_uint_t category = 0;
+#if (NGX_HTTP_REQUEST_TIME_ALWAYS_UPDATE)
+ ngx_time_update(0, 0);
+#endif
+ tp = ngx_timeofday();
+ millis = (tp->sec - r->start_sec) * 1000 + tp->msec - r->start_msec;
+ {
+ ngx_uint_t p = 1;
+ ngx_uint_t m = 1;
+ while (m * p < millis && category < 14) {
+ ++category;
+ m = m == 1 ? 2 : m == 2 ? 5 : 1;
+ if (m == 1) p *= 10;
+ }
+ }
+ ngx_atomic_t *stat = ngx_stat_time + category;
+ (void) ngx_atomic_fetch_add(stat, 1);
+#endif
+#if (NGX_STATISTICS)
+ {
+#if (NGX_HTTP_REQUEST_TIME_ALWAYS_UPDATE)
+ ngx_time_update(0, 0);
+#endif
+ ngx_time_t *tp = ngx_timeofday();
+ (void) ngx_statistics_add_int(ngx_stat_http_request_time_key, (tp->sec
- r->start_sec) * 1000 + tp->msec - r->start_msec);
+ }
+#endif
if (error && r->headers_out.status == 0) { r->headers_out.status = error; @@ -2862,6 +2949,9 @@ #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_active, -1); #endif +#if (NGX_STATISTICS) + (void) ngx_statistics_add_int(ngx_stat_active_key, -1); +#endif
c->destroyed = 1;
diff -uNr 0.7.61/src/http/ngx_http_request.h trunk/src/http/ngx_http_request.h --- 0.7.61/src/http/ngx_http_request.h 2009-10-09 09:53:15.000000000 +0200 +++ trunk/src/http/ngx_http_request.h 2009-10-09 09:53:24.000000000 +0200 @@ -497,7 +497,7 @@ unsigned filter_need_temporary:1; unsigned allow_ranges:1;
-#if (NGX_STAT_STUB) +#if (NGX_STAT_STUB) || (NGX_STATISTICS) unsigned stat_reading:1; unsigned stat_writing:1; #endif diff -uNr 0.7.61/src/http/ngx_http_upstream.c trunk/src/http/ngx_http_upstream.c --- 0.7.61/src/http/ngx_http_upstream.c 2009-10-09 09:53:15.000000000 +0200 +++ trunk/src/http/ngx_http_upstream.c 2009-10-09 09:53:24.000000000 +0200 @@ -16,6 +16,8 @@ ngx_http_upstream_t *u); #endif
+static ngx_int_t ngx_http_upstream_module_init(ngx_cycle_t *cycle);
+
static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx);
static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t
*r);
static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t
*r);
@@ -130,6 +132,12 @@
static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c);
#endif
+#if (NGX_STATISTICS) +ngx_stat_key_t ngx_stat_http_cached_key = NGX_STAT_KEY_INVALID; +ngx_stat_key_t ngx_stat_http_upstream_key = NGX_STAT_KEY_INVALID; +ngx_stat_key_t ngx_stat_http_active_upstream_key = NGX_STAT_KEY_INVALID; +#endif +
ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
@@ -288,7 +296,7 @@ ngx_http_upstream_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ - NULL, /* init module */ + ngx_http_upstream_module_init, /* init module */ NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ @@ -338,6 +346,40 @@ };
+static ngx_int_t
+ngx_http_upstream_module_init(ngx_cycle_t *cycle)
+{
+#if (NGX_STATISTICS)
+ static const ngx_statistics_descr_t UPSTREAM = {
+ ngx_string("Http-Upstreams-Total"),
+ ngx_string("HTTP Upstream Requests Since Start"),
+ ngx_string("requests"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+ static const ngx_statistics_descr_t ACTIVE_UPSTREAM = {
+ ngx_string("Http-Upstreams-Active"),
+ ngx_string("HTTP Upstream Requests Currently Active"),
+ ngx_string("requests"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+ static const ngx_statistics_descr_t CACHED = {
+ ngx_string("Http-Cached"),
+ ngx_string("HTTP Requests Cached Since Start"),
+ ngx_string("requests"),
+ 1.0f, 0,
+ 0, 0, 1, ngx_statistics_invalid_histo };
+
+ ngx_stat_http_upstream_key = ngx_statistics_create_int(&UPSTREAM, 0);
+ ngx_stat_http_active_upstream_key =
ngx_statistics_create_int(&ACTIVE_UPSTREAM, 0);
+ ngx_stat_http_cached_key = ngx_statistics_create_int(&CACHED, 0);
+#endif
+
+ return NGX_OK;
+}
+
+
void
ngx_http_upstream_init(ngx_http_request_t *r)
{
@@ -567,14 +609,14 @@
/* TODO: add keys */
- ngx_http_file_cache_create_key(r); - u->cacheable = 1;
c->min_uses = u->conf->cache_min_uses; c->body_start = u->conf->buffer_size; c->file_cache = u->conf->cache->data;
+ ngx_http_file_cache_create_key(r); + rc = ngx_http_file_cache_open(r);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -937,6 +979,10 @@ u->state->response_msec = tp->msec - u->state->response_msec; }
+#if (NGX_STATISTICS) + (void) ngx_statistics_add_int(ngx_stat_http_active_upstream_key, 1); +#endif + u->state = ngx_array_push(r->upstream_states); if (u->state == NULL) { ngx_http_upstream_finalize_request(r, u, @@ -1208,6 +1254,17 @@
c->log->action = "sending request to upstream";
+#if (NGX_STAT_STUB)
+ (void) ngx_atomic_fetch_add(ngx_stat_upstream, 1);
+ if (u->cacheable)
+ (void) ngx_atomic_fetch_add(ngx_stat_cache, 1);
+#endif
+#if (NGX_STATISTICS)
+ (void) ngx_statistics_add_int(ngx_stat_http_upstream_key, 1);
+ if (u->cacheable)
+ (void) ngx_statistics_add_int(ngx_stat_http_cached_key, 1);
+#endif
+
rc = ngx_output_chain(&u->output, u->request_sent ? NULL :
u->request_bufs);
u->request_sent = 1; @@ -1858,6 +1915,9 @@ ngx_connection_t *c; ngx_http_core_loc_conf_t *clcf;
+ if (u->headers_in.content_length_n != -1) + r->allow_ranges = 1; + rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->post_action) {
@@ -2033,6 +2093,7 @@
p->temp_file->file.log = c->log;
p->temp_file->path = u->conf->temp_path;
p->temp_file->pool = r->pool;
+ p->temp_file->prefix = (r->cache->key[0] << 24 | r->cache->key[1] << 16 |
r->cache->key[2] << 8 | r->cache->key[3]);
if (p->cacheable) { p->temp_file->persistent = 1; @@ -2555,7 +2616,7 @@ tf->persistent = 1;
if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
- tf->persistent, tf->clean, tf->access)
+ tf->persistent, tf->clean, tf->access,
tf->prefix)
!= NGX_OK)
{
return;
@@ -2754,6 +2815,10 @@
{
ngx_time_t *tp;
+#if (NGX_STATISTICS) + (void) ngx_statistics_add_int(ngx_stat_http_active_upstream_key, -1); +#endif + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "finalize http upstream request: %i", rc);
@@ -3812,7 +3877,7 @@ return rv; }
- if (uscf->servers == NULL) { + if ((uscf->flags & NGX_HTTP_UPSTREAM_CREATE) && uscf->servers == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "no servers are inside upstream"); return NGX_CONF_ERROR; diff -uNr 0.7.61/src/http/ngx_http_upstream.h trunk/src/http/ngx_http_upstream.h --- 0.7.61/src/http/ngx_http_upstream.h 2009-10-09 09:53:15.000000000 +0200 +++ trunk/src/http/ngx_http_upstream.h 2009-10-09 09:53:24.000000000 +0200 @@ -332,6 +332,10 @@ extern ngx_module_t ngx_http_upstream_module; extern ngx_conf_bitmask_t ngx_http_upstream_cache_method_mask[];
+#if (NGX_STATISTICS) +extern ngx_stat_key_t ngx_stat_http_cached_key; +extern ngx_stat_key_t ngx_stat_http_upstream_key; +#endif
#endif /* _NGX_HTTP_UPSTREAM_H_INCLUDED_ */ diff -uNr 0.7.61/src/mail/ngx_mail_handler.c trunk/src/mail/ngx_mail_handler.c --- 0.7.61/src/mail/ngx_mail_handler.c 2009-10-09 09:53:16.000000000 +0200 +++ trunk/src/mail/ngx_mail_handler.c 2009-10-09 09:53:25.000000000 +0200 @@ -712,6 +712,9 @@ #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_active, -1); #endif +#if (NGX_STATISTICS) + (void) ngx_statistics_add_int(ngx_stat_active_key, -1); +#endif
c->destroyed = 1;
diff -uNr 0.7.61/src/os/unix/ngx_files.c trunk/src/os/unix/ngx_files.c --- 0.7.61/src/os/unix/ngx_files.c 2009-10-09 09:53:16.000000000 +0200 +++ trunk/src/os/unix/ngx_files.c 2009-10-09 09:53:25.000000000 +0200 @@ -436,6 +436,23 @@ return (size_t) fs.f_bsize; }
+ngx_int_t +ngx_fs_id(u_char *name, ngx_fsid_t *fs_id) +{ + struct statfs fs; + unsigned int i; + + if(statfs((char *) name, &fs) == -1) { + return NGX_ERROR; + } + + *fs_id = 0; + for (i = 0; i < sizeof(fsid_t); i++) + ((u_char *)fs_id)[i % sizeof(ngx_fsid_t)] ^= ((u_char *)&fs.f_fsid)[i]; + + return NGX_OK; +} + #elif (NGX_HAVE_STATVFS)
size_t @@ -454,6 +471,19 @@ return (size_t) fs.f_frsize; }
+ngx_int_t +ngx_fs_id(u_char *name, ngx_fsid_t *fs_id) +{ + struct statvfs fs; + + if(statvfs((char *) name, &fs) == -1) { + return NGX_ERROR; + } + + *fs_id = fs.f_fsid; + return NGX_OK; +} + #else
size_t @@ -462,4 +492,15 @@ return 512; }
+ngx_int_t +ngx_fs_id(u_char *name, ngx_fsid_t *fs_id) +{ + return 0xdeadbeef; +} + #endif + +int ngx_fsid_t_cmp(const void *x, const void *y) +{ + return *(ngx_fsid_t *)x - *(ngx_fsid_t *)y; +} diff -uNr 0.7.61/src/os/unix/ngx_files.h trunk/src/os/unix/ngx_files.h --- 0.7.61/src/os/unix/ngx_files.h 2009-10-09 09:53:16.000000000 +0200 +++ trunk/src/os/unix/ngx_files.h 2009-10-09 09:53:25.000000000 +0200 @@ -15,6 +15,7 @@ typedef int ngx_fd_t; typedef struct stat ngx_file_info_t; typedef ino_t ngx_file_uniq_t; +typedef unsigned long ngx_fsid_t;
typedef struct { @@ -68,6 +69,7 @@
#define NGX_FILE_DEFAULT_ACCESS 0644 #define NGX_FILE_OWNER_ACCESS 0600 +#define NGX_FILE_GROUP_ACCESS 0664
#define ngx_close_file close @@ -216,13 +218,13 @@ #define ngx_de_is_file(dir) \ (((dir)->type) ? ((dir)->type == DT_REG) : (S_ISREG((dir)->info.st_mode))) #define ngx_de_is_link(dir) \ - (((dir)->type) ? ((dir)->type == DT_LINK) : (S_ISLNK((dir)->info.st_mode))) + (((dir)->type) ? ((dir)->type == DT_LNK) : (S_ISLNK((dir)->info.st_mode)))
#else
#define ngx_de_is_dir(dir) ((dir)->type == DT_DIR) #define ngx_de_is_file(dir) ((dir)->type == DT_REG) -#define ngx_de_is_link(dir) ((dir)->type == DT_LINK) +#define ngx_de_is_link(dir) ((dir)->type == DT_LNK)
#endif /* NGX_LINUX */
@@ -280,6 +282,8 @@ #endif
size_t ngx_fs_bsize(u_char *name); +ngx_int_t ngx_fs_id(u_char *name, ngx_fsid_t *fsid); +int ngx_fsid_t_cmp(const void *x, const void *y);
#define ngx_stderr STDERR_FILENO
diff -uNr 0.7.61/src/os/unix/ngx_process_cycle.c
trunk/src/os/unix/ngx_process_cycle.c
--- 0.7.61/src/os/unix/ngx_process_cycle.c 2009-10-09 09:53:16.000000000 +0200
+++ trunk/src/os/unix/ngx_process_cycle.c 2009-10-09 09:53:25.000000000 +0200
@@ -51,7 +51,7 @@
ngx_uint_t ngx_restart;
-#if (NGX_THREADS) +#if (NGX_THREADS) || (NGX_CAN_HAZ_THREADS) volatile ngx_thread_t ngx_threads[NGX_MAX_THREADS]; ngx_int_t ngx_threads_n; #endif @@ -1286,6 +1286,20 @@
ngx_add_timer(&ev, 0);
+#if (NGX_CAN_HAZ_THREADS) + + ngx_threads_n = 100; + + if (ngx_init_threads(ngx_threads_n, 2 * 1024 * 1024, cycle) + == NGX_ERROR) + { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_errno, + "ngx_init_threads failed"); + exit(2); + } + +#endif + for ( ;; ) {
if (ngx_terminate || ngx_quit) {
diff -uNr 0.7.61/src/os/unix/ngx_pthread_thread.c
trunk/src/os/unix/ngx_pthread_thread.c
--- 0.7.61/src/os/unix/ngx_pthread_thread.c 2009-10-09 09:53:16.000000000 +0200
+++ trunk/src/os/unix/ngx_pthread_thread.c 2009-10-09 09:53:25.000000000 +0200
@@ -78,6 +78,8 @@
int err;
ngx_mutex_t *m;
+ ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, log, 0, "initing mutex"); + m = ngx_alloc(sizeof(ngx_mutex_t), log); if (m == NULL) { return NULL; @@ -93,12 +95,16 @@ return NULL; }
+ ngx_log_debug1(NGX_LOG_DEBUG_MUTEX, log, 0, "mutex inited: %p", m); + return m; }
+#if 0 || (NGX_CAN_HAZ_THREADS) + void -ngx_mutex_destroy(ngx_mutex_t *m) +ngx_mutex_destroy_sp(ngx_mutex_t *m) { int err;
@@ -114,7 +120,7 @@
void -ngx_mutex_lock(ngx_mutex_t *m) +ngx_mutex_lock_sp(ngx_mutex_t *m) { int err;
@@ -139,7 +145,7 @@
ngx_int_t -ngx_mutex_trylock(ngx_mutex_t *m) +ngx_mutex_trylock_sp(ngx_mutex_t *m) { int err;
@@ -168,7 +174,7 @@
void -ngx_mutex_unlock(ngx_mutex_t *m) +ngx_mutex_unlock_sp(ngx_mutex_t *m) { int err;
@@ -191,6 +197,7 @@ return; }
+#endif
ngx_cond_t * ngx_cond_init(ngx_log_t *log) diff -uNr 0.7.61/src/os/unix/ngx_thread.h trunk/src/os/unix/ngx_thread.h --- 0.7.61/src/os/unix/ngx_thread.h 2009-10-09 09:53:16.000000000 +0200 +++ trunk/src/os/unix/ngx_thread.h 2009-10-09 09:53:25.000000000 +0200 @@ -11,7 +11,7 @@ #include <ngx_config.h> #include <ngx_core.h>
-#if (NGX_THREADS) +#if (NGX_CAN_HAZ_THREADS)
#define NGX_MAX_THREADS 128
@@ -57,17 +57,21 @@ } ngx_cond_t;
#define ngx_thread_sigmask pthread_sigmask -#define ngx_thread_sigmask_n "pthread_sigmask()" +#define ngx_thread_sigmask_n "pthread_sigmask()"
#define ngx_thread_join(t, p) pthread_join(t, p) +#define ngx_thread_join_n "pthread_join()"
#define ngx_setthrtitle(n)
+ngx_int_t ngx_mutex_trylock_sp(ngx_mutex_t *m); +void ngx_mutex_lock_sp(ngx_mutex_t *m); +void ngx_mutex_unlock_sp(ngx_mutex_t *m);
-ngx_int_t ngx_mutex_trylock(ngx_mutex_t *m); -void ngx_mutex_lock(ngx_mutex_t *m); -void ngx_mutex_unlock(ngx_mutex_t *m); +#define ngx_mutex_trylock(m) NGX_OK +#define ngx_mutex_lock(m) +#define ngx_mutex_unlock(m)
#endif
@@ -106,7 +110,7 @@ ngx_int_t ngx_cond_signal(ngx_cond_t *cv);
-#else /* !NGX_THREADS */ +#else /* !NGX_CAN_HAZ_THREADS */
#define ngx_thread_volatile






.gz, .diff