Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_http_upstream_ip_hash_module.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 typedef struct {
14  /* the round robin data must be first */
16 
18 
19  u_char addrlen;
20  u_char *addr;
21 
22  u_char tries;
23 
26 
27 
28 static ngx_int_t ngx_http_upstream_init_ip_hash_peer(ngx_http_request_t *r,
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"),
40  ngx_http_upstream_ip_hash,
41  0,
42  0,
43  NULL },
44 
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 
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 */
77 };
78 
79 
80 static u_char ngx_http_upstream_ip_hash_pseudo_addr[3];
81 
82 
83 static ngx_int_t
84 ngx_http_upstream_init_ip_hash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
85 {
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,
99 {
100  struct sockaddr_in *sin;
101 #if (NGX_HAVE_INET6)
102  struct sockaddr_in6 *sin6;
103 #endif
105 
107  if (iphp == NULL) {
108  return NGX_ERROR;
109  }
110 
111  r->upstream->peer.data = &iphp->rrp;
112 
114  return NGX_ERROR;
115  }
116 
117  r->upstream->peer.get = ngx_http_upstream_get_ip_hash_peer;
118 
119  switch (r->connection->sockaddr->sa_family) {
120 
121  case AF_INET:
122  sin = (struct sockaddr_in *) r->connection->sockaddr;
123  iphp->addr = (u_char *) &sin->sin_addr.s_addr;
124  iphp->addrlen = 3;
125  break;
126 
127 #if (NGX_HAVE_INET6)
128  case AF_INET6:
129  sin6 = (struct sockaddr_in6 *) r->connection->sockaddr;
130  iphp->addr = (u_char *) &sin6->sin6_addr.s6_addr;
131  iphp->addrlen = 16;
132  break;
133 #endif
134 
135  default:
136  iphp->addr = ngx_http_upstream_ip_hash_pseudo_addr;
137  iphp->addrlen = 3;
138  }
139 
140  iphp->hash = 89;
141  iphp->tries = 0;
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 {
152 
153  time_t now;
154  ngx_int_t w;
155  uintptr_t m;
156  ngx_uint_t i, n, p, hash;
158 
160  "get ip hash peer, try: %ui", pc->tries);
161 
162  /* TODO: cached */
163 
164  if (iphp->tries > 20 || iphp->rrp.peers->single) {
165  return iphp->get_rr_peer(pc, &iphp->rrp);
166  }
167 
168  now = ngx_time();
169 
170  pc->cached = 0;
171  pc->connection = NULL;
172 
173  hash = iphp->hash;
174 
175  for ( ;; ) {
176 
177  for (i = 0; i < iphp->addrlen; i++) {
178  hash = (hash * 113 + iphp->addr[i]) % 6271;
179  }
180 
181  if (!iphp->rrp.peers->weighted) {
182  p = hash % iphp->rrp.peers->number;
183 
184  } else {
185  w = hash % iphp->rrp.peers->total_weight;
186 
187  for (i = 0; i < iphp->rrp.peers->number; i++) {
188  w -= iphp->rrp.peers->peer[i].weight;
189  if (w < 0) {
190  break;
191  }
192  }
193 
194  p = i;
195  }
196 
197  n = p / (8 * sizeof(uintptr_t));
198  m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t));
199 
200  if (!(iphp->rrp.tried[n] & m)) {
201 
203  "get ip hash peer, hash: %ui %04XA", p, m);
204 
205  peer = &iphp->rrp.peers->peer[p];
206 
207  /* ngx_lock_mutex(iphp->rrp.peers->mutex); */
208 
209  if (!peer->down) {
210 
211  if (peer->max_fails == 0 || peer->fails < peer->max_fails) {
212  break;
213  }
214 
215  if (now - peer->checked > peer->fail_timeout) {
216  peer->checked = now;
217  break;
218  }
219  }
220 
221  iphp->rrp.tried[n] |= m;
222 
223  /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */
224 
225  pc->tries--;
226  }
227 
228  if (++iphp->tries >= 20) {
229  return iphp->get_rr_peer(pc, &iphp->rrp);
230  }
231  }
232 
233  iphp->rrp.current = p;
234 
235  pc->sockaddr = peer->sockaddr;
236  pc->socklen = peer->socklen;
237  pc->name = &peer->name;
238 
239  /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */
240 
241  iphp->rrp.tried[n] |= m;
242  iphp->hash = hash;
243 
244  return NGX_OK;
245 }
246 
247 
248 static char *
249 ngx_http_upstream_ip_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
250 {
252 
254 
255  if (uscf->peer.init_upstream) {
257  "load balancing method redefined");
258  }
259 
260  uscf->peer.init_upstream = ngx_http_upstream_init_ip_hash;
261 
267 
268  return NGX_CONF_OK;
269 }