diff options
author | nginx <nginx@nginx.org> | 2014-06-17 13:35:02 +0000 |
---|---|---|
committer | Jon Kolb <kolbyjack@gmail.com> | 2014-06-17 13:35:02 +0000 |
commit | a995714bb2b96df7f846a8eec89715000f0699dd (patch) | |
tree | ebd35e0d5396e1a4497bc0859583b6d0ca2447f6 | |
parent | b72398c9a386f5100c857869af10a910d97549fe (diff) | |
download | nginx-1.7.2.tar.gz |
Changes with nginx 1.7.2 17 Jun 2014v1.7.2
*) Feature: the "hash" directive inside the "upstream" block.
*) Feature: defragmentation of free shared memory blocks.
Thanks to Wandenberg Peixoto and Yichun Zhang.
*) Bugfix: a segmentation fault might occur in a worker process if the
default value of the "access_log" directive was used; the bug had
appeared in 1.7.0.
Thanks to Piotr Sikora.
*) Bugfix: trailing slash was mistakenly removed from the last parameter
of the "try_files" directive.
*) Bugfix: nginx could not be built on OS X in some cases.
*) Bugfix: in the ngx_http_spdy_module.
-rw-r--r-- | CHANGES | 20 | ||||
-rw-r--r-- | CHANGES.ru | 20 | ||||
-rw-r--r-- | auto/cc/clang | 5 | ||||
-rw-r--r-- | auto/cc/gcc | 5 | ||||
-rw-r--r-- | auto/lib/perl/conf | 5 | ||||
-rw-r--r-- | auto/modules | 5 | ||||
-rw-r--r-- | auto/options | 4 | ||||
-rw-r--r-- | auto/sources | 4 | ||||
-rw-r--r-- | src/core/nginx.h | 4 | ||||
-rw-r--r-- | src/core/ngx_slab.c | 60 | ||||
-rw-r--r-- | src/core/ngx_slab.h | 1 | ||||
-rw-r--r-- | src/http/modules/ngx_http_log_module.c | 7 | ||||
-rw-r--r-- | src/http/modules/ngx_http_upstream_hash_module.c | 631 | ||||
-rw-r--r-- | src/http/ngx_http_core_module.c | 3 | ||||
-rw-r--r-- | src/http/ngx_http_spdy.h | 13 | ||||
-rw-r--r-- | src/http/ngx_http_upstream.c | 1 | ||||
-rw-r--r-- | src/http/ngx_http_upstream.h | 1 | ||||
-rw-r--r-- | src/http/ngx_http_upstream_round_robin.c | 114 | ||||
-rw-r--r-- | src/http/ngx_http_upstream_round_robin.h | 1 | ||||
-rw-r--r-- | src/os/unix/ngx_darwin_config.h | 3 |
20 files changed, 838 insertions, 69 deletions
@@ -1,4 +1,24 @@ +Changes with nginx 1.7.2 17 Jun 2014 + + *) Feature: the "hash" directive inside the "upstream" block. + + *) Feature: defragmentation of free shared memory blocks. + Thanks to Wandenberg Peixoto and Yichun Zhang. + + *) Bugfix: a segmentation fault might occur in a worker process if the + default value of the "access_log" directive was used; the bug had + appeared in 1.7.0. + Thanks to Piotr Sikora. + + *) Bugfix: trailing slash was mistakenly removed from the last parameter + of the "try_files" directive. + + *) Bugfix: nginx could not be built on OS X in some cases. + + *) Bugfix: in the ngx_http_spdy_module. + + Changes with nginx 1.7.1 27 May 2014 *) Feature: the "$upstream_cookie_..." variables. diff --git a/CHANGES.ru b/CHANGES.ru index 876699d12..67ac3f5df 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,24 @@ +Изменения в nginx 1.7.2 17.06.2014 + + *) Добавление: директива hash в блоке upstream. + + *) Добавление: дефрагментация свободных блоков разделяемой памяти. + Спасибо Wandenberg Peixoto и Yichun Zhang. + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если использовалось значение access_log по умолчанию; ошибка + появилась в 1.7.0. + Спасибо Piotr Sikora. + + *) Исправление: завершающий слэш ошибочно удалялся из последнего + параметра директивы try_files. + + *) Исправление: nginx мог не собираться на OS X. + + *) Исправление: в модуле ngx_http_spdy_module. + + Изменения в nginx 1.7.1 27.05.2014 *) Добавление: переменные "$upstream_cookie_...". diff --git a/auto/cc/clang b/auto/cc/clang index baaf4baa2..25707b42d 100644 --- a/auto/cc/clang +++ b/auto/cc/clang @@ -88,6 +88,11 @@ CFLAGS="$CFLAGS -Wconditional-uninitialized" # we have a lot of unused function arguments CFLAGS="$CFLAGS -Wno-unused-parameter" +# deprecated system OpenSSL library on OS X +if [ "$NGX_SYSTEM" = "Darwin" ]; then + CFLAGS="$CFLAGS -Wno-deprecated-declarations" +fi + # stop on warning CFLAGS="$CFLAGS -Werror" diff --git a/auto/cc/gcc b/auto/cc/gcc index c27d857e3..727f11e1d 100644 --- a/auto/cc/gcc +++ b/auto/cc/gcc @@ -158,6 +158,11 @@ case "$NGX_GCC_VER" in CFLAGS="$CFLAGS -Wno-unused-parameter" # 4.2.1 shows the warning in wrong places #CFLAGS="$CFLAGS -Wunreachable-code" + + # deprecated system OpenSSL library on OS X + if [ "$NGX_SYSTEM" = "Darwin" ]; then + CFLAGS="$CFLAGS -Wno-deprecated-declarations" + fi ;; *) diff --git a/auto/lib/perl/conf b/auto/lib/perl/conf index 2fbaa76b7..91009f15e 100644 --- a/auto/lib/perl/conf +++ b/auto/lib/perl/conf @@ -52,6 +52,11 @@ if test -n "$NGX_PERL_VER"; then ngx_perl_ldopts=`echo $ngx_perl_ldopts | sed 's/ -pthread//'` fi + if [ "$NGX_SYSTEM" = "Darwin" ]; then + # OS X system perl wants to link universal binaries + ngx_perl_ldopts=`echo $ngx_perl_ldopts | sed -e 's/-arch x86_64 -arch i386//'` + fi + CORE_LINK="$CORE_LINK $ngx_perl_ldopts" LINK_DEPS="$LINK_DEPS $NGX_OBJS/src/http/modules/perl/blib/arch/auto/nginx/nginx.$ngx_perl_dlext" diff --git a/auto/modules b/auto/modules index e1eda943f..788596763 100644 --- a/auto/modules +++ b/auto/modules @@ -371,6 +371,11 @@ if [ $HTTP_MP4 = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_MP4_SRCS" fi +if [ $HTTP_UPSTREAM_HASH = YES ]; then + HTTP_MODULES="$HTTP_MODULES $HTTP_UPSTREAM_HASH_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_HASH_SRCS" +fi + if [ $HTTP_UPSTREAM_IP_HASH = YES ]; then HTTP_MODULES="$HTTP_MODULES $HTTP_UPSTREAM_IP_HASH_MODULE" HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_IP_HASH_SRCS" diff --git a/auto/options b/auto/options index 010a6bbe2..0d296ac60 100644 --- a/auto/options +++ b/auto/options @@ -99,6 +99,7 @@ HTTP_FLV=NO HTTP_MP4=NO HTTP_GUNZIP=NO HTTP_GZIP_STATIC=NO +HTTP_UPSTREAM_HASH=YES HTTP_UPSTREAM_IP_HASH=YES HTTP_UPSTREAM_LEAST_CONN=YES HTTP_UPSTREAM_KEEPALIVE=YES @@ -251,6 +252,7 @@ use the \"--without-http_limit_conn_module\" option instead" --without-http_limit_req_module) HTTP_LIMIT_REQ=NO ;; --without-http_empty_gif_module) HTTP_EMPTY_GIF=NO ;; --without-http_browser_module) HTTP_BROWSER=NO ;; + --without-http_upstream_hash_module) HTTP_UPSTREAM_HASH=NO ;; --without-http_upstream_ip_hash_module) HTTP_UPSTREAM_IP_HASH=NO ;; --without-http_upstream_least_conn_module) HTTP_UPSTREAM_LEAST_CONN=NO ;; @@ -395,6 +397,8 @@ cat << END --without-http_limit_req_module disable ngx_http_limit_req_module --without-http_empty_gif_module disable ngx_http_empty_gif_module --without-http_browser_module disable ngx_http_browser_module + --without-http_upstream_hash_module + disable ngx_http_upstream_hash_module --without-http_upstream_ip_hash_module disable ngx_http_upstream_ip_hash_module --without-http_upstream_least_conn_module diff --git a/auto/sources b/auto/sources index 13c1531f7..1287782ea 100644 --- a/auto/sources +++ b/auto/sources @@ -497,6 +497,10 @@ HTTP_GZIP_STATIC_MODULE=ngx_http_gzip_static_module HTTP_GZIP_STATIC_SRCS=src/http/modules/ngx_http_gzip_static_module.c +HTTP_UPSTREAM_HASH_MODULE=ngx_http_upstream_hash_module +HTTP_UPSTREAM_HASH_SRCS=src/http/modules/ngx_http_upstream_hash_module.c + + HTTP_UPSTREAM_IP_HASH_MODULE=ngx_http_upstream_ip_hash_module HTTP_UPSTREAM_IP_HASH_SRCS=src/http/modules/ngx_http_upstream_ip_hash_module.c diff --git a/src/core/nginx.h b/src/core/nginx.h index 12e6e8a86..81e351c2a 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1007001 -#define NGINX_VERSION "1.7.1" +#define nginx_version 1007002 +#define NGINX_VERSION "1.7.2" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c index be7927ce0..be3e54084 100644 --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c @@ -129,6 +129,8 @@ ngx_slab_init(ngx_slab_pool_t *pool) pool->pages->slab = pages; } + pool->last = pool->pages + pages; + pool->log_nomem = 1; pool->log_ctx = &pool->zero; pool->zero = '\0'; @@ -626,6 +628,8 @@ ngx_slab_alloc_pages(ngx_slab_pool_t *pool, ngx_uint_t pages) if (page->slab >= pages) { if (page->slab > pages) { + page[page->slab - 1].prev = (uintptr_t) &page[pages]; + page[pages].slab = page->slab - pages; page[pages].next = page->next; page[pages].prev = page->prev; @@ -672,7 +676,8 @@ static void ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page, ngx_uint_t pages) { - ngx_slab_page_t *prev; + ngx_uint_t type; + ngx_slab_page_t *prev, *join; page->slab = pages--; @@ -686,6 +691,59 @@ ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page, page->next->prev = page->prev; } + join = page + page->slab; + + if (join < pool->last) { + type = join->prev & NGX_SLAB_PAGE_MASK; + + if (type == NGX_SLAB_PAGE) { + + if (join->next != NULL) { + pages += join->slab; + page->slab += join->slab; + + prev = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK); + prev->next = join->next; + join->next->prev = join->prev; + + join->slab = NGX_SLAB_PAGE_FREE; + join->next = NULL; + join->prev = NGX_SLAB_PAGE; + } + } + } + + if (page > pool->pages) { + join = page - 1; + type = join->prev & NGX_SLAB_PAGE_MASK; + + if (type == NGX_SLAB_PAGE) { + + if (join->slab == NGX_SLAB_PAGE_FREE) { + join = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK); + } + + if (join->next != NULL) { + pages += join->slab; + join->slab += page->slab; + + prev = (ngx_slab_page_t *) (join->prev & ~NGX_SLAB_PAGE_MASK); + prev->next = join->next; + join->next->prev = join->prev; + + page->slab = NGX_SLAB_PAGE_FREE; + page->next = NULL; + page->prev = NGX_SLAB_PAGE; + + page = join; + } + } + } + + if (pages) { + page[pages].prev = (uintptr_t) page; + } + page->prev = (uintptr_t) &pool->free; page->next = pool->free.next; diff --git a/src/core/ngx_slab.h b/src/core/ngx_slab.h index 5735e3bb3..1ee65d531 100644 --- a/src/core/ngx_slab.h +++ b/src/core/ngx_slab.h @@ -29,6 +29,7 @@ typedef struct { size_t min_shift; ngx_slab_page_t *pages; + ngx_slab_page_t *last; ngx_slab_page_t free; u_char *start; diff --git a/src/http/modules/ngx_http_log_module.c b/src/http/modules/ngx_http_log_module.c index f51ba938d..bc660cdd6 100644 --- a/src/http/modules/ngx_http_log_module.c +++ b/src/http/modules/ngx_http_log_module.c @@ -1109,16 +1109,13 @@ ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } + ngx_memzero(log, sizeof(ngx_http_log_t)); + log->file = ngx_conf_open_file(cf->cycle, &ngx_http_access_log); if (log->file == NULL) { return NGX_CONF_ERROR; } - log->script = NULL; - log->disk_full_time = 0; - log->error_log_time = 0; - log->syslog_peer = NULL; - lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module); fmt = lmcf->formats.elts; diff --git a/src/http/modules/ngx_http_upstream_hash_module.c b/src/http/modules/ngx_http_upstream_hash_module.c new file mode 100644 index 000000000..777e180a5 --- /dev/null +++ b/src/http/modules/ngx_http_upstream_hash_module.c @@ -0,0 +1,631 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_http.h> + + +typedef struct { + uint32_t hash; + ngx_str_t *server; +} ngx_http_upstream_chash_point_t; + + +typedef struct { + ngx_uint_t number; + ngx_http_upstream_chash_point_t point[1]; +} ngx_http_upstream_chash_points_t; + + +typedef struct { + ngx_http_complex_value_t key; + ngx_http_upstream_chash_points_t *points; +} ngx_http_upstream_hash_srv_conf_t; + + +typedef struct { + /* the round robin data must be first */ + ngx_http_upstream_rr_peer_data_t rrp; + ngx_http_upstream_hash_srv_conf_t *conf; + ngx_str_t key; + ngx_uint_t tries; + ngx_uint_t rehash; + uint32_t hash; + ngx_event_get_peer_pt get_rr_peer; +} ngx_http_upstream_hash_peer_data_t; + + +static ngx_int_t ngx_http_upstream_init_hash(ngx_conf_t *cf, + ngx_http_upstream_srv_conf_t *us); +static ngx_int_t ngx_http_upstream_init_hash_peer(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us); +static ngx_int_t ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, + void *data); + +static ngx_int_t ngx_http_upstream_init_chash(ngx_conf_t *cf, + ngx_http_upstream_srv_conf_t *us); +static void ngx_http_upstream_add_chash_point( + ngx_http_upstream_chash_points_t *points, uint32_t hash, ngx_str_t *server); +static ngx_uint_t ngx_http_upstream_find_chash_point( + ngx_http_upstream_chash_points_t *points, uint32_t hash); +static ngx_int_t ngx_http_upstream_init_chash_peer(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us); +static ngx_int_t ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, + void *data); + +static void *ngx_http_upstream_hash_create_conf(ngx_conf_t *cf); +static char *ngx_http_upstream_hash(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +static ngx_command_t ngx_http_upstream_hash_commands[] = { + + { ngx_string("hash"), + NGX_HTTP_UPS_CONF|NGX_CONF_TAKE12, + ngx_http_upstream_hash, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_upstream_hash_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_http_upstream_hash_create_conf, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_upstream_hash_module = { + NGX_MODULE_V1, + &ngx_http_upstream_hash_module_ctx, /* module context */ + ngx_http_upstream_hash_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_int_t +ngx_http_upstream_init_hash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) +{ + if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) { + return NGX_ERROR; + } + + us->peer.init = ngx_http_upstream_init_hash_peer; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_init_hash_peer(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us) +{ + ngx_http_upstream_hash_srv_conf_t *hcf; + ngx_http_upstream_hash_peer_data_t *hp; + + hp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_hash_peer_data_t)); + if (hp == NULL) { + return NGX_ERROR; + } + + r->upstream->peer.data = &hp->rrp; + + if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) { + return NGX_ERROR; + } + + r->upstream->peer.get = ngx_http_upstream_get_hash_peer; + + hcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_hash_module); + + if (ngx_http_complex_value(r, &hcf->key, &hp->key) != NGX_OK) { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "upstream hash key:\"%V\"", &hp->key); + + hp->conf = hcf; + hp->tries = 0; + hp->rehash = 0; + hp->hash = 0; + hp->get_rr_peer = ngx_http_upstream_get_round_robin_peer; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data) +{ + ngx_http_upstream_hash_peer_data_t *hp = data; + + time_t now; + u_char buf[NGX_INT_T_LEN]; + size_t size; + uint32_t hash; + ngx_int_t w; + uintptr_t m; + ngx_uint_t i, n, p; + ngx_http_upstream_rr_peer_t *peer; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "get hash peer, try: %ui", pc->tries); + + if (hp->tries > 20 || hp->rrp.peers->single) { + return hp->get_rr_peer(pc, &hp->rrp); + } + + now = ngx_time(); + + pc->cached = 0; + pc->connection = NULL; + + for ( ;; ) { + + /* + * Hash expression is compatible with Cache::Memcached: + * ((crc32([REHASH] KEY) >> 16) & 0x7fff) + PREV_HASH + * with REHASH omitted at the first iteration. + */ + + ngx_crc32_init(hash); + + if (hp->rehash > 0) { + size = ngx_sprintf(buf, "%ui", hp->rehash) - buf; + ngx_crc32_update(&hash, buf, size); + } + + ngx_crc32_update(&hash, hp->key.data, hp->key.len); + ngx_crc32_final(hash); + + hash = (hash >> 16) & 0x7fff; + + hp->hash += hash; + hp->rehash++; + + if (!hp->rrp.peers->weighted) { + p = hp->hash % hp->rrp.peers->number; + + } else { + w = hp->hash % hp->rrp.peers->total_weight; + + for (i = 0; i < hp->rrp.peers->number; i++) { + w -= hp->rrp.peers->peer[i].weight; + if (w < 0) { + break; + } + } + + p = i; + } + + n = p / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); + + if (hp->rrp.tried[n] & m) { + goto next; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "get hash peer, value:%uD, peer:%ui", hp->hash, p); + + peer = &hp->rrp.peers->peer[p]; + + if (peer->down) { + goto next; + } + + if (peer->max_fails + && peer->fails >= peer->max_fails + && now - peer->checked <= peer->fail_timeout) + { + goto next; + } + + break; + + next: + + if (++hp->tries > 20) { + return hp->get_rr_peer(pc, &hp->rrp); + } + } + + hp->rrp.current = p; + + pc->sockaddr = peer->sockaddr; + pc->socklen = peer->socklen; + pc->name = &peer->name; + + if (now - peer->checked > peer->fail_timeout) { + peer->checked = now; + } + + hp->rrp.tried[n] |= m; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_init_chash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) +{ + u_char *host, *port, c; + size_t host_len, port_len, size; + uint32_t hash, base_hash, prev_hash; + ngx_str_t *server; + ngx_uint_t npoints, i, j; + ngx_http_upstream_rr_peer_t *peer; + ngx_http_upstream_rr_peers_t *peers; + ngx_http_upstream_chash_points_t *points; + ngx_http_upstream_hash_srv_conf_t *hcf; + + if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) { + return NGX_ERROR; + } + + us->peer.init = ngx_http_upstream_init_chash_peer; + + peers = us->peer.data; + npoints = peers->total_weight * 160; + + size = sizeof(ngx_http_upstream_chash_points_t) + + sizeof(ngx_http_upstream_chash_point_t) * (npoints - 1); + + points = ngx_palloc(cf->pool, size); + if (points == NULL) { + return NGX_ERROR; + } + + points->number = 0; + + for (i = 0; i < peers->number; i++) { + peer = &peers->peer[i]; + server = &peer->server; + + /* + * Hash expression is compatible with Cache::Memcached::Fast: + * crc32(HOST \0 PORT PREV_HASH). + */ + + if (server->len >= 5 + && ngx_strncasecmp(server->data, (u_char *) "unix:", 5) == 0) + { + host = server->data + 5; + host_len = server->len - 5; + port = NULL; + port_len = 0; + goto done; + } + + for (j = 0; j < server->len; j++) { + c = server->data[server->len - j - 1]; + + if (c == ':') { + host = server->data; + host_len = server->len - j - 1; + port = server->data + server->len - j; + port_len = j; + goto done; + } + + if (c < '0' || c > '9') { + break; + } + } + + host = server->data; + host_len = server->len; + port = NULL; + port_len = 0; + + done: + + ngx_crc32_init(base_hash); + ngx_crc32_update(&base_hash, host, host_len); + ngx_crc32_update(&base_hash, (u_char *) "", 1); + ngx_crc32_update(&base_hash, port, port_len); + + prev_hash = 0; + npoints = peer->weight * 160; + + for (j = 0; j < npoints; j++) { + hash = base_hash; + + ngx_crc32_update(&hash, (u_char *) &prev_hash, sizeof(uint32_t)); + ngx_crc32_final(hash); + + ngx_http_upstream_add_chash_point(points, hash, &peer->server); + + prev_hash = hash; + } + } + + hcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_hash_module); + hcf->points = points; + + return NGX_OK; +} + + +static void +ngx_http_upstream_add_chash_point(ngx_http_upstream_chash_points_t *points, + uint32_t hash, ngx_str_t *server) +{ + size_t size; + ngx_uint_t i; + ngx_http_upstream_chash_point_t *point; + + i = ngx_http_upstream_find_chash_point(points, hash); + point = &points->point[i]; + + if (point->hash == hash) { + return; + } + + size = (points->number - i) * sizeof(ngx_http_upstream_chash_point_t); + + ngx_memmove(point + 1, point, size); + + points->number++; + point->hash = hash; + point->server = server; +} + + +static ngx_uint_t +ngx_http_upstream_find_chash_point(ngx_http_upstream_chash_points_t *points, + uint32_t hash) +{ + ngx_uint_t i, j, k; + ngx_http_upstream_chash_point_t *point; + + /* find first point >= hash */ + + point = &points->point[0]; + + i = 0; + j = points->number; + + while (i < j) { + k = (i + j) / 2; + + if (hash > point[k].hash) { + i = k + 1; + + } else if (hash < point[k].hash) { + j = k; + + } else { + return k; + } + } + + return i; +} + + +static ngx_int_t +ngx_http_upstream_init_chash_peer(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us) +{ + uint32_t hash; + ngx_http_upstream_hash_srv_conf_t *hcf; + ngx_http_upstream_hash_peer_data_t *hp; + + if (ngx_http_upstream_init_hash_peer(r, us) != NGX_OK) { + return NGX_ERROR; + } + + r->upstream->peer.get = ngx_http_upstream_get_chash_peer; + + hp = r->upstream->peer.data; + hcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_hash_module); + + hash = ngx_crc32_long(hp->key.data, hp->key.len); + hp->hash = ngx_http_upstream_find_chash_point(hcf->points, hash); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) +{ + ngx_http_upstream_hash_peer_data_t *hp = data; + + time_t now; + intptr_t m; + ngx_str_t *server; + ngx_int_t total; + ngx_uint_t i, n; + ngx_http_upstream_rr_peer_t *peer, *best; + ngx_http_upstream_chash_point_t *point; + ngx_http_upstream_chash_points_t *points; + ngx_http_upstream_hash_srv_conf_t *hcf; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "get consistent hash peer, try: %ui", pc->tries); + + pc->cached = 0; + pc->connection = NULL; + + now = ngx_time(); + hcf = hp->conf; + + points = hcf->points; + point = &points->point[0]; + + for ( ;; ) { + server = point[hp->hash % points->number].server; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "consistent hash peer:%uD, server:\"%V\"", + hp->hash, server); + + best = NULL; + total = 0; + + for (i = 0; i < hp->rrp.peers->number; i++) { + + n = i / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); + + if (hp->rrp.tried[n] & m) { + continue; + } + + peer = &hp->rrp.peers->peer[i]; + + if (peer->down) { + continue; + } + + if (peer->server.len != server->len + || ngx_strncmp(peer->server.data, server->data, server->len) + != 0) + { + continue; + } + + if (peer->max_fails + && peer->fails >= peer->max_fails + && now - peer->checked <= peer->fail_timeout) + { + continue; + } + + peer->current_weight += peer->effective_weight; + total += peer->effective_weight; + + if (peer->effective_weight < peer->weight) { + peer->effective_weight++; + } + + if (best == NULL || peer->current_weight > best->current_weight) { + best = peer; + } + } + + if (best) { + best->current_weight -= total; + + i = best - &hp->rrp.peers->peer[0]; + + hp->rrp.current = i; + + n = i / (8 * sizeof(uintptr_t)); + m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); + + hp->rrp.tried[n] |= m; + + if (now - best->checked > best->fail_timeout) { + best->checked = now; + } + + pc->sockaddr = best->sockaddr; + pc->socklen = best->socklen; + pc->name = &best->name; + + return NGX_OK; + } + + hp->hash++; + hp->tries++; + + if (hp->tries >= points->number) { + return NGX_BUSY; + } + } +} + + +static void * +ngx_http_upstream_hash_create_conf(ngx_conf_t *cf) +{ + ngx_http_upstream_hash_srv_conf_t *conf; + + conf = ngx_palloc(cf->pool, sizeof(ngx_http_upstream_hash_srv_conf_t)); + if (conf == NULL) { + return NULL; + } + + conf->points = NULL; + + return conf; +} + + +static char * +ngx_http_upstream_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_upstream_hash_srv_conf_t *hcf = conf; + + ngx_str_t *value; + ngx_http_upstream_srv_conf_t *uscf; + ngx_http_compile_complex_value_t ccv; + + value = cf->args->elts; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &hcf->key; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); + + if (uscf->peer.init_upstream) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "load balancing method redefined"); + } + + uscf->flags = NGX_HTTP_UPSTREAM_CREATE + |NGX_HTTP_UPSTREAM_WEIGHT + |NGX_HTTP_UPSTREAM_MAX_FAILS + |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT + |NGX_HTTP_UPSTREAM_DOWN; + + if (cf->args->nelts == 2) { + uscf->peer.init_upstream = ngx_http_upstream_init_hash; + + } else if (ngx_strcmp(value[2].data, "consistent") == 0) { + uscf->peer.init_upstream = ngx_http_upstream_init_chash; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 741a80d93..fb02dd465 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -4789,7 +4789,8 @@ ngx_http_core_try_files(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) tf[i].name = value[i + 1]; if (tf[i].name.len > 0 - && tf[i].name.data[tf[i].name.len - 1] == '/') + && tf[i].name.data[tf[i].name.len - 1] == '/' + && i + 2 < cf->args->nelts) { tf[i].test_dir = 1; tf[i].name.len--; diff --git a/src/http/ngx_http_spdy.h b/src/http/ngx_http_spdy.h index 55aceda89..df24495a1 100644 --- a/src/http/ngx_http_spdy.h +++ b/src/http/ngx_http_spdy.h @@ -230,13 +230,16 @@ ngx_int_t ngx_http_spdy_send_output_queue(ngx_http_spdy_connection_t *sc); #else #define ngx_spdy_frame_write_uint16(p, s) \ - ((p)[0] = (u_char) (s) >> 8, (p)[1] = (u_char) (s), (p) + sizeof(uint16_t)) + ((p)[0] = (u_char) ((s) >> 8), \ + (p)[1] = (u_char) (s), \ + (p) + sizeof(uint16_t)) #define ngx_spdy_frame_write_uint32(p, s) \ - ((p)[0] = (u_char) (s) >> 24, \ - (p)[1] = (u_char) (s) >> 16, \ - (p)[2] = (u_char) (s) >> 8, \ - (p)[3] = (u_char) (s), (p) + sizeof(uint32_t)) + ((p)[0] = (u_char) ((s) >> 24), \ + (p)[1] = (u_char) ((s) >> 16), \ + (p)[2] = (u_char) ((s) >> 8), \ + (p)[3] = (u_char) (s), \ + (p) + sizeof(uint32_t)) #endif diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index de3ff130a..8b6d3f69f 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -4998,6 +4998,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) goto invalid; } + us->name = u.url; us->addrs = u.addrs; us->naddrs = u.naddrs; us->weight = weight; diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index 50b3e6367..3128ccef0 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -87,6 +87,7 @@ typedef struct { typedef struct { + ngx_str_t name; ngx_addr_t *addrs; ngx_uint_t naddrs; ngx_uint_t weight; diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c index 85ff5581b..37c835cbd 100644 --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -30,6 +30,7 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, ngx_url_t u; ngx_uint_t i, j, n, w; ngx_http_upstream_server_t *server; + ngx_http_upstream_rr_peer_t *peer; ngx_http_upstream_rr_peers_t *peers, *backup; us->peer.init = ngx_http_upstream_init_round_robin_peer; @@ -69,6 +70,7 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, peers->name = &us->host; n = 0; + peer = peers->peer; for (i = 0; i < us->servers->nelts; i++) { if (server[i].backup) { @@ -76,15 +78,16 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, } for (j = 0; j < server[i].naddrs; j++) { - peers->peer[n].sockaddr = server[i].addrs[j].sockaddr; - peers->peer[n].socklen = server[i].addrs[j].socklen; - peers->peer[n].name = server[i].addrs[j].name; - peers->peer[n].weight = server[i].weight; - peers->peer[n].effective_weight = server[i].weight; - peers->peer[n].current_weight = 0; - peers->peer[n].max_fails = server[i].max_fails; - peers->peer[n].fail_timeout = server[i].fail_timeout; - peers->peer[n].down = server[i].down; + peer[n].sockaddr = server[i].addrs[j].sockaddr; + peer[n].socklen = server[i].addrs[j].socklen; + peer[n].name = server[i].addrs[j].name; + peer[n].weight = server[i].weight; + peer[n].effective_weight = server[i].weight; + peer[n].current_weight = 0; + peer[n].max_fails = server[i].max_fails; + peer[n].fail_timeout = server[i].fail_timeout; + peer[n].down = server[i].down; + peer[n].server = server[i].name; n++; } } @@ -123,6 +126,7 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, backup->name = &us->host; n = 0; + peer = backup->peer; for (i = 0; i < us->servers->nelts; i++) { if (!server[i].backup) { @@ -130,15 +134,16 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, } for (j = 0; j < server[i].naddrs; j++) { - backup->peer[n].sockaddr = server[i].addrs[j].sockaddr; - backup->peer[n].socklen = server[i].addrs[j].socklen; - backup->peer[n].name = server[i].addrs[j].name; - backup->peer[n].weight = server[i].weight; - backup->peer[n].effective_weight = server[i].weight; - backup->peer[n].current_weight = 0; - backup->peer[n].max_fails = server[i].max_fails; - backup->peer[n].fail_timeout = server[i].fail_timeout; - backup->peer[n].down = server[i].down; + peer[n].sockaddr = server[i].addrs[j].sockaddr; + peer[n].socklen = server[i].addrs[j].socklen; + peer[n].name = server[i].addrs[j].name; + peer[n].weight = server[i].weight; + peer[n].effective_weight = server[i].weight; + peer[n].current_weight = 0; + peer[n].max_fails = server[i].max_fails; + peer[n].fail_timeout = server[i].fail_timeout; + peer[n].down = server[i].down; + peer[n].server = server[i].name; n++; } } @@ -187,15 +192,17 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, peers->total_weight = n; peers->name = &us->host; + peer = peers->peer; + for (i = 0; i < u.naddrs; i++) { - peers->peer[i].sockaddr = u.addrs[i].sockaddr; - peers->peer[i].socklen = u.addrs[i].socklen; - peers->peer[i].name = u.addrs[i].name; - peers->peer[i].weight = 1; - peers->peer[i].effective_weight = 1; - peers->peer[i].current_weight = 0; - peers->peer[i].max_fails = 1; - peers->peer[i].fail_timeout = 10; + peer[i].sockaddr = u.addrs[i].sockaddr; + peer[i].socklen = u.addrs[i].socklen; + peer[i].name = u.addrs[i].name; + peer[i].weight = 1; + peer[i].effective_weight = 1; + peer[i].current_weight = 0; + peer[i].max_fails = 1; + peer[i].fail_timeout = 10; } us->peer.data = peers; @@ -269,6 +276,7 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, socklen_t socklen; ngx_uint_t i, n; struct sockaddr *sockaddr; + ngx_http_upstream_rr_peer_t *peer; ngx_http_upstream_rr_peers_t *peers; ngx_http_upstream_rr_peer_data_t *rrp; @@ -293,15 +301,17 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, peers->number = ur->naddrs; peers->name = &ur->host; + peer = peers->peer; + if (ur->sockaddr) { - peers->peer[0].sockaddr = ur->sockaddr; - peers->peer[0].socklen = ur->socklen; - peers->peer[0].name = ur->host; - peers->peer[0].weight = 1; - peers->peer[0].effective_weight = 1; - peers->peer[0].current_weight = 0; - peers->peer[0].max_fails = 1; - peers->peer[0].fail_timeout = 10; + peer[0].sockaddr = ur->sockaddr; + peer[0].socklen = ur->socklen; + peer[0].name = ur->host; + peer[0].weight = 1; + peer[0].effective_weight = 1; + peer[0].current_weight = 0; + peer[0].max_fails = 1; + peer[0].fail_timeout = 10; } else { @@ -333,15 +343,15 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1); - peers->peer[i].sockaddr = sockaddr; - peers->peer[i].socklen = socklen; - peers->peer[i].name.len = len; - peers->peer[i].name.data = p; - peers->peer[i].weight = 1; - peers->peer[i].effective_weight = 1; - peers->peer[i].current_weight = 0; - peers->peer[i].max_fails = 1; - peers->peer[i].fail_timeout = 10; + peer[i].sockaddr = sockaddr; + peer[i].socklen = socklen; + peer[i].name.len = len; + peer[i].name.data = p; + peer[i].weight = 1; + peer[i].effective_weight = 1; + peer[i].current_weight = 0; + peer[i].max_fails = 1; + peer[i].fail_timeout = 10; } } @@ -387,13 +397,15 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get rr peer, try: %ui", pc->tries); - /* ngx_lock_mutex(rrp->peers->mutex); */ - pc->cached = 0; pc->connection = NULL; - if (rrp->peers->single) { - peer = &rrp->peers->peer[0]; + peers = rrp->peers; + + /* ngx_lock_mutex(peers->mutex); */ + + if (peers->single) { + peer = &peers->peer[0]; if (peer->down) { goto failed; @@ -418,18 +430,16 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) pc->socklen = peer->socklen; pc->name = &peer->name; - /* ngx_unlock_mutex(rrp->peers->mutex); */ + /* ngx_unlock_mutex(peers->mutex); */ - if (pc->tries == 1 && rrp->peers->next) { - pc->tries += rrp->peers->next->number; + if (pc->tries == 1 && peers->next) { + pc->tries += peers->next->number; } return NGX_OK; failed: - peers = rrp->peers; - if (peers->next) { /* ngx_unlock_mutex(peers->mutex); */ diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h index ea90ab918..9db82a63c 100644 --- a/src/http/ngx_http_upstream_round_robin.h +++ b/src/http/ngx_http_upstream_round_robin.h @@ -18,6 +18,7 @@ typedef struct { struct sockaddr *sockaddr; socklen_t socklen; ngx_str_t name; + ngx_str_t server; ngx_int_t current_weight; ngx_int_t effective_weight; diff --git a/src/os/unix/ngx_darwin_config.h b/src/os/unix/ngx_darwin_config.h index 7ac86c73e..bbad977cb 100644 --- a/src/os/unix/ngx_darwin_config.h +++ b/src/os/unix/ngx_darwin_config.h @@ -9,9 +9,6 @@ #define _NGX_DARWIN_CONFIG_H_INCLUDED_ -#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_0 - - #include <sys/types.h> #include <sys/time.h> #include <unistd.h> |