Mercurial > hg > nginx-quic
annotate src/http/modules/ngx_http_upstream_ip_hash_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 | b6047abf5f30 |
children | f01ab2dbcfdc |
rev | line source |
---|---|
884 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4412 | 4 * Copyright (C) Nginx, Inc. |
884 | 5 */ |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_http.h> | |
11 | |
12 | |
13 typedef struct { | |
14 /* the round robin data must be first */ | |
15 ngx_http_upstream_rr_peer_data_t rrp; | |
16 | |
17 ngx_uint_t hash; | |
18 | |
4695
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
19 u_char addrlen; |
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
20 u_char *addr; |
884 | 21 |
22 u_char tries; | |
23 | |
24 ngx_event_get_peer_pt get_rr_peer; | |
25 } ngx_http_upstream_ip_hash_peer_data_t; | |
26 | |
27 | |
28 static ngx_int_t ngx_http_upstream_init_ip_hash_peer(ngx_http_request_t *r, | |
29 ngx_http_upstream_srv_conf_t *us); | |
30 static ngx_int_t ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, | |
31 void *data); | |
32 static char *ngx_http_upstream_ip_hash(ngx_conf_t *cf, ngx_command_t *cmd, | |
33 void *conf); | |
34 | |
35 | |
36 static ngx_command_t ngx_http_upstream_ip_hash_commands[] = { | |
37 | |
38 { ngx_string("ip_hash"), | |
39 NGX_HTTP_UPS_CONF|NGX_CONF_NOARGS, | |
40 ngx_http_upstream_ip_hash, | |
41 0, | |
42 0, | |
43 NULL }, | |
44 | |
45 ngx_null_command | |
46 }; | |
47 | |
48 | |
49 static ngx_http_module_t ngx_http_upstream_ip_hash_module_ctx = { | |
50 NULL, /* preconfiguration */ | |
51 NULL, /* postconfiguration */ | |
52 | |
53 NULL, /* create main configuration */ | |
54 NULL, /* init main configuration */ | |
55 | |
56 NULL, /* create server configuration */ | |
57 NULL, /* merge server configuration */ | |
58 | |
59 NULL, /* create location configuration */ | |
60 NULL /* merge location configuration */ | |
61 }; | |
62 | |
63 | |
64 ngx_module_t ngx_http_upstream_ip_hash_module = { | |
65 NGX_MODULE_V1, | |
66 &ngx_http_upstream_ip_hash_module_ctx, /* module context */ | |
67 ngx_http_upstream_ip_hash_commands, /* module directives */ | |
68 NGX_HTTP_MODULE, /* module type */ | |
69 NULL, /* init master */ | |
70 NULL, /* init module */ | |
71 NULL, /* init process */ | |
72 NULL, /* init thread */ | |
73 NULL, /* exit thread */ | |
74 NULL, /* exit process */ | |
75 NULL, /* exit master */ | |
76 NGX_MODULE_V1_PADDING | |
77 }; | |
78 | |
79 | |
4695
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
80 static u_char ngx_http_upstream_ip_hash_pseudo_addr[3]; |
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
81 |
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
82 |
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
83 static ngx_int_t |
884 | 84 ngx_http_upstream_init_ip_hash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) |
85 { | |
86 if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) { | |
87 return NGX_ERROR; | |
88 } | |
89 | |
90 us->peer.init = ngx_http_upstream_init_ip_hash_peer; | |
91 | |
92 return NGX_OK; | |
93 } | |
94 | |
95 | |
96 static ngx_int_t | |
97 ngx_http_upstream_init_ip_hash_peer(ngx_http_request_t *r, | |
98 ngx_http_upstream_srv_conf_t *us) | |
99 { | |
100 struct sockaddr_in *sin; | |
4695
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
101 #if (NGX_HAVE_INET6) |
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
102 struct sockaddr_in6 *sin6; |
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
103 #endif |
884 | 104 ngx_http_upstream_ip_hash_peer_data_t *iphp; |
105 | |
106 iphp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_ip_hash_peer_data_t)); | |
107 if (iphp == NULL) { | |
108 return NGX_ERROR; | |
109 } | |
110 | |
111 r->upstream->peer.data = &iphp->rrp; | |
112 | |
113 if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) { | |
114 return NGX_ERROR; | |
115 } | |
116 | |
117 r->upstream->peer.get = ngx_http_upstream_get_ip_hash_peer; | |
118 | |
4695
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
119 switch (r->connection->sockaddr->sa_family) { |
2512
2e91aecb9e57
a prelimiary IPv6 support, HTTP listen
Igor Sysoev <igor@sysoev.ru>
parents:
1418
diff
changeset
|
120 |
4695
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
121 case AF_INET: |
2512
2e91aecb9e57
a prelimiary IPv6 support, HTTP listen
Igor Sysoev <igor@sysoev.ru>
parents:
1418
diff
changeset
|
122 sin = (struct sockaddr_in *) r->connection->sockaddr; |
4695
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
123 iphp->addr = (u_char *) &sin->sin_addr.s_addr; |
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
124 iphp->addrlen = 3; |
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
125 break; |
2512
2e91aecb9e57
a prelimiary IPv6 support, HTTP listen
Igor Sysoev <igor@sysoev.ru>
parents:
1418
diff
changeset
|
126 |
4695
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
127 #if (NGX_HAVE_INET6) |
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
128 case AF_INET6: |
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
129 sin6 = (struct sockaddr_in6 *) r->connection->sockaddr; |
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
130 iphp->addr = (u_char *) &sin6->sin6_addr.s6_addr; |
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
131 iphp->addrlen = 16; |
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
132 break; |
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
133 #endif |
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
134 |
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
135 default: |
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
136 iphp->addr = ngx_http_upstream_ip_hash_pseudo_addr; |
441b2941a506
Added IPv6 support to ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
4655
diff
changeset
|
137 iphp->addrlen = 3; |
2512
2e91aecb9e57
a prelimiary IPv6 support, HTTP listen
Igor Sysoev <igor@sysoev.ru>
parents:
1418
diff
changeset
|
138 } |
884 | 139 |
140 iphp->hash = 89; | |
141 iphp->tries = 0; | |
142 iphp->get_rr_peer = ngx_http_upstream_get_round_robin_peer; | |
143 | |
144 return NGX_OK; | |
145 } | |
146 | |
147 | |
148 static ngx_int_t | |
149 ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data) | |
150 { | |
151 ngx_http_upstream_ip_hash_peer_data_t *iphp = data; | |
152 | |
153 time_t now; | |
4655
382c523d253a
Upstream: weights support in ip_hash balancer.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
154 ngx_int_t w; |
884 | 155 uintptr_t m; |
156 ngx_uint_t i, n, p, hash; | |
157 ngx_http_upstream_rr_peer_t *peer; | |
158 | |
159 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, | |
160 "get ip hash peer, try: %ui", pc->tries); | |
161 | |
162 /* TODO: cached */ | |
163 | |
6102 | 164 ngx_http_upstream_rr_peers_wlock(iphp->rrp.peers); |
165 | |
1418
acb1f441e7b2
update ip_hash to "backup" option
Igor Sysoev <igor@sysoev.ru>
parents:
1417
diff
changeset
|
166 if (iphp->tries > 20 || iphp->rrp.peers->single) { |
6102 | 167 ngx_http_upstream_rr_peers_unlock(iphp->rrp.peers); |
884 | 168 return iphp->get_rr_peer(pc, &iphp->rrp); |
169 } | |
170 | |
171 now = ngx_time(); | |
172 | |
173 pc->cached = 0; | |
174 pc->connection = NULL; | |
175 | |
176 hash = iphp->hash; | |
177 | |
178 for ( ;; ) { | |
179 | |
5359
2fda9065d0f4
Win32: Borland C compatibility fixes.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5173
diff
changeset
|
180 for (i = 0; i < (ngx_uint_t) iphp->addrlen; i++) { |
884 | 181 hash = (hash * 113 + iphp->addr[i]) % 6271; |
182 } | |
183 | |
6121
b6047abf5f30
Upstream: simplified ip_hash and hash peer selection code.
Ruslan Ermilov <ru@nginx.com>
parents:
6108
diff
changeset
|
184 w = hash % iphp->rrp.peers->total_weight; |
b6047abf5f30
Upstream: simplified ip_hash and hash peer selection code.
Ruslan Ermilov <ru@nginx.com>
parents:
6108
diff
changeset
|
185 peer = iphp->rrp.peers->peer; |
b6047abf5f30
Upstream: simplified ip_hash and hash peer selection code.
Ruslan Ermilov <ru@nginx.com>
parents:
6108
diff
changeset
|
186 p = 0; |
4655
382c523d253a
Upstream: weights support in ip_hash balancer.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
187 |
6121
b6047abf5f30
Upstream: simplified ip_hash and hash peer selection code.
Ruslan Ermilov <ru@nginx.com>
parents:
6108
diff
changeset
|
188 while (w >= peer->weight) { |
b6047abf5f30
Upstream: simplified ip_hash and hash peer selection code.
Ruslan Ermilov <ru@nginx.com>
parents:
6108
diff
changeset
|
189 w -= peer->weight; |
b6047abf5f30
Upstream: simplified ip_hash and hash peer selection code.
Ruslan Ermilov <ru@nginx.com>
parents:
6108
diff
changeset
|
190 peer = peer->next; |
b6047abf5f30
Upstream: simplified ip_hash and hash peer selection code.
Ruslan Ermilov <ru@nginx.com>
parents:
6108
diff
changeset
|
191 p++; |
4655
382c523d253a
Upstream: weights support in ip_hash balancer.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
192 } |
884 | 193 |
194 n = p / (8 * sizeof(uintptr_t)); | |
1416
ad2311c943a3
fix ip_hash on 64-bit platform
Igor Sysoev <igor@sysoev.ru>
parents:
1284
diff
changeset
|
195 m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); |
884 | 196 |
5486
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
197 if (iphp->rrp.tried[n] & m) { |
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
198 goto next; |
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
199 } |
884 | 200 |
5486
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
201 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, |
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
202 "get ip hash peer, hash: %ui %04XA", p, m); |
884 | 203 |
5486
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
204 if (peer->down) { |
6108
55dc5f7eb921
Upstream: get rid of questionable micro-optimization in ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
6102
diff
changeset
|
205 goto next; |
5486
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
206 } |
884 | 207 |
5486
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
208 if (peer->max_fails |
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
209 && peer->fails >= peer->max_fails |
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
210 && now - peer->checked <= peer->fail_timeout) |
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
211 { |
6108
55dc5f7eb921
Upstream: get rid of questionable micro-optimization in ip_hash.
Ruslan Ermilov <ru@nginx.com>
parents:
6102
diff
changeset
|
212 goto next; |
5486
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
213 } |
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
214 |
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
215 break; |
884 | 216 |
5486
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
217 next: |
884 | 218 |
5706
a2bf26774cd3
Upstream: fix tries check in ip_hash.
Roman Arutyunyan <arut@nginx.com>
parents:
5486
diff
changeset
|
219 if (++iphp->tries > 20) { |
6102 | 220 ngx_http_upstream_rr_peers_unlock(iphp->rrp.peers); |
884 | 221 return iphp->get_rr_peer(pc, &iphp->rrp); |
222 } | |
223 } | |
224 | |
6100
c44459611d91
Upstream: store peers as a linked list.
Ruslan Ermilov <ru@nginx.com>
parents:
6099
diff
changeset
|
225 iphp->rrp.current = peer; |
1417
b23a80f9a7b8
set current peer to use it in ngx_http_upstream_free_round_robin_peer()
Igor Sysoev <igor@sysoev.ru>
parents:
1416
diff
changeset
|
226 |
884 | 227 pc->sockaddr = peer->sockaddr; |
228 pc->socklen = peer->socklen; | |
229 pc->name = &peer->name; | |
230 | |
6099
6ff0ebd6fbf4
Upstream: track the number of active connections to upstreams.
Ruslan Ermilov <ru@nginx.com>
parents:
5706
diff
changeset
|
231 peer->conns++; |
6ff0ebd6fbf4
Upstream: track the number of active connections to upstreams.
Ruslan Ermilov <ru@nginx.com>
parents:
5706
diff
changeset
|
232 |
5486
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
233 if (now - peer->checked > peer->fail_timeout) { |
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
234 peer->checked = now; |
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
235 } |
741aa3fde496
Upstream: simplified peer selection loop in the "ip_hash" module.
Vladimir Homutov <vl@nginx.com>
parents:
5359
diff
changeset
|
236 |
6102 | 237 ngx_http_upstream_rr_peers_unlock(iphp->rrp.peers); |
884 | 238 |
239 iphp->rrp.tried[n] |= m; | |
240 iphp->hash = hash; | |
241 | |
242 return NGX_OK; | |
243 } | |
244 | |
245 | |
246 static char * | |
247 ngx_http_upstream_ip_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
248 { | |
249 ngx_http_upstream_srv_conf_t *uscf; | |
250 | |
251 uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); | |
252 | |
5173
5373be93c0be
Upstream: warn if multiple non-stackable balancers are installed.
Ruslan Ermilov <ru@nginx.com>
parents:
4695
diff
changeset
|
253 if (uscf->peer.init_upstream) { |
5373be93c0be
Upstream: warn if multiple non-stackable balancers are installed.
Ruslan Ermilov <ru@nginx.com>
parents:
4695
diff
changeset
|
254 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, |
5373be93c0be
Upstream: warn if multiple non-stackable balancers are installed.
Ruslan Ermilov <ru@nginx.com>
parents:
4695
diff
changeset
|
255 "load balancing method redefined"); |
5373be93c0be
Upstream: warn if multiple non-stackable balancers are installed.
Ruslan Ermilov <ru@nginx.com>
parents:
4695
diff
changeset
|
256 } |
5373be93c0be
Upstream: warn if multiple non-stackable balancers are installed.
Ruslan Ermilov <ru@nginx.com>
parents:
4695
diff
changeset
|
257 |
884 | 258 uscf->peer.init_upstream = ngx_http_upstream_init_ip_hash; |
259 | |
260 uscf->flags = NGX_HTTP_UPSTREAM_CREATE | |
4655
382c523d253a
Upstream: weights support in ip_hash balancer.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
261 |NGX_HTTP_UPSTREAM_WEIGHT |
884 | 262 |NGX_HTTP_UPSTREAM_MAX_FAILS |
263 |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT | |
264 |NGX_HTTP_UPSTREAM_DOWN; | |
265 | |
266 return NGX_CONF_OK; | |
267 } |