Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_http_upstream_round_robin.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11 
12 
13 static ngx_http_upstream_rr_peer_t *ngx_http_upstream_get_peer(
15 
16 #if (NGX_HTTP_SSL)
17 
18 static ngx_int_t ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc,
19  void *data);
20 static void ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc,
21  void *data);
22 
23 #endif
24 
25 
29 {
30  ngx_url_t u;
31  ngx_uint_t i, j, n, w;
33  ngx_http_upstream_rr_peers_t *peers, *backup;
34 
36 
37  if (us->servers) {
38  server = us->servers->elts;
39 
40  n = 0;
41  w = 0;
42 
43  for (i = 0; i < us->servers->nelts; i++) {
44  if (server[i].backup) {
45  continue;
46  }
47 
48  n += server[i].naddrs;
49  w += server[i].naddrs * server[i].weight;
50  }
51 
52  if (n == 0) {
54  "no servers in upstream \"%V\" in %s:%ui",
55  &us->host, us->file_name, us->line);
56  return NGX_ERROR;
57  }
58 
59  peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
60  + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
61  if (peers == NULL) {
62  return NGX_ERROR;
63  }
64 
65  peers->single = (n == 1);
66  peers->number = n;
67  peers->weighted = (w != n);
68  peers->total_weight = w;
69  peers->name = &us->host;
70 
71  n = 0;
72 
73  for (i = 0; i < us->servers->nelts; i++) {
74  for (j = 0; j < server[i].naddrs; j++) {
75  if (server[i].backup) {
76  continue;
77  }
78 
79  peers->peer[n].sockaddr = server[i].addrs[j].sockaddr;
80  peers->peer[n].socklen = server[i].addrs[j].socklen;
81  peers->peer[n].name = server[i].addrs[j].name;
82  peers->peer[n].max_fails = server[i].max_fails;
83  peers->peer[n].fail_timeout = server[i].fail_timeout;
84  peers->peer[n].down = server[i].down;
85  peers->peer[n].weight = server[i].weight;
86  peers->peer[n].effective_weight = server[i].weight;
87  peers->peer[n].current_weight = 0;
88  n++;
89  }
90  }
91 
92  us->peer.data = peers;
93 
94  /* backup servers */
95 
96  n = 0;
97  w = 0;
98 
99  for (i = 0; i < us->servers->nelts; i++) {
100  if (!server[i].backup) {
101  continue;
102  }
103 
104  n += server[i].naddrs;
105  w += server[i].naddrs * server[i].weight;
106  }
107 
108  if (n == 0) {
109  return NGX_OK;
110  }
111 
112  backup = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
113  + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
114  if (backup == NULL) {
115  return NGX_ERROR;
116  }
117 
118  peers->single = 0;
119  backup->single = 0;
120  backup->number = n;
121  backup->weighted = (w != n);
122  backup->total_weight = w;
123  backup->name = &us->host;
124 
125  n = 0;
126 
127  for (i = 0; i < us->servers->nelts; i++) {
128  for (j = 0; j < server[i].naddrs; j++) {
129  if (!server[i].backup) {
130  continue;
131  }
132 
133  backup->peer[n].sockaddr = server[i].addrs[j].sockaddr;
134  backup->peer[n].socklen = server[i].addrs[j].socklen;
135  backup->peer[n].name = server[i].addrs[j].name;
136  backup->peer[n].weight = server[i].weight;
137  backup->peer[n].effective_weight = server[i].weight;
138  backup->peer[n].current_weight = 0;
139  backup->peer[n].max_fails = server[i].max_fails;
140  backup->peer[n].fail_timeout = server[i].fail_timeout;
141  backup->peer[n].down = server[i].down;
142  n++;
143  }
144  }
145 
146  peers->next = backup;
147 
148  return NGX_OK;
149  }
150 
151 
152  /* an upstream implicitly defined by proxy_pass, etc. */
153 
154  if (us->port == 0) {
156  "no port in upstream \"%V\" in %s:%ui",
157  &us->host, us->file_name, us->line);
158  return NGX_ERROR;
159  }
160 
161  ngx_memzero(&u, sizeof(ngx_url_t));
162 
163  u.host = us->host;
164  u.port = us->port;
165 
166  if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
167  if (u.err) {
169  "%s in upstream \"%V\" in %s:%ui",
170  u.err, &us->host, us->file_name, us->line);
171  }
172 
173  return NGX_ERROR;
174  }
175 
176  n = u.naddrs;
177 
178  peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
179  + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1));
180  if (peers == NULL) {
181  return NGX_ERROR;
182  }
183 
184  peers->single = (n == 1);
185  peers->number = n;
186  peers->weighted = 0;
187  peers->total_weight = n;
188  peers->name = &us->host;
189 
190  for (i = 0; i < u.naddrs; i++) {
191  peers->peer[i].sockaddr = u.addrs[i].sockaddr;
192  peers->peer[i].socklen = u.addrs[i].socklen;
193  peers->peer[i].name = u.addrs[i].name;
194  peers->peer[i].weight = 1;
195  peers->peer[i].effective_weight = 1;
196  peers->peer[i].current_weight = 0;
197  peers->peer[i].max_fails = 1;
198  peers->peer[i].fail_timeout = 10;
199  }
200 
201  us->peer.data = peers;
202 
203  /* implicitly defined upstream has no backup servers */
204 
205  return NGX_OK;
206 }
207 
208 
209 ngx_int_t
212 {
213  ngx_uint_t n;
215 
216  rrp = r->upstream->peer.data;
217 
218  if (rrp == NULL) {
220  if (rrp == NULL) {
221  return NGX_ERROR;
222  }
223 
224  r->upstream->peer.data = rrp;
225  }
226 
227  rrp->peers = us->peer.data;
228  rrp->current = 0;
229 
230  n = rrp->peers->number;
231 
232  if (rrp->peers->next && rrp->peers->next->number > n) {
233  n = rrp->peers->next->number;
234  }
235 
236  if (n <= 8 * sizeof(uintptr_t)) {
237  rrp->tried = &rrp->data;
238  rrp->data = 0;
239 
240  } else {
241  n = (n + (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t));
242 
243  rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
244  if (rrp->tried == NULL) {
245  return NGX_ERROR;
246  }
247  }
248 
251  r->upstream->peer.tries = rrp->peers->number;
252 #if (NGX_HTTP_SSL)
253  r->upstream->peer.set_session =
254  ngx_http_upstream_set_round_robin_peer_session;
255  r->upstream->peer.save_session =
256  ngx_http_upstream_save_round_robin_peer_session;
257 #endif
258 
259  return NGX_OK;
260 }
261 
262 
263 ngx_int_t
266 {
267  u_char *p;
268  size_t len;
269  ngx_uint_t i, n;
270  struct sockaddr_in *sin;
273 
274  rrp = r->upstream->peer.data;
275 
276  if (rrp == NULL) {
278  if (rrp == NULL) {
279  return NGX_ERROR;
280  }
281 
282  r->upstream->peer.data = rrp;
283  }
284 
285  peers = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peers_t)
286  + sizeof(ngx_http_upstream_rr_peer_t) * (ur->naddrs - 1));
287  if (peers == NULL) {
288  return NGX_ERROR;
289  }
290 
291  peers->single = (ur->naddrs == 1);
292  peers->number = ur->naddrs;
293  peers->name = &ur->host;
294 
295  if (ur->sockaddr) {
296  peers->peer[0].sockaddr = ur->sockaddr;
297  peers->peer[0].socklen = ur->socklen;
298  peers->peer[0].name = ur->host;
299  peers->peer[0].weight = 1;
300  peers->peer[0].effective_weight = 1;
301  peers->peer[0].current_weight = 0;
302  peers->peer[0].max_fails = 1;
303  peers->peer[0].fail_timeout = 10;
304 
305  } else {
306 
307  for (i = 0; i < ur->naddrs; i++) {
308 
309  len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1;
310 
311  p = ngx_pnalloc(r->pool, len);
312  if (p == NULL) {
313  return NGX_ERROR;
314  }
315 
316  len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p, NGX_INET_ADDRSTRLEN);
317  len = ngx_sprintf(&p[len], ":%d", ur->port) - p;
318 
319  sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in));
320  if (sin == NULL) {
321  return NGX_ERROR;
322  }
323 
324  sin->sin_family = AF_INET;
325  sin->sin_port = htons(ur->port);
326  sin->sin_addr.s_addr = ur->addrs[i];
327 
328  peers->peer[i].sockaddr = (struct sockaddr *) sin;
329  peers->peer[i].socklen = sizeof(struct sockaddr_in);
330  peers->peer[i].name.len = len;
331  peers->peer[i].name.data = p;
332  peers->peer[i].weight = 1;
333  peers->peer[i].effective_weight = 1;
334  peers->peer[i].current_weight = 0;
335  peers->peer[i].max_fails = 1;
336  peers->peer[i].fail_timeout = 10;
337  }
338  }
339 
340  rrp->peers = peers;
341  rrp->current = 0;
342 
343  if (rrp->peers->number <= 8 * sizeof(uintptr_t)) {
344  rrp->tried = &rrp->data;
345  rrp->data = 0;
346 
347  } else {
348  n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
349  / (8 * sizeof(uintptr_t));
350 
351  rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t));
352  if (rrp->tried == NULL) {
353  return NGX_ERROR;
354  }
355  }
356 
359  r->upstream->peer.tries = rrp->peers->number;
360 #if (NGX_HTTP_SSL)
361  r->upstream->peer.set_session = ngx_http_upstream_empty_set_session;
362  r->upstream->peer.save_session = ngx_http_upstream_empty_save_session;
363 #endif
364 
365  return NGX_OK;
366 }
367 
368 
369 ngx_int_t
371 {
373 
374  ngx_int_t rc;
375  ngx_uint_t i, n;
378 
380  "get rr peer, try: %ui", pc->tries);
381 
382  /* ngx_lock_mutex(rrp->peers->mutex); */
383 
384  pc->cached = 0;
385  pc->connection = NULL;
386 
387  if (rrp->peers->single) {
388  peer = &rrp->peers->peer[0];
389 
390  if (peer->down) {
391  goto failed;
392  }
393 
394  } else {
395 
396  /* there are several peers */
397 
398  peer = ngx_http_upstream_get_peer(rrp);
399 
400  if (peer == NULL) {
401  goto failed;
402  }
403 
405  "get rr peer, current: %ui %i",
406  rrp->current, peer->current_weight);
407  }
408 
409  pc->sockaddr = peer->sockaddr;
410  pc->socklen = peer->socklen;
411  pc->name = &peer->name;
412 
413  /* ngx_unlock_mutex(rrp->peers->mutex); */
414 
415  if (pc->tries == 1 && rrp->peers->next) {
416  pc->tries += rrp->peers->next->number;
417  }
418 
419  return NGX_OK;
420 
421 failed:
422 
423  peers = rrp->peers;
424 
425  if (peers->next) {
426 
427  /* ngx_unlock_mutex(peers->mutex); */
428 
429  ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "backup servers");
430 
431  rrp->peers = peers->next;
432  pc->tries = rrp->peers->number;
433 
434  n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
435  / (8 * sizeof(uintptr_t));
436 
437  for (i = 0; i < n; i++) {
438  rrp->tried[i] = 0;
439  }
440 
442 
443  if (rc != NGX_BUSY) {
444  return rc;
445  }
446 
447  /* ngx_lock_mutex(peers->mutex); */
448  }
449 
450  /* all peers failed, mark them as live for quick recovery */
451 
452  for (i = 0; i < peers->number; i++) {
453  peers->peer[i].fails = 0;
454  }
455 
456  /* ngx_unlock_mutex(peers->mutex); */
457 
458  pc->name = peers->name;
459 
460  return NGX_BUSY;
461 }
462 
463 
465 ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
466 {
467  time_t now;
468  uintptr_t m;
469  ngx_int_t total;
470  ngx_uint_t i, n;
471  ngx_http_upstream_rr_peer_t *peer, *best;
472 
473  now = ngx_time();
474 
475  best = NULL;
476  total = 0;
477 
478  for (i = 0; i < rrp->peers->number; i++) {
479 
480  n = i / (8 * sizeof(uintptr_t));
481  m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
482 
483  if (rrp->tried[n] & m) {
484  continue;
485  }
486 
487  peer = &rrp->peers->peer[i];
488 
489  if (peer->down) {
490  continue;
491  }
492 
493  if (peer->max_fails
494  && peer->fails >= peer->max_fails
495  && now - peer->checked <= peer->fail_timeout)
496  {
497  continue;
498  }
499 
500  peer->current_weight += peer->effective_weight;
501  total += peer->effective_weight;
502 
503  if (peer->effective_weight < peer->weight) {
504  peer->effective_weight++;
505  }
506 
507  if (best == NULL || peer->current_weight > best->current_weight) {
508  best = peer;
509  }
510  }
511 
512  if (best == NULL) {
513  return NULL;
514  }
515 
516  i = best - &rrp->peers->peer[0];
517 
518  rrp->current = i;
519 
520  n = i / (8 * sizeof(uintptr_t));
521  m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
522 
523  rrp->tried[n] |= m;
524 
525  best->current_weight -= total;
526 
527  if (now - best->checked > best->fail_timeout) {
528  best->checked = now;
529  }
530 
531  return best;
532 }
533 
534 
535 void
537  ngx_uint_t state)
538 {
540 
541  time_t now;
543 
545  "free rr peer %ui %ui", pc->tries, state);
546 
547  /* TODO: NGX_PEER_KEEPALIVE */
548 
549  if (rrp->peers->single) {
550  pc->tries = 0;
551  return;
552  }
553 
554  peer = &rrp->peers->peer[rrp->current];
555 
556  if (state & NGX_PEER_FAILED) {
557  now = ngx_time();
558 
559  /* ngx_lock_mutex(rrp->peers->mutex); */
560 
561  peer->fails++;
562  peer->accessed = now;
563  peer->checked = now;
564 
565  if (peer->max_fails) {
566  peer->effective_weight -= peer->weight / peer->max_fails;
567  }
568 
570  "free rr peer failed: %ui %i",
571  rrp->current, peer->effective_weight);
572 
573  if (peer->effective_weight < 0) {
574  peer->effective_weight = 0;
575  }
576 
577  /* ngx_unlock_mutex(rrp->peers->mutex); */
578 
579  } else {
580 
581  /* mark peer live if check passed */
582 
583  if (peer->accessed < peer->checked) {
584  peer->fails = 0;
585  }
586  }
587 
588  if (pc->tries) {
589  pc->tries--;
590  }
591 
592  /* ngx_unlock_mutex(rrp->peers->mutex); */
593 }
594 
595 
596 #if (NGX_HTTP_SSL)
597 
598 ngx_int_t
599 ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
600  void *data)
601 {
603 
604  ngx_int_t rc;
605  ngx_ssl_session_t *ssl_session;
607 
608  peer = &rrp->peers->peer[rrp->current];
609 
610  /* TODO: threads only mutex */
611  /* ngx_lock_mutex(rrp->peers->mutex); */
612 
613  ssl_session = peer->ssl_session;
614 
615  rc = ngx_ssl_set_session(pc->connection, ssl_session);
616 
618  "set session: %p:%d",
619  ssl_session, ssl_session ? ssl_session->references : 0);
620 
621  /* ngx_unlock_mutex(rrp->peers->mutex); */
622 
623  return rc;
624 }
625 
626 
627 void
628 ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
629  void *data)
630 {
632 
633  ngx_ssl_session_t *old_ssl_session, *ssl_session;
635 
636  ssl_session = ngx_ssl_get_session(pc->connection);
637 
638  if (ssl_session == NULL) {
639  return;
640  }
641 
643  "save session: %p:%d", ssl_session, ssl_session->references);
644 
645  peer = &rrp->peers->peer[rrp->current];
646 
647  /* TODO: threads only mutex */
648  /* ngx_lock_mutex(rrp->peers->mutex); */
649 
650  old_ssl_session = peer->ssl_session;
651  peer->ssl_session = ssl_session;
652 
653  /* ngx_unlock_mutex(rrp->peers->mutex); */
654 
655  if (old_ssl_session) {
656 
658  "old session: %p:%d",
659  old_ssl_session, old_ssl_session->references);
660 
661  /* TODO: may block */
662 
663  ngx_ssl_free_session(old_ssl_session);
664  }
665 }
666 
667 
668 static ngx_int_t
669 ngx_http_upstream_empty_set_session(ngx_peer_connection_t *pc, void *data)
670 {
671  return NGX_OK;
672 }
673 
674 
675 static void
676 ngx_http_upstream_empty_save_session(ngx_peer_connection_t *pc, void *data)
677 {
678  return;
679 }
680 
681 #endif