upstream choice modules
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index f22de51..ab21477 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -13,9 +13,6 @@
typedef struct {
ngx_http_upstream_conf_t upstream;
- ngx_http_upstream_srv_conf_t *upstream_peers;
- ngx_peers_t *peers0;
-
ngx_str_t index;
ngx_array_t *flushes;
@@ -121,6 +118,11 @@
static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post,
void *data);
+static char *ngx_http_fastcgi_upstream_max_fails_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf);
+static char *ngx_http_fastcgi_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf);
+
static ngx_http_fastcgi_request_start_t ngx_http_fastcgi_request_start = {
{ 1, /* version */
@@ -310,16 +312,16 @@
{ ngx_string("fastcgi_upstream_max_fails"),
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_fastcgi_loc_conf_t, upstream.max_fails),
+ ngx_http_fastcgi_upstream_max_fails_unsupported,
+ 0,
+ 0,
NULL },
{ ngx_string("fastcgi_upstream_fail_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_sec_slot,
- NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_fastcgi_loc_conf_t, upstream.fail_timeout),
+ ngx_http_fastcgi_upstream_fail_timeout_unsupported,
+ 0,
+ 0,
NULL },
{ ngx_string("fastcgi_param"),
@@ -411,8 +413,6 @@
u->peer.log = r->connection->log;
u->peer.log_error = NGX_ERROR_ERR;
- u->peer.peers = flcf->upstream_peers->peers;
- u->peer.tries = flcf->upstream_peers->peers->number;
#if (NGX_THREADS)
u->peer.lock = &r->connection->lock;
#endif
@@ -1547,9 +1547,6 @@
conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
- conf->upstream.max_fails = NGX_CONF_UNSET_UINT;
- conf->upstream.fail_timeout = NGX_CONF_UNSET;
-
conf->upstream.pass_request_headers = NGX_CONF_UNSET;
conf->upstream.pass_request_body = NGX_CONF_UNSET;
@@ -1573,7 +1570,6 @@
uintptr_t *code;
ngx_str_t *header;
ngx_uint_t i, j;
- ngx_peer_t *peer;
ngx_array_t hide_headers;
ngx_keyval_t *src;
ngx_hash_key_t *hk;
@@ -1707,25 +1703,6 @@
|NGX_HTTP_UPSTREAM_FT_OFF;
}
- ngx_conf_merge_uint_value(conf->upstream.max_fails,
- prev->upstream.max_fails, 1);
-
- ngx_conf_merge_sec_value(conf->upstream.fail_timeout,
- prev->upstream.fail_timeout, 10);
-
- if (conf->upstream_peers) {
- peer = conf->upstream_peers->peers->peer;
- for (i = 0; i < conf->upstream_peers->peers->number; i++) {
- ngx_conf_init_uint_value(peer[i].weight, 1);
- peer[i].current_weight = peer[i].weight;
- ngx_conf_init_uint_value(peer[i].max_fails,
- conf->upstream.max_fails);
- ngx_conf_init_value(peer[i].fail_timeout,
- conf->upstream.fail_timeout);
- }
-
- }
-
ngx_conf_merge_path_value(conf->upstream.temp_path,
prev->upstream.temp_path,
NGX_HTTP_FASTCGI_TEMP_PATH, 1, 2, 0,
@@ -1844,8 +1821,8 @@
peers:
- if (conf->upstream_peers == NULL) {
- conf->upstream_peers = prev->upstream_peers;
+ if (conf->upstream.upstream == NULL) {
+ conf->upstream.upstream = prev->upstream.upstream;
conf->upstream.schema = prev->upstream.schema;
}
@@ -2033,10 +2010,10 @@
ngx_memzero(&u, sizeof(ngx_url_t));
u.url = value[1];
- u.upstream = 1;
+ u.no_resolve = 1;
- lcf->upstream_peers = ngx_http_upstream_add(cf, &u);
- if (lcf->upstream_peers == NULL) {
+ lcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
+ if (lcf->upstream.upstream == NULL) {
return NGX_CONF_ERROR;
}
@@ -2084,3 +2061,29 @@
return NGX_CONF_OK;
}
+
+
+static char *
+ngx_http_fastcgi_upstream_max_fails_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf)
+{
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"fastcgi_upstream_max_fails\" is not supported, "
+ "use the \"max_fails\" parameter of the \"server\" directive ",
+ "inside the \"upstream\" block");
+
+ return NGX_CONF_ERROR;
+}
+
+
+static char *
+ngx_http_fastcgi_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf)
+{
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"fastcgi_upstream_fail_timeout\" is not supported, "
+ "use the \"fail_timeout\" parameter of the \"server\" directive ",
+ "inside the \"upstream\" block");
+
+ return NGX_CONF_ERROR;
+}
diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c
index 63bda64..bd8b837 100644
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -12,7 +12,6 @@
typedef struct {
ngx_http_upstream_conf_t upstream;
- ngx_peers_t *peers;
} ngx_http_memcached_loc_conf_t;
@@ -39,6 +38,11 @@
static char *ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char *ngx_http_memcached_upstream_max_fails_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf);
+static char *ngx_http_memcached_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf);
+
static ngx_conf_bitmask_t ngx_http_memcached_next_upstream_masks[] = {
{ ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
@@ -96,16 +100,16 @@
{ ngx_string("memcached_upstream_max_fails"),
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_memcached_loc_conf_t, upstream.max_fails),
+ ngx_http_memcached_upstream_max_fails_unsupported,
+ 0,
+ 0,
NULL },
{ ngx_string("memcached_upstream_fail_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_sec_slot,
- NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_memcached_loc_conf_t, upstream.fail_timeout),
+ ngx_http_memcached_upstream_fail_timeout_unsupported,
+ 0,
+ 0,
NULL },
ngx_null_command
@@ -178,8 +182,6 @@
u->peer.log = r->connection->log;
u->peer.log_error = NGX_ERROR_ERR;
- u->peer.peers = mlcf->peers;
- u->peer.tries = mlcf->peers->number;
#if (NGX_THREADS)
u->peer.lock = &r->connection->lock;
#endif
@@ -511,13 +513,8 @@
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
- conf->upstream.max_fails = NGX_CONF_UNSET_UINT;
- conf->upstream.fail_timeout = NGX_CONF_UNSET;
-
- /* "fastcgi_cyclic_temp_file" is disabled */
- conf->upstream.cyclic_temp_file = 0;
-
/* the hardcoded values */
+ conf->upstream.cyclic_temp_file = 0;
conf->upstream.buffering = 0;
conf->upstream.ignore_client_abort = 0;
conf->upstream.send_lowat = 0;
@@ -540,8 +537,6 @@
ngx_http_memcached_loc_conf_t *prev = parent;
ngx_http_memcached_loc_conf_t *conf = child;
- ngx_uint_t i;
-
ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
prev->upstream.connect_timeout, 60000);
@@ -566,20 +561,6 @@
|NGX_HTTP_UPSTREAM_FT_OFF;
}
- ngx_conf_merge_uint_value(conf->upstream.max_fails,
- prev->upstream.max_fails, 1);
-
- ngx_conf_merge_sec_value(conf->upstream.fail_timeout,
- prev->upstream.fail_timeout, 10);
-
- if (conf->peers && conf->peers->number > 1) {
- for (i = 0; i < conf->peers->number; i++) {
- conf->peers->peer[i].weight = 1;
- conf->peers->peer[i].max_fails = conf->upstream.max_fails;
- conf->peers->peer[i].fail_timeout = conf->upstream.fail_timeout;
- }
- }
-
return NGX_CONF_OK;
}
@@ -602,16 +583,14 @@
ngx_memzero(&u, sizeof(ngx_url_t));
u.url = value[1];
- u.uri_part = 1;
+ u.no_resolve = 1;
+ /* u.uri_part = 1; may be used as namespace */
- if (ngx_parse_url(cf, &u) != NGX_OK) {
- if (u.err) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "%s in \"%V\"", u.err, &u.url);
- }
+ lcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
+ if (lcf->upstream.upstream == NULL) {
+ return NGX_CONF_ERROR;
}
- lcf->peers = u.peers;
lcf->upstream.schema.len = sizeof("memcached://") - 1;
lcf->upstream.schema.data = (u_char *) "memcached://";
@@ -627,3 +606,29 @@
return NGX_CONF_OK;
}
+
+
+static char *
+ngx_http_memcached_upstream_max_fails_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf)
+{
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"memcached_upstream_max_fails\" is not supported, "
+ "use the \"max_fails\" parameter of the \"server\" directive ",
+ "inside the \"upstream\" block");
+
+ return NGX_CONF_ERROR;
+}
+
+
+static char *
+ngx_http_memcached_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf)
+{
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"memcached_upstream_fail_timeout\" is not supported, "
+ "use the \"fail_timeout\" parameter of the \"server\" directive ",
+ "inside the \"upstream\" block");
+
+ return NGX_CONF_ERROR;
+}
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index f17f0a7..2095f6a 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -35,8 +35,6 @@
typedef struct {
ngx_http_upstream_conf_t upstream;
- ngx_http_upstream_srv_conf_t *upstream_peers;
-
ngx_array_t *flushes;
ngx_array_t *body_set_len;
ngx_array_t *body_set;
@@ -107,6 +105,11 @@
static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
+static char *ngx_http_proxy_upstream_max_fails_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf);
+static char *ngx_http_proxy_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf);
+
static ngx_conf_post_t ngx_http_proxy_lowat_post =
{ ngx_http_proxy_lowat_check };
@@ -297,16 +300,16 @@
{ ngx_string("proxy_upstream_max_fails"),
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_proxy_loc_conf_t, upstream.max_fails),
+ ngx_http_proxy_upstream_max_fails_unsupported,
+ 0,
+ 0,
NULL },
{ ngx_string("proxy_upstream_fail_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_sec_slot,
- NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_proxy_loc_conf_t, upstream.fail_timeout),
+ ngx_http_proxy_upstream_fail_timeout_unsupported,
+ 0,
+ 0,
NULL },
{ ngx_string("proxy_pass_header"),
@@ -419,8 +422,6 @@
u->peer.log = r->connection->log;
u->peer.log_error = NGX_ERROR_ERR;
- u->peer.peers = plcf->upstream_peers->peers;
- u->peer.tries = plcf->upstream_peers->peers->number;
#if (NGX_THREADS)
u->peer.lock = &r->connection->lock;
#endif
@@ -1498,9 +1499,6 @@
conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
- conf->upstream.max_fails = NGX_CONF_UNSET_UINT;
- conf->upstream.fail_timeout = NGX_CONF_UNSET;
-
conf->upstream.pass_request_headers = NGX_CONF_UNSET;
conf->upstream.pass_request_body = NGX_CONF_UNSET;
@@ -1527,7 +1525,6 @@
uintptr_t *code;
ngx_str_t *header;
ngx_uint_t i, j;
- ngx_peer_t *peer;
ngx_array_t hide_headers;
ngx_keyval_t *src, *s, *h;
ngx_hash_key_t *hk;
@@ -1660,24 +1657,6 @@
|NGX_HTTP_UPSTREAM_FT_OFF;
}
- ngx_conf_merge_uint_value(conf->upstream.max_fails,
- prev->upstream.max_fails, 1);
-
- ngx_conf_merge_sec_value(conf->upstream.fail_timeout,
- prev->upstream.fail_timeout, 10);
-
- if (conf->upstream_peers) {
- peer = conf->upstream_peers->peers->peer;
- for (i = 0; i < conf->upstream_peers->peers->number; i++) {
- ngx_conf_init_uint_value(peer[i].weight, 1);
- peer[i].current_weight = peer[i].weight;
- ngx_conf_init_uint_value(peer[i].max_fails,
- conf->upstream.max_fails);
- ngx_conf_init_value(peer[i].fail_timeout,
- conf->upstream.fail_timeout);
- }
- }
-
ngx_conf_merge_path_value(conf->upstream.temp_path,
prev->upstream.temp_path,
NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0,
@@ -1834,8 +1813,8 @@
peers:
- if (conf->upstream_peers == NULL) {
- conf->upstream_peers = prev->upstream_peers;
+ if (conf->upstream.upstream == NULL) {
+ conf->upstream.upstream = prev->upstream.upstream;
conf->host_header = prev->host_header;
conf->port_text = prev->port_text;
@@ -2180,11 +2159,11 @@
u.url.len = url->len - add;
u.url.data = url->data + add;
u.default_portn = port;
+ u.no_resolve = 1;
u.uri_part = 1;
- u.upstream = 1;
- plcf->upstream_peers = ngx_http_upstream_add(cf, &u);
- if (plcf->upstream_peers == NULL) {
+ plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
+ if (plcf->upstream.upstream == NULL) {
return NGX_CONF_ERROR;
}
@@ -2345,3 +2324,29 @@
return NGX_CONF_OK;
}
+
+
+static char *
+ngx_http_proxy_upstream_max_fails_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf)
+{
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"proxy_upstream_max_fails\" is not supported, "
+ "use the \"max_fails\" parameter of the \"server\" directive ",
+ "inside the \"upstream\" block");
+
+ return NGX_CONF_ERROR;
+}
+
+
+static char *
+ngx_http_proxy_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
+ ngx_command_t *cmd, void *conf)
+{
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"proxy_upstream_fail_timeout\" is not supported, "
+ "use the \"fail_timeout\" parameter of the \"server\" directive ",
+ "inside the \"upstream\" block");
+
+ return NGX_CONF_ERROR;
+}
diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c
new file mode 100644
index 0000000..1de019e
--- /dev/null
+++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c
@@ -0,0 +1,228 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+ /* the round robin data must be first */
+ ngx_http_upstream_rr_peer_data_t rrp;
+
+ ngx_uint_t hash;
+
+ /* AF_INET only */
+ u_char addr[3];
+
+ u_char tries;
+
+ ngx_event_get_peer_pt get_rr_peer;
+} ngx_http_upstream_ip_hash_peer_data_t;
+
+
+static ngx_int_t ngx_http_upstream_init_ip_hash_peer(ngx_http_request_t *r,
+ ngx_http_upstream_srv_conf_t *us);
+static ngx_int_t ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc,
+ void *data);
+static char *ngx_http_upstream_ip_hash(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+
+
+static ngx_command_t ngx_http_upstream_ip_hash_commands[] = {
+
+ { ngx_string("ip_hash"),
+ NGX_HTTP_UPS_CONF|NGX_CONF_NOARGS,
+ ngx_http_upstream_ip_hash,
+ 0,
+ 0,
+ NULL },
+
+ ngx_null_command
+};
+
+
+static ngx_http_module_t ngx_http_upstream_ip_hash_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_upstream_ip_hash_module = {
+ NGX_MODULE_V1,
+ &ngx_http_upstream_ip_hash_module_ctx, /* module context */
+ ngx_http_upstream_ip_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
+};
+
+
+ngx_int_t
+ngx_http_upstream_init_ip_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_ip_hash_peer;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_init_ip_hash_peer(ngx_http_request_t *r,
+ ngx_http_upstream_srv_conf_t *us)
+{
+ struct sockaddr_in *sin;
+ ngx_http_upstream_ip_hash_peer_data_t *iphp;
+
+ iphp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_ip_hash_peer_data_t));
+ if (iphp == NULL) {
+ return NGX_ERROR;
+ }
+
+ r->upstream->peer.data = &iphp->rrp;
+
+ if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ r->upstream->peer.get = ngx_http_upstream_get_ip_hash_peer;
+
+ /* AF_INET only */
+ sin = (struct sockaddr_in *) r->connection->sockaddr;
+ iphp->addr[0] = (u_char) ((sin->sin_addr.s_addr >> 24) & 0xff);
+ iphp->addr[1] = (u_char) ((sin->sin_addr.s_addr >> 16) & 0xff);
+ iphp->addr[2] = (u_char) ((sin->sin_addr.s_addr >> 8) & 0xff);
+
+ iphp->hash = 89;
+ iphp->tries = 0;
+ iphp->get_rr_peer = ngx_http_upstream_get_round_robin_peer;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
+{
+ ngx_http_upstream_ip_hash_peer_data_t *iphp = data;
+
+ time_t now;
+ uintptr_t m;
+ ngx_uint_t i, n, p, hash;
+ ngx_http_upstream_rr_peer_t *peer;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+ "get ip hash peer, try: %ui", pc->tries);
+
+ /* TODO: cached */
+
+ if (iphp->tries > 20 || iphp->rrp.peers->number == 1) {
+ return iphp->get_rr_peer(pc, &iphp->rrp);
+ }
+
+ now = ngx_time();
+
+ pc->cached = 0;
+ pc->connection = NULL;
+
+ hash = iphp->hash;
+
+ for ( ;; ) {
+
+ for (i = 0; i < 3; i++) {
+ hash = (hash * 113 + iphp->addr[i]) % 6271;
+ }
+
+ p = hash % iphp->rrp.peers->number;
+
+ n = p / (8 * sizeof(uintptr_t));
+ m = 1 << p % (8 * sizeof(uintptr_t));
+
+ if (!(iphp->rrp.tried[n] & m)) {
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+ "get ip hash peer, hash: %ui %04XA", p, m);
+
+ peer = &iphp->rrp.peers->peer[p];
+
+ /* ngx_lock_mutex(iphp->rrp.peers->mutex); */
+
+ if (!peer->down) {
+
+ if (peer->max_fails == 0 || peer->fails < peer->max_fails) {
+ break;
+ }
+
+ if (now - peer->accessed > peer->fail_timeout) {
+ peer->fails = 0;
+ break;
+ }
+
+ } else {
+ iphp->rrp.tried[n] |= m;
+ }
+
+ /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */
+
+ pc->tries--;
+ }
+
+ if (++iphp->tries >= 20) {
+ return iphp->get_rr_peer(pc, &iphp->rrp);
+ }
+ }
+
+ pc->sockaddr = peer->sockaddr;
+ pc->socklen = peer->socklen;
+ pc->name = &peer->name;
+#if (NGX_SSL)
+ pc->ssl_session = peer->ssl_session;
+#endif
+
+ /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */
+
+ iphp->rrp.tried[n] |= m;
+ iphp->hash = hash;
+
+ return NGX_OK;
+}
+
+
+static char *
+ngx_http_upstream_ip_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_upstream_srv_conf_t *uscf;
+
+ uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
+
+ uscf->peer.init_upstream = ngx_http_upstream_init_ip_hash;
+
+ uscf->flags = NGX_HTTP_UPSTREAM_CREATE
+ |NGX_HTTP_UPSTREAM_MAX_FAILS
+ |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
+ |NGX_HTTP_UPSTREAM_DOWN;
+
+ return NGX_CONF_OK;
+}
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h
index df97610..96a310f 100644
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -32,6 +32,7 @@
#include <ngx_http_variables.h>
#include <ngx_http_request.h>
#include <ngx_http_upstream.h>
+#include <ngx_http_upstream_round_robin.h>
#include <ngx_http_config.h>
#include <ngx_http_busy_lock.h>
#include <ngx_http_core_module.h>
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index bbd0255..8a86f2e 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -2409,9 +2409,9 @@
ngx_http_log_error_handler(ngx_http_request_t *r, ngx_http_request_t *sr,
u_char *buf, size_t len)
{
- u_char *p;
- ngx_http_upstream_t *u;
- ngx_peer_connection_t *peer;
+ char *uri_separator;
+ u_char *p;
+ ngx_http_upstream_t *u;
if (r->server_name.data) {
p = ngx_snprintf(buf, len, ", server: %V", &r->server_name);
@@ -2451,14 +2451,19 @@
u = sr->upstream;
- if (u) {
- peer = &u->peer;
+ if (u && u->peer.name) {
+
+ uri_separator = "";
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+ if (u->peer.sockaddr && u->peer.sockaddr->sa_family == AF_UNIX) {
+ uri_separator = ":";
+ }
+#endif
p = ngx_snprintf(buf, len, ", upstream: \"%V%V%s%V\"",
- &u->conf->schema,
- &peer->peers->peer[peer->cur_peer].name,
- peer->peers->peer[peer->cur_peer].uri_separator,
- &u->uri);
+ &u->conf->schema, u->peer.name,
+ uri_separator, &u->uri);
len -= p - buf;
buf = p;
}
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 4e653d0..da1c9ad 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -87,8 +87,6 @@
static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *,
ngx_http_upstream_t *u, ngx_connection_t *c);
static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c);
-static void ngx_http_upstream_ssl_shutdown(ngx_connection_t *c,
- ngx_peer_t *peer);
#endif
@@ -215,7 +213,7 @@
NULL },
{ ngx_string("server"),
- NGX_HTTP_UPS_CONF|NGX_CONF_TAKE12,
+ NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,
ngx_http_upstream_server,
NGX_HTTP_SRV_CONF_OFFSET,
0,
@@ -308,12 +306,15 @@
u->request_bufs = r->request_body->bufs;
}
- if (u->create_request(r) != NGX_OK) {
+ if (u->conf->upstream->peer.init(r, u->conf->upstream) != NGX_OK) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
- u->peer.log = r->connection->log;
+ if (u->create_request(r) != NGX_OK) {
+ ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return;
+ }
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
@@ -326,7 +327,7 @@
u->writer.pool = r->pool;
- if (ngx_array_init(&u->states, r->pool, u->peer.peers->number,
+ if (ngx_array_init(&u->states, r->pool, 1,
sizeof(ngx_http_upstream_state_t))
!= NGX_OK)
{
@@ -528,7 +529,7 @@
return;
}
- u->state->peer = &u->peer.peers->peer[u->peer.cur_peer].name;
+ u->state->peer = u->peer.name;
if (rc == NGX_BUSY) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams");
@@ -617,8 +618,7 @@
ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r,
ngx_http_upstream_t *u, ngx_connection_t *c)
{
- ngx_int_t rc;
- ngx_peer_t *peer;
+ ngx_int_t rc;
if (ngx_ssl_create_connection(u->conf->ssl, c,
NGX_SSL_BUFFER|NGX_SSL_CLIENT)
@@ -632,9 +632,7 @@
c->sendfile = 0;
u->output.sendfile = 0;
- peer = &u->peer.peers->peer[u->peer.cur_peer];
-
- if (ngx_ssl_set_session(c, peer->ssl_session) != NGX_OK) {
+ if (ngx_ssl_set_session(c, u->peer.ssl_session) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
@@ -664,6 +662,8 @@
if (c->ssl->handshaked) {
+ u->peer.save_session(&u->peer, u->peer.data);
+
c->write->handler = ngx_http_upstream_send_request_handler;
c->read->handler = ngx_http_upstream_process_header;
@@ -972,7 +972,7 @@
}
n = u->peer.connection->recv(u->peer.connection, u->buffer.last,
- u->buffer.end - u->buffer.last);
+ u->buffer.end - u->buffer.last);
if (n == NGX_AGAIN) {
#if 0
@@ -1585,7 +1585,7 @@
ngx_buf_t *b;
ngx_int_t rc;
ngx_uint_t do_write;
- ngx_connection_t *c, *client;
+ ngx_connection_t *c, *downstream, *upstream;
ngx_http_request_t *r;
ngx_http_upstream_t *u;
ngx_http_core_loc_conf_t *clcf;
@@ -1618,7 +1618,8 @@
return;
}
- client = r->connection;
+ downstream = r->connection;
+ upstream = u->peer.connection;
b = &u->buffer;
@@ -1633,7 +1634,7 @@
if (u->out_bufs || u->busy_bufs) {
rc = ngx_http_output_filter(r, u->out_bufs);
- if (client->destroyed) {
+ if (downstream->destroyed) {
return;
}
@@ -1649,8 +1650,8 @@
if (u->busy_bufs == NULL) {
if (u->length == 0
- || u->peer.connection->read->eof
- || u->peer.connection->read->error)
+ || upstream->read->eof
+ || upstream->read->error)
{
ngx_http_upstream_finalize_request(r, u, 0);
return;
@@ -1667,9 +1668,9 @@
size = u->length;
}
- if (size && u->peer.connection->read->ready) {
+ if (size && upstream->read->ready) {
- n = u->peer.connection->recv(u->peer.connection, b->last, size);
+ n = upstream->recv(upstream, b->last, size);
if (n == NGX_AGAIN) {
break;
@@ -1690,8 +1691,8 @@
break;
}
- if (client->data == r) {
- if (ngx_handle_write_event(client->write, clcf->send_lowat)
+ if (downstream->data == r) {
+ if (ngx_handle_write_event(downstream->write, clcf->send_lowat)
== NGX_ERROR)
{
ngx_http_upstream_finalize_request(r, u, 0);
@@ -1699,23 +1700,23 @@
}
}
- if (client->write->active) {
- ngx_add_timer(client->write, clcf->send_timeout);
+ if (downstream->write->active) {
+ ngx_add_timer(downstream->write, clcf->send_timeout);
- } else if (client->write->timer_set) {
- ngx_del_timer(client->write);
+ } else if (downstream->write->timer_set) {
+ ngx_del_timer(downstream->write);
}
- if (ngx_handle_read_event(u->peer.connection->read, 0) == NGX_ERROR) {
+ if (ngx_handle_read_event(upstream->read, 0) == NGX_ERROR) {
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
- if (u->peer.connection->read->active) {
- ngx_add_timer(u->peer.connection->read, u->conf->read_timeout);
+ if (upstream->read->active) {
+ ngx_add_timer(upstream->read, u->conf->read_timeout);
- } else if (u->peer.connection->read->timer_set) {
- ngx_del_timer(u->peer.connection->read);
+ } else if (upstream->read->timer_set) {
+ ngx_del_timer(upstream->read);
}
}
@@ -1922,22 +1923,22 @@
ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
ngx_uint_t ft_type)
{
- ngx_uint_t status, down;
+ ngx_uint_t status, state;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "http next upstream, %xD", ft_type);
+ "http next upstream, %xi", ft_type);
#if 0
ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
#endif
if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) {
- down = 0;
+ state = NGX_PEER_NEXT;
} else {
- down = 1;
+ state = NGX_PEER_FAILED;
}
- ngx_event_connect_peer_failed(&u->peer, down);
+ u->peer.free(&u->peer, u->peer.data, state);
if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT,
@@ -2003,11 +2004,15 @@
"close http upstream connection: %d",
u->peer.connection->fd);
#if (NGX_HTTP_SSL)
+
if (u->peer.connection->ssl) {
- ngx_http_upstream_ssl_shutdown(u->peer.connection,
- &u->peer.peers->peer[u->peer.cur_peer]);
+ u->peer.connection->ssl->no_wait_shutdown = 1;
+ u->peer.connection->ssl->no_send_shutdown = 1;
+
+ (void) ngx_ssl_shutdown(u->peer.connection);
}
#endif
+
ngx_close_connection(u->peer.connection);
}
@@ -2054,19 +2059,32 @@
u->finalize_request(r, rc);
+ u->peer.free(&u->peer, u->peer.data, 0);
+
if (u->peer.connection) {
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "close http upstream connection: %d",
- u->peer.connection->fd);
+
#if (NGX_HTTP_SSL)
/* TODO: do not shutdown persistent connection */
if (u->peer.connection->ssl) {
- ngx_http_upstream_ssl_shutdown(u->peer.connection,
- &u->peer.peers->peer[u->peer.cur_peer]);
+
+ /*
+ * We send the "close notify" shutdown alert to the upstream only
+ * and do not wait its "close notify" shutdown alert.
+ * It is acceptable according to the TLS standard.
+ */
+
+ u->peer.connection->ssl->no_wait_shutdown = 1;
+
+ (void) ngx_ssl_shutdown(u->peer.connection);
}
#endif
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "close http upstream connection: %d",
+ u->peer.connection->fd);
+
ngx_close_connection(u->peer.connection);
}
@@ -2105,35 +2123,6 @@
}
-#if (NGX_HTTP_SSL)
-
-static void
-ngx_http_upstream_ssl_shutdown(ngx_connection_t *c, ngx_peer_t *peer)
-{
- /* lock peer mutex */
-
- if (peer->ssl_session) {
- ngx_ssl_free_session(peer->ssl_session);
- }
-
- peer->ssl_session = ngx_ssl_get_session(c);
-
- /* unlock peer mutex */
-
- /*
- * We send the "close notify" shutdown alert to the upstream only
- * and do not wait its "close notify" shutdown alert.
- * It is acceptable according to the TLS standard.
- */
-
- c->ssl->no_wait_shutdown = 1;
-
- (void) ngx_ssl_shutdown(c);
-}
-
-#endif
-
-
static ngx_int_t
ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
@@ -2595,31 +2584,41 @@
static char *
ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
{
- char *rv;
- void *mconf;
- ngx_str_t *value;
- ngx_url_t u;
- ngx_uint_t i, j, m, n;
- ngx_conf_t pcf;
- ngx_peers_t **peers;
- ngx_http_module_t *module;
- ngx_http_conf_ctx_t *ctx;
- ngx_http_upstream_srv_conf_t *uscf;
+ char *rv;
+ void *mconf;
+ ngx_str_t *value;
+ ngx_url_t u;
+ ngx_uint_t m;
+ ngx_conf_t pcf;
+ ngx_http_module_t *module;
+ ngx_http_conf_ctx_t *ctx, *http_ctx;
+ ngx_http_upstream_srv_conf_t *uscf;
+
+ ngx_memzero(&u, sizeof(ngx_url_t));
+
+ value = cf->args->elts;
+ u.host = value[1];
+ u.upstream = 1;
+ u.no_resolve = 1;
+
+ uscf = ngx_http_upstream_add(cf, &u, NGX_HTTP_UPSTREAM_CREATE
+ |NGX_HTTP_UPSTREAM_WEIGHT
+ |NGX_HTTP_UPSTREAM_MAX_FAILS
+ |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
+ |NGX_HTTP_UPSTREAM_DOWN
+ |NGX_HTTP_UPSTREAM_BACKUP);
+ if (uscf == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}
- ngx_memzero(&u, sizeof(ngx_url_t));
-
- value = cf->args->elts;
- u.host = value[1];
-
- uscf = ngx_http_upstream_add(cf, &u);
- if (uscf == NULL) {
- return NGX_CONF_ERROR;
- }
+ http_ctx = cf->ctx;
+ ctx->main_conf = http_ctx->main_conf;
/* the upstream{}'s srv_conf */
@@ -2630,6 +2629,8 @@
ctx->srv_conf[ngx_http_upstream_module.ctx_index] = uscf;
+ uscf->srv_conf = ctx->srv_conf;
+
/* the upstream{}'s loc_conf */
@@ -2645,6 +2646,15 @@
module = ngx_modules[m]->ctx;
+ if (module->create_srv_conf) {
+ mconf = module->create_srv_conf(cf);
+ if (mconf == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf;
+ }
+
if (module->create_loc_conf) {
mconf = module->create_loc_conf(cf);
if (mconf == NULL) {
@@ -2676,34 +2686,6 @@
return NGX_CONF_ERROR;
}
- peers = uscf->servers->elts;
-
- if (uscf->servers->nelts == 1) {
- uscf->peers = peers[0];
- }
-
- n = 0;
-
- for (i = 0; i < uscf->servers->nelts; i++) {
- n += peers[i]->number;
- }
-
- uscf->peers = ngx_pcalloc(cf->pool,
- sizeof(ngx_peers_t) + sizeof(ngx_peer_t) * (n - 1));
- if (uscf->peers == NULL) {
- return NGX_CONF_ERROR;
- }
-
- uscf->peers->number = n;
-
- n = 0;
-
- for (i = 0; i < uscf->servers->nelts; i++) {
- for (j = 0; j < peers[i]->number; j++) {
- uscf->peers->peer[n++] = peers[i]->peer[j];
- }
- }
-
return rv;
}
@@ -2713,24 +2695,28 @@
{
ngx_http_upstream_srv_conf_t *uscf = conf;
- ngx_str_t *value;
- ngx_url_t u;
- ngx_int_t weight;
- ngx_uint_t i;
- ngx_peers_t **peers;
+ time_t fail_timeout;
+ ngx_str_t *value, s;
+ ngx_url_t u;
+ ngx_int_t weight, max_fails;
+ ngx_uint_t i;
+ ngx_http_upstream_server_t *us;
if (uscf->servers == NULL) {
- uscf->servers = ngx_array_create(cf->pool, 4, sizeof(ngx_peers_t *));
+ uscf->servers = ngx_array_create(cf->pool, 4,
+ sizeof(ngx_http_upstream_server_t));
if (uscf->servers == NULL) {
return NGX_CONF_ERROR;
}
}
- peers = ngx_array_push(uscf->servers);
- if (peers == NULL) {
+ us = ngx_array_push(uscf->servers);
+ if (us == NULL) {
return NGX_CONF_ERROR;
}
+ ngx_memzero(us, sizeof(ngx_http_upstream_server_t));
+
value = cf->args->elts;
ngx_memzero(&u, sizeof(ngx_url_t));
@@ -2748,51 +2734,100 @@
}
weight = 1;
+ max_fails = 1;
+ fail_timeout = 10;
- if (cf->args->nelts == 3) {
+ for (i = 2; i < cf->args->nelts; i++) {
- value = &value[2];
+ if (ngx_strncmp(value[i].data, "weight=", 7) == 0) {
- if (ngx_strncmp(value->data, "weight=", 7) == 0) {
+ if (!(uscf->flags & NGX_HTTP_UPSTREAM_WEIGHT)) {
+ goto invalid;
+ }
- weight = ngx_atoi(&value->data[7], value->len - 7);
+ weight = ngx_atoi(&value[i].data[7], value[i].len - 7);
if (weight == NGX_ERROR || weight == 0) {
goto invalid;
}
- } else {
- goto invalid;
+ continue;
}
+
+ if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) {
+
+ if (!(uscf->flags & NGX_HTTP_UPSTREAM_MAX_FAILS)) {
+ goto invalid;
+ }
+
+ max_fails = ngx_atoi(&value[i].data[10], value[i].len - 10);
+
+ if (max_fails == NGX_ERROR) {
+ goto invalid;
+ }
+
+ continue;
+ }
+
+ if (ngx_strncmp(value[i].data, "fail_timeout=", 13) == 0) {
+
+ if (!(uscf->flags & NGX_HTTP_UPSTREAM_FAIL_TIMEOUT)) {
+ goto invalid;
+ }
+
+ s.len = value[i].len - 13;
+ s.data = &value[i].data[13];
+
+ fail_timeout = ngx_parse_time(&s, 1);
+
+ if (fail_timeout < 0) {
+ goto invalid;
+ }
+
+ continue;
+ }
+
+ if (ngx_strncmp(value[i].data, "down", 4) == 0) {
+
+ if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) {
+ goto invalid;
+ }
+
+ us->down = 1;
+
+ continue;
+ }
+
+ goto invalid;
}
- for (i = 0; i < u.peers->number; i++) {
- u.peers->peer[i].weight = weight;
- u.peers->peer[i].current_weight = weight;
- u.peers->peer[i].max_fails = NGX_CONF_UNSET_UINT;
- u.peers->peer[i].fail_timeout = NGX_CONF_UNSET;
- }
-
- *peers = u.peers;
+ us->addrs = u.addrs;
+ us->naddrs = u.naddrs;
+ us->weight = weight;
+ us->max_fails = max_fails;
+ us->fail_timeout = fail_timeout;
return NGX_CONF_OK;
invalid:
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", value);
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
ngx_http_upstream_srv_conf_t *
-ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u)
+ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags)
{
ngx_uint_t i;
+ ngx_http_upstream_server_t *us;
ngx_http_upstream_srv_conf_t *uscf, **uscfp;
ngx_http_upstream_main_conf_t *umcf;
- if (u->upstream) {
+ if (!(flags & NGX_HTTP_UPSTREAM_CREATE)) {
+
if (ngx_parse_url(cf, u) != NGX_OK) {
if (u->err) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -2801,17 +2836,6 @@
return NULL;
}
-
- if (u->peers) {
- uscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_srv_conf_t));
- if (uscf == NULL) {
- return NULL;
- }
-
- uscf->peers = u->peers;
-
- return uscf;
- }
}
umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);
@@ -2819,15 +2843,28 @@
uscfp = umcf->upstreams.elts;
for (i = 0; i < umcf->upstreams.nelts; i++) {
- if (uscfp[i]->host.len != u->host.len) {
+ if (uscfp[i]->host.len != u->host.len
+ || ngx_strncasecmp(uscfp[i]->host.data, u->host.data, u->host.len)
+ != 0)
+ {
continue;
}
- if (ngx_strncasecmp(uscfp[i]->host.data, u->host.data, u->host.len)
- == 0)
+ if ((flags & NGX_HTTP_UPSTREAM_CREATE)
+ && (uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE))
{
- return uscfp[i];
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate upstream \"%V\"", &u->host);
+ return NULL;
}
+
+ if (uscfp[i]->port == 0 && u->portn && !u->no_port) {
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "upstream \"%V\" port %d is ignored",
+ &u->host, u->portn);
+ }
+
+ return uscfp[i];
}
uscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_srv_conf_t));
@@ -2835,10 +2872,29 @@
return NULL;
}
+ uscf->flags = flags;
uscf->host = u->host;
uscf->file_name = cf->conf_file->file.name;
uscf->line = cf->conf_file->line;
- uscf->port = u->default_portn;
+ uscf->port = u->portn;
+
+ if (u->naddrs == 1) {
+ uscf->servers = ngx_array_create(cf->pool, 1,
+ sizeof(ngx_http_upstream_server_t));
+ if (uscf->servers == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ us = ngx_array_push(uscf->servers);
+ if (us == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ ngx_memzero(us, sizeof(ngx_http_upstream_server_t));
+
+ us->addrs = u->addrs;
+ us->naddrs = u->naddrs;
+ }
uscfp = ngx_array_push(&umcf->upstreams);
if (uscfp == NULL) {
@@ -2881,32 +2937,25 @@
ngx_array_t headers_in;
ngx_hash_key_t *hk;
ngx_hash_init_t hash;
+ ngx_http_upstream_init_pt init;
ngx_http_upstream_header_t *header;
ngx_http_upstream_srv_conf_t **uscfp;
uscfp = umcf->upstreams.elts;
for (i = 0; i < umcf->upstreams.nelts; i++) {
- if (uscfp[i]->peers) {
- continue;
- }
- uscfp[i]->peers = ngx_inet_resolve_peer(cf, &uscfp[i]->host,
- uscfp[i]->port);
- if (uscfp[i]->peers == NULL) {
- return NGX_CONF_ERROR;
- }
+ init = uscfp[i]->peer.init_upstream ? uscfp[i]->peer.init_upstream:
+ ngx_http_upstream_init_round_robin;
- if (uscfp[i]->peers == NGX_CONF_ERROR) {
- ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
- "upstream host \"%V\" is not found in %s:%ui",
- &uscfp[i]->host, uscfp[i]->file_name.data,
- uscfp[i]->line);
+ if (init(cf, uscfp[i]) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
+ /* upstream_headers_in_hash */
+
if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t))
!= NGX_OK)
{
diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h
index 9831946..80c4d82 100644
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -44,23 +44,61 @@
typedef struct {
ngx_hash_t headers_in_hash;
ngx_array_t upstreams;
- /* ngx_http_upstream_srv_conf_t */
+ /* ngx_http_upstream_srv_conf_t */
} ngx_http_upstream_main_conf_t;
+typedef struct ngx_http_upstream_srv_conf_s ngx_http_upstream_srv_conf_t;
+
+typedef ngx_int_t (*ngx_http_upstream_init_pt)(ngx_conf_t *cf,
+ ngx_http_upstream_srv_conf_t *us);
+typedef ngx_int_t (*ngx_http_upstream_init_peer_pt)(ngx_http_request_t *r,
+ ngx_http_upstream_srv_conf_t *us);
+
typedef struct {
- ngx_peers_t *peers;
+ ngx_http_upstream_init_pt init_upstream;
+ ngx_http_upstream_init_peer_pt init;
+ void *data;
+} ngx_http_upstream_peer_t;
- ngx_array_t *servers;
+typedef struct {
+ ngx_peer_addr_t *addrs;
+ ngx_uint_t naddrs;
+ ngx_uint_t weight;
+ ngx_uint_t max_fails;
+ time_t fail_timeout;
+
+ unsigned down:1;
+ unsigned backup:1;
+} ngx_http_upstream_server_t;
+
+
+#define NGX_HTTP_UPSTREAM_CREATE 0x0001
+#define NGX_HTTP_UPSTREAM_WEIGHT 0x0002
+#define NGX_HTTP_UPSTREAM_MAX_FAILS 0x0004
+#define NGX_HTTP_UPSTREAM_FAIL_TIMEOUT 0x0008
+#define NGX_HTTP_UPSTREAM_DOWN 0x0010
+#define NGX_HTTP_UPSTREAM_BACKUP 0x0020
+
+
+struct ngx_http_upstream_srv_conf_s {
+ ngx_http_upstream_peer_t peer;
+ void **srv_conf;
+
+ ngx_array_t *servers; /* ngx_http_upstream_server_t */
+
+ ngx_uint_t flags;
ngx_str_t host;
ngx_str_t file_name;
ngx_uint_t line;
in_port_t port;
-} ngx_http_upstream_srv_conf_t;
+};
typedef struct {
+ ngx_http_upstream_srv_conf_t *upstream;
+
ngx_msec_t connect_timeout;
ngx_msec_t send_timeout;
ngx_msec_t read_timeout;
@@ -78,9 +116,6 @@
size_t temp_file_write_size_conf;
ngx_uint_t next_upstream;
- ngx_uint_t max_fails;
-
- time_t fail_timeout;
ngx_bufs_t bufs;
@@ -213,7 +248,11 @@
void ngx_http_upstream_init(ngx_http_request_t *r);
ngx_http_upstream_srv_conf_t *ngx_http_upstream_add(ngx_conf_t *cf,
- ngx_url_t *u);
+ ngx_url_t *u, ngx_uint_t flags);
+
+
+#define ngx_http_conf_upstream_srv_conf(uscf, module) \
+ uscf->srv_conf[module.ctx_index]
extern ngx_module_t ngx_http_upstream_module;
diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c
new file mode 100644
index 0000000..c7ec7ab
--- /dev/null
+++ b/src/http/ngx_http_upstream_round_robin.c
@@ -0,0 +1,430 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+ngx_int_t
+ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
+ ngx_http_upstream_srv_conf_t *us)
+{
+ ngx_url_t u;
+ ngx_uint_t i, j, n;
+ ngx_http_upstream_server_t *server;
+ ngx_http_upstream_rr_peers_t *peers;
+
+ us->peer.init = ngx_http_upstream_init_round_robin_peer;
+
+ if (us->servers) {
+ n = 0;
+ server = us->servers->elts;
+
+ for (i = 0; i < us->servers->nelts; i++) {
+ n += server[i].naddrs;
+ }
+
+ peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
+ + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
+ if (peers == NULL) {
+ return NGX_ERROR;
+ }
+
+ peers->number = n;
+ peers->name = &us->host;
+
+ n = 0;
+
+ for (i = 0; i < us->servers->nelts; i++) {
+ 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].current_weight = server[i].weight;
+ 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;
+ n++;
+ }
+ }
+
+ us->peer.data = peers;
+
+ return NGX_OK;
+ }
+
+
+ /* an upstream implicitly defined by proxy_pass, etc. */
+
+ ngx_memzero(&u, sizeof(ngx_url_t));
+
+ u.host = us->host;
+ u.portn = us->port;
+
+ if (ngx_inet_resolve_host(cf, &u) != NGX_OK) {
+ if (u.err) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "%s in upstream host \"%V\" is not found in %s:%ui",
+ u.err, &us->host, us->file_name.data, us->line);
+ }
+
+ return NGX_ERROR;
+ }
+
+ n = u.naddrs;
+
+ peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
+ + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
+ if (peers == NULL) {
+ return NGX_ERROR;
+ }
+
+ peers->number = n;
+ peers->name = &us->host;
+
+ n = 0;
+
+ for (i = 0; i < u.naddrs; i++) {
+ peers->peer[n].sockaddr = u.addrs[i].sockaddr;
+ peers->peer[n].socklen = u.addrs[i].socklen;
+ peers->peer[n].name = u.addrs[i].name;
+ peers->peer[n].weight = 1;
+ peers->peer[n].current_weight = 1;
+ peers->peer[n].max_fails = 1;
+ peers->peer[n].fail_timeout = 10;
+ n++;
+ }
+
+ us->peer.data = peers;
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
+ ngx_http_upstream_srv_conf_t *us)
+{
+ ngx_uint_t n;
+ ngx_http_upstream_rr_peer_data_t *rrp;
+
+ rrp = r->upstream->peer.data;
+
+ if (rrp == NULL) {
+ rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
+ if (rrp == NULL) {
+ return NGX_ERROR;
+ }
+
+ r->upstream->peer.data = rrp;
+ }
+
+ rrp->peers = us->peer.data;
+ rrp->current = 0;
+
+ if (rrp->peers->number <= 8 * sizeof(uintptr_t)) {
+ rrp->tried = &rrp->data;
+ rrp->data = 0;
+
+ } else {
+ n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
+ / (8 * sizeof(uintptr_t));
+
+ rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
+ if (rrp->tried == NULL) {
+ return NGX_ERROR;
+ }
+ }
+
+ r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
+ r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
+ r->upstream->peer.tries = rrp->peers->number;
+#if (NGX_HTTP_SSL)
+ r->upstream->peer.save_session = ngx_http_upstream_save_round_robin_peer;
+#endif
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
+{
+ ngx_http_upstream_rr_peer_data_t *rrp = data;
+
+ time_t now;
+ uintptr_t m;
+ ngx_uint_t i, n;
+ ngx_connection_t *c;
+ ngx_http_upstream_rr_peer_t *peer;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+ "get rr peer, try: %ui", pc->tries);
+
+ now = ngx_time();
+
+ /* ngx_lock_mutex(rrp->peers->mutex); */
+
+ if (rrp->peers->last_cached) {
+
+ /* cached connection */
+
+ c = rrp->peers->cached[rrp->peers->last_cached];
+ rrp->peers->last_cached--;
+
+ /* ngx_unlock_mutex(ppr->peers->mutex); */
+
+#if (NGX_THREADS)
+ c->read->lock = c->read->own_lock;
+ c->write->lock = c->write->own_lock;
+#endif
+
+ pc->connection = c;
+ pc->cached = 1;
+
+ return NGX_OK;
+ }
+
+ pc->cached = 0;
+ pc->connection = NULL;
+
+ if (rrp->peers->number == 1) {
+ peer = &rrp->peers->peer[0];
+
+ } else {
+
+ /* there are several peers */
+
+ if (pc->tries == rrp->peers->number) {
+
+ /* it's a first try - get a current peer */
+
+ for ( ;; ) {
+ rrp->current = rrp->peers->current;
+
+ n = rrp->current / (8 * sizeof(uintptr_t));
+ m = 1 << rrp->current % (8 * sizeof(uintptr_t));
+
+ if (!(rrp->tried[n] & m)) {
+ peer = &rrp->peers->peer[rrp->current];
+
+ if (!peer->down) {
+
+ if (peer->max_fails == 0
+ || peer->fails < peer->max_fails)
+ {
+ break;
+ }
+
+ if (now - peer->accessed > peer->fail_timeout) {
+ peer->fails = 0;
+ break;
+ }
+
+ } else {
+ rrp->tried[n] |= m;
+ }
+
+ pc->tries--;
+ }
+
+ rrp->peers->current++;
+
+ if (rrp->peers->current >= rrp->peers->number) {
+ rrp->peers->current = 0;
+ }
+
+ if (pc->tries) {
+ continue;
+ }
+
+ goto failed;
+ }
+
+ peer->current_weight--;
+
+ if (peer->current_weight == 0) {
+ peer->current_weight = peer->weight;
+
+ rrp->peers->current++;
+
+ if (rrp->peers->current >= rrp->peers->number) {
+ rrp->peers->current = 0;
+ }
+ }
+
+ } else {
+ for ( ;; ) {
+ n = rrp->current / (8 * sizeof(uintptr_t));
+ m = 1 << rrp->current % (8 * sizeof(uintptr_t));
+
+ if (!(rrp->tried[n] & m)) {
+
+ peer = &rrp->peers->peer[rrp->current];
+
+ if (!peer->down) {
+
+ if (peer->max_fails == 0
+ || peer->fails < peer->max_fails)
+ {
+ break;
+ }
+
+ if (now - peer->accessed > peer->fail_timeout) {
+ peer->fails = 0;
+ break;
+ }
+
+ } else {
+ rrp->tried[n] |= m;
+ }
+
+ pc->tries--;
+ }
+
+ rrp->current++;
+
+ if (rrp->current >= rrp->peers->number) {
+ rrp->current = 0;
+ }
+
+ if (pc->tries) {
+ continue;
+ }
+
+ goto failed;
+ }
+
+ peer->current_weight--;
+
+ if (peer->current_weight == 0) {
+ peer->current_weight = peer->weight;
+
+ if (rrp->current == rrp->peers->current) {
+ rrp->peers->current++;
+
+ if (rrp->peers->current >= rrp->peers->number) {
+ rrp->peers->current = 0;
+ }
+ }
+ }
+ }
+
+ rrp->tried[n] |= m;
+ }
+
+ pc->sockaddr = peer->sockaddr;
+ pc->socklen = peer->socklen;
+ pc->name = &peer->name;
+#if (NGX_SSL)
+ pc->ssl_session = peer->ssl_session;
+#endif
+
+ /* ngx_unlock_mutex(rrp->peers->mutex); */
+
+ return NGX_OK;
+
+failed:
+
+ /* all peers failed, mark them as live for quick recovery */
+
+ for (i = 0; i < rrp->peers->number; i++) {
+ rrp->peers->peer[i].fails = 0;
+ }
+
+ /* ngx_unlock_mutex(rrp->peers->mutex); */
+
+ pc->name = rrp->peers->name;
+
+ return NGX_BUSY;
+}
+
+
+void
+ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
+ ngx_uint_t state)
+{
+ ngx_http_upstream_rr_peer_data_t *rrp = data;
+
+ time_t now;
+ ngx_http_upstream_rr_peer_t *peer;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+ "free rr peer %ui %ui", pc->tries, state);
+
+ if (state == 0 && pc->tries == 0) {
+ return;
+ }
+
+ /* TODO: NGX_PEER_KEEPALIVE */
+
+ if (rrp->peers->number == 1) {
+ pc->tries = 0;
+ return;
+ }
+
+ if (state & NGX_PEER_FAILED) {
+ now = ngx_time();
+
+ peer = &rrp->peers->peer[rrp->current];
+
+ /* ngx_lock_mutex(rrp->peers->mutex); */
+
+ peer->fails++;
+ peer->accessed = now;
+
+ if (peer->current_weight > 1) {
+ peer->current_weight /= 2;
+ }
+
+ /* ngx_unlock_mutex(rrp->peers->mutex); */
+ }
+
+ rrp->current++;
+
+ if (rrp->current >= rrp->peers->number) {
+ rrp->current = 0;
+ }
+
+ if (pc->tries) {
+ pc->tries--;
+ }
+
+ /* ngx_unlock_mutex(rrp->peers->mutex); */
+}
+
+
+#if (NGX_HTTP_SSL)
+
+void
+ngx_http_upstream_save_round_robin_peer(ngx_peer_connection_t *pc, void *data)
+{
+ ngx_http_upstream_rr_peer_data_t *rrp = data;
+
+ ngx_ssl_session_t *ssl_session;
+ ngx_http_upstream_rr_peer_t *peer;
+
+ ssl_session = ngx_ssl_get_session(pc->connection);
+
+ if (ssl_session == NULL) {
+ return;
+ }
+
+ peer = &rrp->peers->peer[rrp->current];
+
+ /* ngx_lock_mutex(rrp->peers->mutex); */
+ peer->ssl_session = ssl_session;
+ /* ngx_unlock_mutex(rrp->peers->mutex); */
+
+ if (pc->ssl_session) {
+ /* TODO: may block */
+ ngx_ssl_free_session(pc->ssl_session);
+ }
+}
+
+#endif
diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h
new file mode 100644
index 0000000..0f7d84b
--- /dev/null
+++ b/src/http/ngx_http_upstream_round_robin.h
@@ -0,0 +1,77 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#ifndef _NGX_HTTP_UPSTREAM_ROUND_ROBIN_H_INCLUDED_
+#define _NGX_HTTP_UPSTREAM_ROUND_ROBIN_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+ struct sockaddr *sockaddr;
+ socklen_t socklen;
+ ngx_str_t name;
+
+ ngx_uint_t current_weight;
+ ngx_uint_t weight;
+
+ ngx_uint_t fails;
+ time_t accessed;
+
+ ngx_uint_t max_fails;
+ time_t fail_timeout;
+
+ ngx_uint_t down; /* unsigned down:1; */
+
+#if (NGX_SSL)
+ ngx_ssl_session_t *ssl_session;
+#endif
+} ngx_http_upstream_rr_peer_t;
+
+
+typedef struct {
+ ngx_uint_t current;
+
+ ngx_uint_t number;
+ ngx_uint_t last_cached;
+
+ /* ngx_mutex_t *mutex; */
+ ngx_connection_t **cached;
+
+ ngx_str_t *name;
+
+ ngx_http_upstream_rr_peer_t peer[1];
+} ngx_http_upstream_rr_peers_t;
+
+
+typedef struct {
+ ngx_http_upstream_rr_peers_t *peers;
+ ngx_uint_t current;
+ uintptr_t *tried;
+ uintptr_t data;
+} ngx_http_upstream_rr_peer_data_t;
+
+
+ngx_int_t ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
+ ngx_http_upstream_srv_conf_t *us);
+ngx_int_t ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
+ ngx_http_upstream_srv_conf_t *us);
+ngx_int_t ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc,
+ void *data);
+void ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc,
+ void *data, ngx_uint_t state);
+
+#if (NGX_HTTP_SSL)
+void ngx_http_upstream_save_round_robin_peer(ngx_peer_connection_t *pc,
+ void *data);
+#endif
+
+
+
+#endif /* _NGX_HTTP_UPSTREAM_ROUND_ROBIN_H_INCLUDED_ */