annotate src/stream/ngx_stream_upstream_least_conn_module.c @ 6133:af7eba90645d

Win32: shared memory base addresses and remapping. Two mechanisms are implemented to make it possible to store pointers in shared memory on Windows, in particular on Windows Vista and later versions with ASLR: - The ngx_shm_remap() function added to allow remapping of a shared memory zone to the address originally used for it in the master process. While important, it doesn't solve the problem by itself as in many cases it's not possible to use the address because of conflicts with other allocations. - We now create mappings at the same address in all processes by starting mappings at predefined addresses normally unused by newborn processes. These two mechanisms combined allow to use shared memory on Windows almost without problems, including reloads. Based on the patch by Sergey Brester: http://mailman.nginx.org/pipermail/nginx-devel/2015-April/006836.html
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 27 Apr 2015 18:25:42 +0300
parents 61d7ae76647d
children 68c106e6fa0a
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
6115
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
1
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
2 /*
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
3 * Copyright (C) Maxim Dounin
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
4 * Copyright (C) Nginx, Inc.
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
5 */
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
6
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
7
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
8 #include <ngx_config.h>
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
9 #include <ngx_core.h>
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
10 #include <ngx_stream.h>
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
11
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
12
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
13 static ngx_int_t ngx_stream_upstream_init_least_conn_peer(
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
14 ngx_stream_session_t *s, ngx_stream_upstream_srv_conf_t *us);
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
15 static ngx_int_t ngx_stream_upstream_get_least_conn_peer(
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
16 ngx_peer_connection_t *pc, void *data);
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
17 static char *ngx_stream_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd,
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
18 void *conf);
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
19
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
20
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
21 static ngx_command_t ngx_stream_upstream_least_conn_commands[] = {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
22
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
23 { ngx_string("least_conn"),
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
24 NGX_STREAM_UPS_CONF|NGX_CONF_NOARGS,
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
25 ngx_stream_upstream_least_conn,
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
26 0,
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
27 0,
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
28 NULL },
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
29
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
30 ngx_null_command
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
31 };
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
32
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
33
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
34 static ngx_stream_module_t ngx_stream_upstream_least_conn_module_ctx = {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
35 NULL, /* create main configuration */
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
36 NULL, /* init main configuration */
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
37
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
38 NULL, /* create server configuration */
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
39 NULL, /* merge server configuration */
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
40 };
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
41
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
42
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
43 ngx_module_t ngx_stream_upstream_least_conn_module = {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
44 NGX_MODULE_V1,
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
45 &ngx_stream_upstream_least_conn_module_ctx, /* module context */
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
46 ngx_stream_upstream_least_conn_commands, /* module directives */
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
47 NGX_STREAM_MODULE, /* module type */
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
48 NULL, /* init master */
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
49 NULL, /* init module */
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
50 NULL, /* init process */
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
51 NULL, /* init thread */
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
52 NULL, /* exit thread */
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
53 NULL, /* exit process */
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
54 NULL, /* exit master */
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
55 NGX_MODULE_V1_PADDING
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
56 };
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
57
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
58
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
59 static ngx_int_t
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
60 ngx_stream_upstream_init_least_conn(ngx_conf_t *cf,
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
61 ngx_stream_upstream_srv_conf_t *us)
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
62 {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
63 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, cf->log, 0,
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
64 "init least conn");
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
65
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
66 if (ngx_stream_upstream_init_round_robin(cf, us) != NGX_OK) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
67 return NGX_ERROR;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
68 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
69
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
70 us->peer.init = ngx_stream_upstream_init_least_conn_peer;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
71
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
72 return NGX_OK;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
73 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
74
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
75
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
76 static ngx_int_t
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
77 ngx_stream_upstream_init_least_conn_peer(ngx_stream_session_t *s,
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
78 ngx_stream_upstream_srv_conf_t *us)
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
79 {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
80 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
81 "init least conn peer");
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
82
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
83 if (ngx_stream_upstream_init_round_robin_peer(s, us) != NGX_OK) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
84 return NGX_ERROR;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
85 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
86
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
87 s->upstream->peer.get = ngx_stream_upstream_get_least_conn_peer;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
88
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
89 return NGX_OK;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
90 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
91
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
92
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
93 static ngx_int_t
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
94 ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
95 {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
96 ngx_stream_upstream_rr_peer_data_t *rrp = data;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
97
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
98 time_t now;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
99 uintptr_t m;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
100 ngx_int_t rc, total;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
101 ngx_uint_t i, n, p, many;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
102 ngx_stream_upstream_rr_peer_t *peer, *best;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
103 ngx_stream_upstream_rr_peers_t *peers;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
104
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
105 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0,
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
106 "get least conn peer, try: %ui", pc->tries);
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
107
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
108 if (rrp->peers->single) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
109 return ngx_stream_upstream_get_round_robin_peer(pc, rrp);
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
110 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
111
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
112 pc->connection = NULL;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
113
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
114 now = ngx_time();
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
115
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
116 peers = rrp->peers;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
117
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
118 ngx_stream_upstream_rr_peers_wlock(peers);
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
119
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
120 best = NULL;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
121 total = 0;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
122
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
123 #if (NGX_SUPPRESS_WARN)
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
124 many = 0;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
125 p = 0;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
126 #endif
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
127
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
128 for (peer = peers->peer, i = 0;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
129 peer;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
130 peer = peer->next, i++)
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
131 {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
132
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
133 n = i / (8 * sizeof(uintptr_t));
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
134 m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
135
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
136 if (rrp->tried[n] & m) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
137 continue;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
138 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
139
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
140 if (peer->down) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
141 continue;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
142 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
143
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
144 if (peer->max_fails
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
145 && peer->fails >= peer->max_fails
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
146 && now - peer->checked <= peer->fail_timeout)
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
147 {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
148 continue;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
149 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
150
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
151 /*
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
152 * select peer with least number of connections; if there are
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
153 * multiple peers with the same number of connections, select
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
154 * based on round-robin
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
155 */
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
156
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
157 if (best == NULL
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
158 || peer->conns * best->weight < best->conns * peer->weight)
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
159 {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
160 best = peer;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
161 many = 0;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
162 p = i;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
163
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
164 } else if (peer->conns * best->weight == best->conns * peer->weight) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
165 many = 1;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
166 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
167 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
168
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
169 if (best == NULL) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
170 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0,
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
171 "get least conn peer, no peer found");
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
172
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
173 goto failed;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
174 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
175
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
176 if (many) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
177 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0,
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
178 "get least conn peer, many");
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
179
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
180 for (peer = best, i = p;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
181 peer;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
182 peer = peer->next, i++)
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
183 {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
184 n = i / (8 * sizeof(uintptr_t));
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
185 m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t));
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
186
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
187 if (rrp->tried[n] & m) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
188 continue;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
189 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
190
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
191 if (peer->down) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
192 continue;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
193 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
194
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
195 if (peer->conns * best->weight != best->conns * peer->weight) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
196 continue;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
197 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
198
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
199 if (peer->max_fails
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
200 && peer->fails >= peer->max_fails
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
201 && now - peer->checked <= peer->fail_timeout)
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
202 {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
203 continue;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
204 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
205
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
206 peer->current_weight += peer->effective_weight;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
207 total += peer->effective_weight;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
208
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
209 if (peer->effective_weight < peer->weight) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
210 peer->effective_weight++;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
211 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
212
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
213 if (peer->current_weight > best->current_weight) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
214 best = peer;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
215 p = i;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
216 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
217 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
218 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
219
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
220 best->current_weight -= total;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
221
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
222 if (now - best->checked > best->fail_timeout) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
223 best->checked = now;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
224 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
225
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
226 pc->sockaddr = best->sockaddr;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
227 pc->socklen = best->socklen;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
228 pc->name = &best->name;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
229
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
230 best->conns++;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
231
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
232 rrp->current = best;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
233
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
234 n = p / (8 * sizeof(uintptr_t));
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
235 m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
236
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
237 rrp->tried[n] |= m;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
238
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
239 ngx_stream_upstream_rr_peers_unlock(peers);
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
240
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
241 return NGX_OK;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
242
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
243 failed:
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
244
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
245 if (peers->next) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
246 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0,
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
247 "get least conn peer, backup servers");
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
248
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
249 rrp->peers = peers->next;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
250
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
251 n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1))
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
252 / (8 * sizeof(uintptr_t));
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
253
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
254 for (i = 0; i < n; i++) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
255 rrp->tried[i] = 0;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
256 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
257
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
258 ngx_stream_upstream_rr_peers_unlock(peers);
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
259
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
260 rc = ngx_stream_upstream_get_least_conn_peer(pc, rrp);
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
261
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
262 if (rc != NGX_BUSY) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
263 return rc;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
264 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
265
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
266 ngx_stream_upstream_rr_peers_wlock(peers);
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
267 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
268
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
269 /* all peers failed, mark them as live for quick recovery */
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
270
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
271 for (peer = peers->peer; peer; peer = peer->next) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
272 peer->fails = 0;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
273 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
274
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
275 ngx_stream_upstream_rr_peers_unlock(peers);
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
276
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
277 pc->name = peers->name;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
278
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
279 return NGX_BUSY;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
280 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
281
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
282
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
283 static char *
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
284 ngx_stream_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
285 {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
286 ngx_stream_upstream_srv_conf_t *uscf;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
287
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
288 uscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_upstream_module);
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
289
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
290 if (uscf->peer.init_upstream) {
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
291 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
292 "load balancing method redefined");
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
293 }
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
294
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
295 uscf->peer.init_upstream = ngx_stream_upstream_init_least_conn;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
296
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
297 uscf->flags = NGX_STREAM_UPSTREAM_CREATE
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
298 |NGX_STREAM_UPSTREAM_WEIGHT
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
299 |NGX_STREAM_UPSTREAM_MAX_FAILS
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
300 |NGX_STREAM_UPSTREAM_FAIL_TIMEOUT
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
301 |NGX_STREAM_UPSTREAM_DOWN
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
302 |NGX_STREAM_UPSTREAM_BACKUP;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
303
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
304 return NGX_CONF_OK;
61d7ae76647d Stream: port from NGINX+.
Ruslan Ermilov <ru@nginx.com>
parents:
diff changeset
305 }