aboutsummaryrefslogtreecommitdiff
path: root/src/http/ngx_http_upstream_round_robin.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/http/ngx_http_upstream_round_robin.c')
-rw-r--r--src/http/ngx_http_upstream_round_robin.c203
1 files changed, 193 insertions, 10 deletions
diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c
index 1f15fae50..cc1b6d1a2 100644
--- a/src/http/ngx_http_upstream_round_robin.c
+++ b/src/http/ngx_http_upstream_round_robin.c
@@ -32,10 +32,15 @@ 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, w, t;
+ ngx_uint_t i, j, n, r, w, t;
ngx_http_upstream_server_t *server;
ngx_http_upstream_rr_peer_t *peer, **peerp;
ngx_http_upstream_rr_peers_t *peers, *backup;
+#if (NGX_HTTP_UPSTREAM_ZONE)
+ ngx_uint_t resolve;
+ ngx_http_core_loc_conf_t *clcf;
+ ngx_http_upstream_rr_peer_t **rpeerp;
+#endif
us->peer.init = ngx_http_upstream_init_round_robin_peer;
@@ -43,14 +48,33 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
server = us->servers->elts;
n = 0;
+ r = 0;
w = 0;
t = 0;
+#if (NGX_HTTP_UPSTREAM_ZONE)
+ resolve = 0;
+#endif
+
for (i = 0; i < us->servers->nelts; i++) {
+
+#if (NGX_HTTP_UPSTREAM_ZONE)
+ if (server[i].host.len) {
+ resolve = 1;
+ }
+#endif
+
if (server[i].backup) {
continue;
}
+#if (NGX_HTTP_UPSTREAM_ZONE)
+ if (server[i].host.len) {
+ r++;
+ continue;
+ }
+#endif
+
n += server[i].naddrs;
w += server[i].naddrs * server[i].weight;
@@ -59,7 +83,53 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
}
}
- if (n == 0) {
+#if (NGX_HTTP_UPSTREAM_ZONE)
+ if (us->shm_zone) {
+
+ if (resolve && !(us->flags & NGX_HTTP_UPSTREAM_MODIFY)) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "load balancing method does not support"
+ " resolving names at run time in"
+ " upstream \"%V\" in %s:%ui",
+ &us->host, us->file_name, us->line);
+ return NGX_ERROR;
+ }
+
+ clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
+
+ us->resolver = clcf->resolver;
+ us->resolver_timeout = clcf->resolver_timeout;
+
+ /*
+ * Without "resolver_timeout" in http{}, the value is unset.
+ * Even if we set it in ngx_http_core_merge_loc_conf(), it's
+ * still dependent on the module order and unreliable.
+ */
+ ngx_conf_init_msec_value(us->resolver_timeout, 30000);
+
+ if (resolve
+ && (us->resolver == NULL
+ || us->resolver->connections.nelts == 0))
+ {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no resolver defined to resolve names"
+ " at run time in upstream \"%V\" in %s:%ui",
+ &us->host, us->file_name, us->line);
+ return NGX_ERROR;
+ }
+
+ } else if (resolve) {
+
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "resolving names at run time requires"
+ " upstream \"%V\" in %s:%ui"
+ " to be in shared memory",
+ &us->host, us->file_name, us->line);
+ return NGX_ERROR;
+ }
+#endif
+
+ if (n + r == 0) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no servers in upstream \"%V\" in %s:%ui",
&us->host, us->file_name, us->line);
@@ -71,7 +141,8 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
return NGX_ERROR;
}
- peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
+ peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t)
+ * (n + r));
if (peer == NULL) {
return NGX_ERROR;
}
@@ -86,11 +157,46 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
n = 0;
peerp = &peers->peer;
+#if (NGX_HTTP_UPSTREAM_ZONE)
+ rpeerp = &peers->resolve;
+#endif
+
for (i = 0; i < us->servers->nelts; i++) {
if (server[i].backup) {
continue;
}
+#if (NGX_HTTP_UPSTREAM_ZONE)
+ if (server[i].host.len) {
+
+ peer[n].host = ngx_pcalloc(cf->pool,
+ sizeof(ngx_http_upstream_host_t));
+ if (peer[n].host == NULL) {
+ return NGX_ERROR;
+ }
+
+ peer[n].host->name = server[i].host;
+
+ peer[n].sockaddr = server[i].addrs[0].sockaddr;
+ peer[n].socklen = server[i].addrs[0].socklen;
+ peer[n].name = server[i].addrs[0].name;
+ peer[n].weight = server[i].weight;
+ peer[n].effective_weight = server[i].weight;
+ peer[n].current_weight = 0;
+ peer[n].max_conns = server[i].max_conns;
+ 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;
+
+ *rpeerp = &peer[n];
+ rpeerp = &peer[n].next;
+ n++;
+
+ continue;
+ }
+#endif
+
for (j = 0; j < server[i].naddrs; j++) {
peer[n].sockaddr = server[i].addrs[j].sockaddr;
peer[n].socklen = server[i].addrs[j].socklen;
@@ -115,6 +221,7 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
/* backup servers */
n = 0;
+ r = 0;
w = 0;
t = 0;
@@ -123,6 +230,13 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
continue;
}
+#if (NGX_HTTP_UPSTREAM_ZONE)
+ if (server[i].host.len) {
+ r++;
+ continue;
+ }
+#endif
+
n += server[i].naddrs;
w += server[i].naddrs * server[i].weight;
@@ -131,7 +245,7 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
}
}
- if (n == 0) {
+ if (n + r == 0) {
return NGX_OK;
}
@@ -140,12 +254,16 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
return NGX_ERROR;
}
- peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
+ peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t)
+ * (n + r));
if (peer == NULL) {
return NGX_ERROR;
}
- peers->single = 0;
+ if (n > 0) {
+ peers->single = 0;
+ }
+
backup->single = 0;
backup->number = n;
backup->weighted = (w != n);
@@ -156,11 +274,46 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
n = 0;
peerp = &backup->peer;
+#if (NGX_HTTP_UPSTREAM_ZONE)
+ rpeerp = &backup->resolve;
+#endif
+
for (i = 0; i < us->servers->nelts; i++) {
if (!server[i].backup) {
continue;
}
+#if (NGX_HTTP_UPSTREAM_ZONE)
+ if (server[i].host.len) {
+
+ peer[n].host = ngx_pcalloc(cf->pool,
+ sizeof(ngx_http_upstream_host_t));
+ if (peer[n].host == NULL) {
+ return NGX_ERROR;
+ }
+
+ peer[n].host->name = server[i].host;
+
+ peer[n].sockaddr = server[i].addrs[0].sockaddr;
+ peer[n].socklen = server[i].addrs[0].socklen;
+ peer[n].name = server[i].addrs[0].name;
+ peer[n].weight = server[i].weight;
+ peer[n].effective_weight = server[i].weight;
+ peer[n].current_weight = 0;
+ peer[n].max_conns = server[i].max_conns;
+ 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;
+
+ *rpeerp = &peer[n];
+ rpeerp = &peer[n].next;
+ n++;
+
+ continue;
+ }
+#endif
+
for (j = 0; j < server[i].naddrs; j++) {
peer[n].sockaddr = server[i].addrs[j].sockaddr;
peer[n].socklen = server[i].addrs[j].socklen;
@@ -273,7 +426,12 @@ ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
rrp->peers = us->peer.data;
rrp->current = NULL;
- rrp->config = 0;
+
+ ngx_http_upstream_rr_peers_rlock(rrp->peers);
+
+#if (NGX_HTTP_UPSTREAM_ZONE)
+ rrp->config = rrp->peers->config ? *rrp->peers->config : 0;
+#endif
n = rrp->peers->number;
@@ -281,6 +439,10 @@ ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
n = rrp->peers->next->number;
}
+ r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers);
+
+ ngx_http_upstream_rr_peers_unlock(rrp->peers);
+
if (n <= 8 * sizeof(uintptr_t)) {
rrp->tried = &rrp->data;
rrp->data = 0;
@@ -296,7 +458,6 @@ ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
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 = ngx_http_upstream_tries(rrp->peers);
#if (NGX_HTTP_SSL)
r->upstream->peer.set_session =
ngx_http_upstream_set_round_robin_peer_session;
@@ -446,6 +607,12 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
peers = rrp->peers;
ngx_http_upstream_rr_peers_wlock(peers);
+#if (NGX_HTTP_UPSTREAM_ZONE)
+ if (peers->config && rrp->config != *peers->config) {
+ goto busy;
+ }
+#endif
+
if (peers->single) {
peer = peers->peer;
@@ -458,6 +625,7 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
}
rrp->current = peer;
+ ngx_http_upstream_rr_peer_ref(peers, peer);
} else {
@@ -510,6 +678,10 @@ failed:
ngx_http_upstream_rr_peers_wlock(peers);
}
+#if (NGX_HTTP_UPSTREAM_ZONE)
+busy:
+#endif
+
ngx_http_upstream_rr_peers_unlock(peers);
pc->name = peers->name;
@@ -580,6 +752,7 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
}
rrp->current = best;
+ ngx_http_upstream_rr_peer_ref(rrp->peers, best);
n = p / (8 * sizeof(uintptr_t));
m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
@@ -617,9 +790,16 @@ ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
if (rrp->peers->single) {
+ if (peer->fails) {
+ peer->fails = 0;
+ }
+
peer->conns--;
- ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
+ if (ngx_http_upstream_rr_peer_unref(rrp->peers, peer) == NGX_OK) {
+ ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
+ }
+
ngx_http_upstream_rr_peers_unlock(rrp->peers);
pc->tries = 0;
@@ -661,7 +841,10 @@ ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
peer->conns--;
- ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
+ if (ngx_http_upstream_rr_peer_unref(rrp->peers, peer) == NGX_OK) {
+ ngx_http_upstream_rr_peer_unlock(rrp->peers, peer);
+ }
+
ngx_http_upstream_rr_peers_unlock(rrp->peers);
if (pc->tries) {