blob: 8d7046aded3609c45cce0999e5eb57342c89661d [file] [log] [blame]
Igor Sysoev3d2fd182006-12-04 16:46:13 +00001
2/*
3 * Copyright (C) Igor Sysoev
Maxim Konovalovf8d59e32012-01-18 15:07:43 +00004 * Copyright (C) Nginx, Inc.
Igor Sysoev3d2fd182006-12-04 16:46:13 +00005 */
6
7
8#include <ngx_config.h>
9#include <ngx_core.h>
10#include <ngx_http.h>
11
12
Roman Arutyunyancfc3db12014-09-12 18:50:46 +040013#define ngx_http_upstream_tries(p) ((p)->number \
14 + ((p)->next ? (p)->next->number : 0))
15
16
Maxim Dounin52327e02012-05-14 09:57:20 +000017static ngx_http_upstream_rr_peer_t *ngx_http_upstream_get_peer(
18 ngx_http_upstream_rr_peer_data_t *rrp);
Igor Sysoevd12a5712007-07-28 16:04:01 +000019
Igor Sysoev08b59752011-07-22 16:30:17 +000020#if (NGX_HTTP_SSL)
21
22static ngx_int_t ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc,
23 void *data);
24static void ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc,
25 void *data);
26
27#endif
28
Igor Sysoevd12a5712007-07-28 16:04:01 +000029
Igor Sysoev3d2fd182006-12-04 16:46:13 +000030ngx_int_t
31ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
32 ngx_http_upstream_srv_conf_t *us)
33{
34 ngx_url_t u;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +000035 ngx_uint_t i, j, n, w;
Igor Sysoev3d2fd182006-12-04 16:46:13 +000036 ngx_http_upstream_server_t *server;
Ruslan Ermilov0c957672015-04-10 14:48:36 +030037 ngx_http_upstream_rr_peer_t *peer, **peerp;
Igor Sysoev6876bcd2007-08-09 13:54:33 +000038 ngx_http_upstream_rr_peers_t *peers, *backup;
Igor Sysoev3d2fd182006-12-04 16:46:13 +000039
40 us->peer.init = ngx_http_upstream_init_round_robin_peer;
41
42 if (us->servers) {
Igor Sysoev3d2fd182006-12-04 16:46:13 +000043 server = us->servers->elts;
44
Igor Sysoev6876bcd2007-08-09 13:54:33 +000045 n = 0;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +000046 w = 0;
Igor Sysoev6876bcd2007-08-09 13:54:33 +000047
Igor Sysoev3d2fd182006-12-04 16:46:13 +000048 for (i = 0; i < us->servers->nelts; i++) {
Igor Sysoev6876bcd2007-08-09 13:54:33 +000049 if (server[i].backup) {
50 continue;
51 }
52
Igor Sysoev3d2fd182006-12-04 16:46:13 +000053 n += server[i].naddrs;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +000054 w += server[i].naddrs * server[i].weight;
Igor Sysoev3d2fd182006-12-04 16:46:13 +000055 }
56
Maxim Dounina5d4f662012-04-02 21:29:35 +000057 if (n == 0) {
58 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
59 "no servers in upstream \"%V\" in %s:%ui",
60 &us->host, us->file_name, us->line);
61 return NGX_ERROR;
62 }
63
Ruslan Ermilov0c957672015-04-10 14:48:36 +030064 peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
Igor Sysoev3d2fd182006-12-04 16:46:13 +000065 if (peers == NULL) {
66 return NGX_ERROR;
67 }
68
Ruslan Ermilov0c957672015-04-10 14:48:36 +030069 peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
70 if (peer == NULL) {
71 return NGX_ERROR;
72 }
73
Igor Sysoev6876bcd2007-08-09 13:54:33 +000074 peers->single = (n == 1);
Igor Sysoev3d2fd182006-12-04 16:46:13 +000075 peers->number = n;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +000076 peers->weighted = (w != n);
77 peers->total_weight = w;
Igor Sysoev3d2fd182006-12-04 16:46:13 +000078 peers->name = &us->host;
79
80 n = 0;
Ruslan Ermilov0c957672015-04-10 14:48:36 +030081 peerp = &peers->peer;
Igor Sysoev3d2fd182006-12-04 16:46:13 +000082
83 for (i = 0; i < us->servers->nelts; i++) {
Xiaochen Wang8f3dfde2013-10-21 18:20:32 +080084 if (server[i].backup) {
85 continue;
86 }
Igor Sysoev6876bcd2007-08-09 13:54:33 +000087
Xiaochen Wang8f3dfde2013-10-21 18:20:32 +080088 for (j = 0; j < server[i].naddrs; j++) {
Ruslan Ermilov20038ac2014-06-12 21:13:24 +040089 peer[n].sockaddr = server[i].addrs[j].sockaddr;
90 peer[n].socklen = server[i].addrs[j].socklen;
91 peer[n].name = server[i].addrs[j].name;
92 peer[n].weight = server[i].weight;
93 peer[n].effective_weight = server[i].weight;
94 peer[n].current_weight = 0;
95 peer[n].max_fails = server[i].max_fails;
96 peer[n].fail_timeout = server[i].fail_timeout;
97 peer[n].down = server[i].down;
98 peer[n].server = server[i].name;
Ruslan Ermilov0c957672015-04-10 14:48:36 +030099
100 *peerp = &peer[n];
101 peerp = &peer[n].next;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000102 n++;
103 }
104 }
105
106 us->peer.data = peers;
107
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000108 /* backup servers */
109
110 n = 0;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +0000111 w = 0;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000112
113 for (i = 0; i < us->servers->nelts; i++) {
114 if (!server[i].backup) {
115 continue;
116 }
117
118 n += server[i].naddrs;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +0000119 w += server[i].naddrs * server[i].weight;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000120 }
121
122 if (n == 0) {
123 return NGX_OK;
124 }
125
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300126 backup = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000127 if (backup == NULL) {
128 return NGX_ERROR;
129 }
130
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300131 peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
132 if (peer == NULL) {
133 return NGX_ERROR;
134 }
135
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000136 peers->single = 0;
137 backup->single = 0;
138 backup->number = n;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +0000139 backup->weighted = (w != n);
140 backup->total_weight = w;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000141 backup->name = &us->host;
142
143 n = 0;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300144 peerp = &backup->peer;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000145
146 for (i = 0; i < us->servers->nelts; i++) {
Xiaochen Wang8f3dfde2013-10-21 18:20:32 +0800147 if (!server[i].backup) {
148 continue;
149 }
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000150
Xiaochen Wang8f3dfde2013-10-21 18:20:32 +0800151 for (j = 0; j < server[i].naddrs; j++) {
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400152 peer[n].sockaddr = server[i].addrs[j].sockaddr;
153 peer[n].socklen = server[i].addrs[j].socklen;
154 peer[n].name = server[i].addrs[j].name;
155 peer[n].weight = server[i].weight;
156 peer[n].effective_weight = server[i].weight;
157 peer[n].current_weight = 0;
158 peer[n].max_fails = server[i].max_fails;
159 peer[n].fail_timeout = server[i].fail_timeout;
160 peer[n].down = server[i].down;
161 peer[n].server = server[i].name;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300162
163 *peerp = &peer[n];
164 peerp = &peer[n].next;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000165 n++;
166 }
167 }
168
169 peers->next = backup;
170
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000171 return NGX_OK;
172 }
173
174
175 /* an upstream implicitly defined by proxy_pass, etc. */
176
Ruslan Ermilova2a22912013-01-10 12:58:55 +0000177 if (us->port == 0) {
Igor Sysoevbf3aaac2006-12-12 16:46:16 +0000178 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
179 "no port in upstream \"%V\" in %s:%ui",
Igor Sysoev4b96baa2007-09-15 17:11:06 +0000180 &us->host, us->file_name, us->line);
Igor Sysoevbf3aaac2006-12-12 16:46:16 +0000181 return NGX_ERROR;
182 }
183
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000184 ngx_memzero(&u, sizeof(ngx_url_t));
185
186 u.host = us->host;
Ruslan Ermilova2a22912013-01-10 12:58:55 +0000187 u.port = us->port;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000188
Igor Sysoev7ed63ee2007-10-08 08:55:12 +0000189 if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000190 if (u.err) {
191 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
Igor Sysoev5d118d32006-12-11 08:59:30 +0000192 "%s in upstream \"%V\" in %s:%ui",
Igor Sysoev4b96baa2007-09-15 17:11:06 +0000193 u.err, &us->host, us->file_name, us->line);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000194 }
195
196 return NGX_ERROR;
197 }
198
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000199 n = u.naddrs;
200
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300201 peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t));
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000202 if (peers == NULL) {
203 return NGX_ERROR;
204 }
205
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300206 peer = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peer_t) * n);
207 if (peer == NULL) {
208 return NGX_ERROR;
209 }
210
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000211 peers->single = (n == 1);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000212 peers->number = n;
Maxim Dounin1ba6ecd2012-06-03 23:22:41 +0000213 peers->weighted = 0;
214 peers->total_weight = n;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000215 peers->name = &us->host;
216
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300217 peerp = &peers->peer;
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400218
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000219 for (i = 0; i < u.naddrs; i++) {
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400220 peer[i].sockaddr = u.addrs[i].sockaddr;
221 peer[i].socklen = u.addrs[i].socklen;
222 peer[i].name = u.addrs[i].name;
223 peer[i].weight = 1;
224 peer[i].effective_weight = 1;
225 peer[i].current_weight = 0;
226 peer[i].max_fails = 1;
227 peer[i].fail_timeout = 10;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300228 *peerp = &peer[i];
229 peerp = &peer[i].next;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000230 }
231
232 us->peer.data = peers;
233
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000234 /* implicitly defined upstream has no backup servers */
235
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000236 return NGX_OK;
237}
238
239
240ngx_int_t
241ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
242 ngx_http_upstream_srv_conf_t *us)
243{
244 ngx_uint_t n;
245 ngx_http_upstream_rr_peer_data_t *rrp;
246
247 rrp = r->upstream->peer.data;
248
249 if (rrp == NULL) {
250 rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
251 if (rrp == NULL) {
252 return NGX_ERROR;
253 }
254
255 r->upstream->peer.data = rrp;
256 }
257
258 rrp->peers = us->peer.data;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300259 rrp->current = NULL;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000260
Maxim Douninb7fcb432011-08-18 17:04:52 +0000261 n = rrp->peers->number;
262
263 if (rrp->peers->next && rrp->peers->next->number > n) {
264 n = rrp->peers->next->number;
265 }
266
267 if (n <= 8 * sizeof(uintptr_t)) {
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000268 rrp->tried = &rrp->data;
269 rrp->data = 0;
270
271 } else {
Maxim Douninb7fcb432011-08-18 17:04:52 +0000272 n = (n + (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t));
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000273
274 rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
275 if (rrp->tried == NULL) {
276 return NGX_ERROR;
277 }
278 }
279
280 r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
281 r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
Roman Arutyunyancfc3db12014-09-12 18:50:46 +0400282 r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000283#if (NGX_HTTP_SSL)
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000284 r->upstream->peer.set_session =
285 ngx_http_upstream_set_round_robin_peer_session;
286 r->upstream->peer.save_session =
287 ngx_http_upstream_save_round_robin_peer_session;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000288#endif
289
290 return NGX_OK;
291}
292
293
294ngx_int_t
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000295ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
296 ngx_http_upstream_resolved_t *ur)
297{
298 u_char *p;
299 size_t len;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400300 socklen_t socklen;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000301 ngx_uint_t i, n;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400302 struct sockaddr *sockaddr;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300303 ngx_http_upstream_rr_peer_t *peer, **peerp;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000304 ngx_http_upstream_rr_peers_t *peers;
305 ngx_http_upstream_rr_peer_data_t *rrp;
306
307 rrp = r->upstream->peer.data;
308
309 if (rrp == NULL) {
310 rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t));
311 if (rrp == NULL) {
312 return NGX_ERROR;
313 }
314
315 r->upstream->peer.data = rrp;
316 }
317
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300318 peers = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peers_t));
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000319 if (peers == NULL) {
320 return NGX_ERROR;
321 }
322
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300323 peer = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peer_t)
324 * ur->naddrs);
325 if (peer == NULL) {
326 return NGX_ERROR;
327 }
328
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000329 peers->single = (ur->naddrs == 1);
330 peers->number = ur->naddrs;
331 peers->name = &ur->host;
332
Igor Sysoev302cedc2008-12-23 19:35:12 +0000333 if (ur->sockaddr) {
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400334 peer[0].sockaddr = ur->sockaddr;
335 peer[0].socklen = ur->socklen;
336 peer[0].name = ur->host;
337 peer[0].weight = 1;
338 peer[0].effective_weight = 1;
339 peer[0].current_weight = 0;
340 peer[0].max_fails = 1;
341 peer[0].fail_timeout = 10;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300342 peers->peer = peer;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000343
Igor Sysoev302cedc2008-12-23 19:35:12 +0000344 } else {
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300345 peerp = &peers->peer;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000346
Igor Sysoev302cedc2008-12-23 19:35:12 +0000347 for (i = 0; i < ur->naddrs; i++) {
348
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400349 socklen = ur->addrs[i].socklen;
Igor Sysoev302cedc2008-12-23 19:35:12 +0000350
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400351 sockaddr = ngx_palloc(r->pool, socklen);
352 if (sockaddr == NULL) {
353 return NGX_ERROR;
354 }
355
356 ngx_memcpy(sockaddr, ur->addrs[i].sockaddr, socklen);
357
358 switch (sockaddr->sa_family) {
359#if (NGX_HAVE_INET6)
360 case AF_INET6:
361 ((struct sockaddr_in6 *) sockaddr)->sin6_port = htons(ur->port);
362 break;
363#endif
364 default: /* AF_INET */
365 ((struct sockaddr_in *) sockaddr)->sin_port = htons(ur->port);
366 }
367
368 p = ngx_pnalloc(r->pool, NGX_SOCKADDR_STRLEN);
Igor Sysoev302cedc2008-12-23 19:35:12 +0000369 if (p == NULL) {
370 return NGX_ERROR;
371 }
372
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400373 len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1);
Igor Sysoev302cedc2008-12-23 19:35:12 +0000374
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400375 peer[i].sockaddr = sockaddr;
376 peer[i].socklen = socklen;
377 peer[i].name.len = len;
378 peer[i].name.data = p;
379 peer[i].weight = 1;
380 peer[i].effective_weight = 1;
381 peer[i].current_weight = 0;
382 peer[i].max_fails = 1;
383 peer[i].fail_timeout = 10;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300384 *peerp = &peer[i];
385 peerp = &peer[i].next;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000386 }
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000387 }
388
389 rrp->peers = peers;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300390 rrp->current = NULL;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000391
392 if (rrp->peers->number <= 8 * sizeof(uintptr_t)) {
393 rrp->tried = &rrp->data;
394 rrp->data = 0;
395
396 } else {
397 n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
398 / (8 * sizeof(uintptr_t));
399
400 rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
401 if (rrp->tried == NULL) {
402 return NGX_ERROR;
403 }
404 }
405
406 r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer;
407 r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
Roman Arutyunyancfc3db12014-09-12 18:50:46 +0400408 r->upstream->peer.tries = ngx_http_upstream_tries(rrp->peers);
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000409#if (NGX_HTTP_SSL)
Igor Sysoev08b59752011-07-22 16:30:17 +0000410 r->upstream->peer.set_session = ngx_http_upstream_empty_set_session;
411 r->upstream->peer.save_session = ngx_http_upstream_empty_save_session;
Igor Sysoev96dd8af2007-11-27 13:34:13 +0000412#endif
413
414 return NGX_OK;
415}
416
417
418ngx_int_t
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000419ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
420{
421 ngx_http_upstream_rr_peer_data_t *rrp = data;
422
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000423 ngx_int_t rc;
424 ngx_uint_t i, n;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000425 ngx_http_upstream_rr_peer_t *peer;
426 ngx_http_upstream_rr_peers_t *peers;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000427
428 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
429 "get rr peer, try: %ui", pc->tries);
430
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000431 pc->cached = 0;
432 pc->connection = NULL;
433
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400434 peers = rrp->peers;
435
436 /* ngx_lock_mutex(peers->mutex); */
437
438 if (peers->single) {
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300439 peer = peers->peer;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000440
Ruslan Ermilov4d0d2b22012-11-16 12:18:05 +0000441 if (peer->down) {
442 goto failed;
443 }
444
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300445 rrp->current = peer;
446
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000447 } else {
448
449 /* there are several peers */
450
Maxim Dounin52327e02012-05-14 09:57:20 +0000451 peer = ngx_http_upstream_get_peer(rrp);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000452
Maxim Dounin52327e02012-05-14 09:57:20 +0000453 if (peer == NULL) {
454 goto failed;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000455 }
456
Maxim Dounin52327e02012-05-14 09:57:20 +0000457 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300458 "get rr peer, current: %p %i",
459 peer, peer->current_weight);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000460 }
461
462 pc->sockaddr = peer->sockaddr;
463 pc->socklen = peer->socklen;
464 pc->name = &peer->name;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000465
Ruslan Ermilov627a9dc2015-04-10 13:16:23 +0300466 peer->conns++;
467
Ruslan Ermilov20038ac2014-06-12 21:13:24 +0400468 /* ngx_unlock_mutex(peers->mutex); */
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000469
470 return NGX_OK;
471
472failed:
473
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000474 if (peers->next) {
475
476 /* ngx_unlock_mutex(peers->mutex); */
477
478 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "backup servers");
479
480 rrp->peers = peers->next;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000481
Valentin Bartenevdd46cc62012-12-25 08:02:21 +0000482 n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
483 / (8 * sizeof(uintptr_t));
484
Igor Sysoevcc076092007-08-14 13:35:52 +0000485 for (i = 0; i < n; i++) {
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000486 rrp->tried[i] = 0;
487 }
488
489 rc = ngx_http_upstream_get_round_robin_peer(pc, rrp);
490
491 if (rc != NGX_BUSY) {
492 return rc;
493 }
494
495 /* ngx_lock_mutex(peers->mutex); */
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000496 }
497
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000498 /* all peers failed, mark them as live for quick recovery */
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000499
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300500 for (peer = peers->peer; peer; peer = peer->next) {
501 peer->fails = 0;
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000502 }
503
504 /* ngx_unlock_mutex(peers->mutex); */
505
506 pc->name = peers->name;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000507
508 return NGX_BUSY;
509}
510
511
Maxim Dounin52327e02012-05-14 09:57:20 +0000512static ngx_http_upstream_rr_peer_t *
513ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
Igor Sysoevd12a5712007-07-28 16:04:01 +0000514{
Maxim Dounin52327e02012-05-14 09:57:20 +0000515 time_t now;
516 uintptr_t m;
517 ngx_int_t total;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300518 ngx_uint_t i, n, p;
Maxim Dounin52327e02012-05-14 09:57:20 +0000519 ngx_http_upstream_rr_peer_t *peer, *best;
Igor Sysoevd12a5712007-07-28 16:04:01 +0000520
Maxim Dounin52327e02012-05-14 09:57:20 +0000521 now = ngx_time();
Igor Sysoevd12a5712007-07-28 16:04:01 +0000522
Maxim Dounin52327e02012-05-14 09:57:20 +0000523 best = NULL;
524 total = 0;
Igor Sysoevd12a5712007-07-28 16:04:01 +0000525
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300526#if (NGX_SUPPRESS_WARN)
527 p = 0;
528#endif
529
530 for (peer = rrp->peers->peer, i = 0;
531 peer;
532 peer = peer->next, i++)
533 {
Igor Sysoevd12a5712007-07-28 16:04:01 +0000534
Maxim Dounin52327e02012-05-14 09:57:20 +0000535 n = i / (8 * sizeof(uintptr_t));
536 m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
Igor Sysoevd12a5712007-07-28 16:04:01 +0000537
Maxim Dounin52327e02012-05-14 09:57:20 +0000538 if (rrp->tried[n] & m) {
539 continue;
Igor Sysoevd12a5712007-07-28 16:04:01 +0000540 }
541
Maxim Dounin52327e02012-05-14 09:57:20 +0000542 if (peer->down) {
543 continue;
Maxim Dounin624fbe92011-08-18 16:52:38 +0000544 }
545
Maxim Dounin52327e02012-05-14 09:57:20 +0000546 if (peer->max_fails
547 && peer->fails >= peer->max_fails
548 && now - peer->checked <= peer->fail_timeout)
549 {
550 continue;
551 }
552
553 peer->current_weight += peer->effective_weight;
554 total += peer->effective_weight;
555
556 if (peer->effective_weight < peer->weight) {
557 peer->effective_weight++;
558 }
559
560 if (best == NULL || peer->current_weight > best->current_weight) {
561 best = peer;
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300562 p = i;
Igor Sysoevd12a5712007-07-28 16:04:01 +0000563 }
564 }
Maxim Dounin52327e02012-05-14 09:57:20 +0000565
566 if (best == NULL) {
567 return NULL;
568 }
569
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300570 rrp->current = best;
Maxim Dounin52327e02012-05-14 09:57:20 +0000571
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300572 n = p / (8 * sizeof(uintptr_t));
573 m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
Maxim Dounin52327e02012-05-14 09:57:20 +0000574
575 rrp->tried[n] |= m;
576
577 best->current_weight -= total;
Maxim Dounina1ab0dd2013-05-21 21:47:50 +0400578
579 if (now - best->checked > best->fail_timeout) {
580 best->checked = now;
581 }
Maxim Dounin52327e02012-05-14 09:57:20 +0000582
583 return best;
Igor Sysoevd12a5712007-07-28 16:04:01 +0000584}
585
586
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000587void
588ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
589 ngx_uint_t state)
590{
591 ngx_http_upstream_rr_peer_data_t *rrp = data;
592
593 time_t now;
594 ngx_http_upstream_rr_peer_t *peer;
595
596 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
597 "free rr peer %ui %ui", pc->tries, state);
598
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000599 /* TODO: NGX_PEER_KEEPALIVE */
600
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300601 peer = rrp->current;
Ruslan Ermilov627a9dc2015-04-10 13:16:23 +0300602
Igor Sysoev6876bcd2007-08-09 13:54:33 +0000603 if (rrp->peers->single) {
Ruslan Ermilov627a9dc2015-04-10 13:16:23 +0300604
605 peer->conns--;
606
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000607 pc->tries = 0;
608 return;
609 }
610
611 if (state & NGX_PEER_FAILED) {
612 now = ngx_time();
613
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000614 /* ngx_lock_mutex(rrp->peers->mutex); */
615
616 peer->fails++;
617 peer->accessed = now;
Maxim Douninb713e482011-10-12 14:22:48 +0000618 peer->checked = now;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000619
Igor Sysoev333723e2008-08-26 14:34:16 +0000620 if (peer->max_fails) {
Maxim Dounin52327e02012-05-14 09:57:20 +0000621 peer->effective_weight -= peer->weight / peer->max_fails;
Igor Sysoev333723e2008-08-26 14:34:16 +0000622 }
Igor Sysoevd12a5712007-07-28 16:04:01 +0000623
624 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300625 "free rr peer failed: %p %i",
626 peer, peer->effective_weight);
Igor Sysoevd12a5712007-07-28 16:04:01 +0000627
Maxim Dounin52327e02012-05-14 09:57:20 +0000628 if (peer->effective_weight < 0) {
629 peer->effective_weight = 0;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000630 }
631
632 /* ngx_unlock_mutex(rrp->peers->mutex); */
Maxim Douninb713e482011-10-12 14:22:48 +0000633
634 } else {
635
636 /* mark peer live if check passed */
637
638 if (peer->accessed < peer->checked) {
639 peer->fails = 0;
640 }
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000641 }
642
Ruslan Ermilov627a9dc2015-04-10 13:16:23 +0300643 peer->conns--;
644
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000645 if (pc->tries) {
646 pc->tries--;
647 }
648
649 /* ngx_unlock_mutex(rrp->peers->mutex); */
650}
651
652
653#if (NGX_HTTP_SSL)
654
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000655ngx_int_t
656ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
657 void *data)
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000658{
659 ngx_http_upstream_rr_peer_data_t *rrp = data;
660
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000661 ngx_int_t rc;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000662 ngx_ssl_session_t *ssl_session;
663 ngx_http_upstream_rr_peer_t *peer;
664
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300665 peer = rrp->current;
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000666
667 /* TODO: threads only mutex */
668 /* ngx_lock_mutex(rrp->peers->mutex); */
669
670 ssl_session = peer->ssl_session;
671
672 rc = ngx_ssl_set_session(pc->connection, ssl_session);
673
Piotr Sikorad224ed72014-07-06 16:41:14 -0700674 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
675 "set session: %p", ssl_session);
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000676
677 /* ngx_unlock_mutex(rrp->peers->mutex); */
678
679 return rc;
680}
681
682
683void
684ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
685 void *data)
686{
687 ngx_http_upstream_rr_peer_data_t *rrp = data;
688
689 ngx_ssl_session_t *old_ssl_session, *ssl_session;
690 ngx_http_upstream_rr_peer_t *peer;
691
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000692 ssl_session = ngx_ssl_get_session(pc->connection);
693
694 if (ssl_session == NULL) {
695 return;
696 }
697
Piotr Sikorad224ed72014-07-06 16:41:14 -0700698 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
699 "save session: %p", ssl_session);
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000700
Ruslan Ermilov0c957672015-04-10 14:48:36 +0300701 peer = rrp->current;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000702
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000703 /* TODO: threads only mutex */
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000704 /* ngx_lock_mutex(rrp->peers->mutex); */
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000705
706 old_ssl_session = peer->ssl_session;
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000707 peer->ssl_session = ssl_session;
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000708
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000709 /* ngx_unlock_mutex(rrp->peers->mutex); */
710
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000711 if (old_ssl_session) {
712
Piotr Sikorad224ed72014-07-06 16:41:14 -0700713 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
714 "old session: %p", old_ssl_session);
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000715
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000716 /* TODO: may block */
Igor Sysoev8b0a3d22007-07-10 21:04:37 +0000717
718 ngx_ssl_free_session(old_ssl_session);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000719 }
720}
721
Igor Sysoev08b59752011-07-22 16:30:17 +0000722
723static ngx_int_t
724ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc, void *data)
725{
726 return NGX_OK;
727}
728
729
730static void
731ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc, void *data)
732{
733 return;
734}
735
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000736#endif