blob: 54569b0a27b2ea892c29fe0cd1d15fc523c97262 [file] [log] [blame]
Willy Tarreauf89c1872009-10-01 11:19:37 +02001/*
2 * Map-based load-balancing (RR and HASH)
3 *
4 * Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <common/compat.h>
14#include <common/config.h>
15#include <common/debug.h>
Willy Tarreau45cb4fb2009-10-26 21:10:04 +010016#include <eb32tree.h>
Willy Tarreauf89c1872009-10-01 11:19:37 +020017
18#include <types/global.h>
19#include <types/server.h>
20
21#include <proto/backend.h>
Christopher Faulet5b517552017-06-09 14:17:53 +020022#include <proto/lb_map.h>
Willy Tarreauf89c1872009-10-01 11:19:37 +020023#include <proto/proto_http.h>
24#include <proto/proto_tcp.h>
25#include <proto/queue.h>
26
Willy Tarreau1b877482018-08-21 19:44:53 +020027/* this function updates the map according to server <srv>'s new state.
28 *
29 * The server's lock must be held. The lbprm's lock will be used.
30 */
Willy Tarreauf89c1872009-10-01 11:19:37 +020031static void map_set_server_status_down(struct server *srv)
32{
33 struct proxy *p = srv->proxy;
34
Willy Tarreauc5150da2014-05-13 19:27:31 +020035 if (!srv_lb_status_changed(srv))
Willy Tarreauf89c1872009-10-01 11:19:37 +020036 return;
37
Emeric Brun52a91d32017-08-31 14:41:55 +020038 if (srv_willbe_usable(srv))
Willy Tarreauf89c1872009-10-01 11:19:37 +020039 goto out_update_state;
40
41 /* FIXME: could be optimized since we know what changed */
Willy Tarreau1b877482018-08-21 19:44:53 +020042 HA_SPIN_LOCK(LBPRM_LOCK, &p->lbprm.lock);
Willy Tarreauf89c1872009-10-01 11:19:37 +020043 recount_servers(p);
44 update_backend_weight(p);
Christopher Faulet5b517552017-06-09 14:17:53 +020045 recalc_server_map(p);
Willy Tarreau1b877482018-08-21 19:44:53 +020046 HA_SPIN_UNLOCK(LBPRM_LOCK, &p->lbprm.lock);
Willy Tarreauf89c1872009-10-01 11:19:37 +020047 out_update_state:
Willy Tarreauc5150da2014-05-13 19:27:31 +020048 srv_lb_commit_status(srv);
Willy Tarreauf89c1872009-10-01 11:19:37 +020049}
50
Willy Tarreau1b877482018-08-21 19:44:53 +020051/* This function updates the map according to server <srv>'s new state.
52 *
53 * The server's lock must be held. The lbprm's lock will be used.
54 */
Willy Tarreauf89c1872009-10-01 11:19:37 +020055static void map_set_server_status_up(struct server *srv)
56{
57 struct proxy *p = srv->proxy;
58
Willy Tarreauc5150da2014-05-13 19:27:31 +020059 if (!srv_lb_status_changed(srv))
Willy Tarreauf89c1872009-10-01 11:19:37 +020060 return;
61
Emeric Brun52a91d32017-08-31 14:41:55 +020062 if (!srv_willbe_usable(srv))
Willy Tarreauf89c1872009-10-01 11:19:37 +020063 goto out_update_state;
64
65 /* FIXME: could be optimized since we know what changed */
Willy Tarreau1b877482018-08-21 19:44:53 +020066 HA_SPIN_LOCK(LBPRM_LOCK, &p->lbprm.lock);
Willy Tarreauf89c1872009-10-01 11:19:37 +020067 recount_servers(p);
68 update_backend_weight(p);
Christopher Faulet5b517552017-06-09 14:17:53 +020069 recalc_server_map(p);
Willy Tarreau1b877482018-08-21 19:44:53 +020070 HA_SPIN_UNLOCK(LBPRM_LOCK, &p->lbprm.lock);
Willy Tarreauf89c1872009-10-01 11:19:37 +020071 out_update_state:
Willy Tarreauc5150da2014-05-13 19:27:31 +020072 srv_lb_commit_status(srv);
Willy Tarreauf89c1872009-10-01 11:19:37 +020073}
74
75/* This function recomputes the server map for proxy px. It relies on
76 * px->lbprm.tot_wact, tot_wbck, tot_used, tot_weight, so it must be
77 * called after recount_servers(). It also expects px->lbprm.map.srv
78 * to be allocated with the largest size needed. It updates tot_weight.
Willy Tarreau1b877482018-08-21 19:44:53 +020079 *
80 * The lbprm's lock must be held.
Willy Tarreauf89c1872009-10-01 11:19:37 +020081 */
82void recalc_server_map(struct proxy *px)
83{
84 int o, tot, flag;
85 struct server *cur, *best;
86
87 switch (px->lbprm.tot_used) {
88 case 0: /* no server */
Willy Tarreauf89c1872009-10-01 11:19:37 +020089 return;
Willy Tarreauf89c1872009-10-01 11:19:37 +020090 default:
91 tot = px->lbprm.tot_weight;
92 break;
93 }
94
95 /* here we *know* that we have some servers */
96 if (px->srv_act)
Willy Tarreauc93cd162014-05-13 15:54:22 +020097 flag = 0;
Willy Tarreauf89c1872009-10-01 11:19:37 +020098 else
Willy Tarreauc93cd162014-05-13 15:54:22 +020099 flag = SRV_F_BACKUP;
Willy Tarreauf89c1872009-10-01 11:19:37 +0200100
101 /* this algorithm gives priority to the first server, which means that
102 * it will respect the declaration order for equivalent weights, and
103 * that whatever the weights, the first server called will always be
104 * the first declared. This is an important asumption for the backup
105 * case, where we want the first server only.
106 */
107 for (cur = px->srv; cur; cur = cur->next)
108 cur->wscore = 0;
109
110 for (o = 0; o < tot; o++) {
111 int max = 0;
112 best = NULL;
113 for (cur = px->srv; cur; cur = cur->next) {
Willy Tarreau9943d312014-05-22 16:20:59 +0200114 if ((cur->flags & SRV_F_BACKUP) == flag &&
Emeric Brun52a91d32017-08-31 14:41:55 +0200115 srv_willbe_usable(cur)) {
Willy Tarreauf89c1872009-10-01 11:19:37 +0200116 int v;
117
118 /* If we are forced to return only one server, we don't want to
119 * go further, because we would return the wrong one due to
120 * divide overflow.
121 */
122 if (tot == 1) {
123 best = cur;
124 /* note that best->wscore will be wrong but we don't care */
125 break;
126 }
127
Christopher Faulet5b517552017-06-09 14:17:53 +0200128 HA_ATOMIC_ADD(&cur->wscore, cur->next_eweight);
Willy Tarreauf89c1872009-10-01 11:19:37 +0200129 v = (cur->wscore + tot) / tot; /* result between 0 and 3 */
130 if (best == NULL || v > max) {
131 max = v;
132 best = cur;
133 }
134 }
135 }
136 px->lbprm.map.srv[o] = best;
Cyril Bonté3906d572017-12-14 16:39:26 +0100137 HA_ATOMIC_SUB(&best->wscore, tot);
Willy Tarreauf89c1872009-10-01 11:19:37 +0200138 }
Willy Tarreauf89c1872009-10-01 11:19:37 +0200139}
140
141/* This function is responsible of building the server MAP for map-based LB
142 * algorithms, allocating the map, and setting p->lbprm.wmult to the GCD of the
143 * weights if applicable. It should be called only once per proxy, at config
144 * time.
145 */
146void init_server_map(struct proxy *p)
147{
148 struct server *srv;
149 int pgcd;
150 int act, bck;
151
152 p->lbprm.set_server_status_up = map_set_server_status_up;
153 p->lbprm.set_server_status_down = map_set_server_status_down;
154 p->lbprm.update_server_eweight = NULL;
155
156 if (!p->srv)
157 return;
158
159 /* We will factor the weights to reduce the table,
160 * using Euclide's largest common divisor algorithm.
161 * Since we may have zero weights, we have to first
162 * find a non-zero weight server.
163 */
164 pgcd = 1;
165 srv = p->srv;
166 while (srv && !srv->uweight)
167 srv = srv->next;
168
169 if (srv) {
170 pgcd = srv->uweight; /* note: cannot be zero */
171 while (pgcd > 1 && (srv = srv->next)) {
172 int w = srv->uweight;
173 while (w) {
174 int t = pgcd % w;
175 pgcd = w;
176 w = t;
177 }
178 }
179 }
180
181 /* It is sometimes useful to know what factor to apply
182 * to the backend's effective weight to know its real
183 * weight.
184 */
185 p->lbprm.wmult = pgcd;
186
187 act = bck = 0;
188 for (srv = p->srv; srv; srv = srv->next) {
Emeric Brun52a91d32017-08-31 14:41:55 +0200189 srv->next_eweight = (srv->uweight * p->lbprm.wdiv + p->lbprm.wmult - 1) / p->lbprm.wmult;
Willy Tarreauc5150da2014-05-13 19:27:31 +0200190
Willy Tarreauc93cd162014-05-13 15:54:22 +0200191 if (srv->flags & SRV_F_BACKUP)
Emeric Brun52a91d32017-08-31 14:41:55 +0200192 bck += srv->next_eweight;
Willy Tarreauf89c1872009-10-01 11:19:37 +0200193 else
Emeric Brun52a91d32017-08-31 14:41:55 +0200194 act += srv->next_eweight;
195 srv_lb_commit_status(srv);
Willy Tarreauf89c1872009-10-01 11:19:37 +0200196 }
197
198 /* this is the largest map we will ever need for this servers list */
199 if (act < bck)
200 act = bck;
201
202 if (!act)
203 act = 1;
204
Vincent Bernat3c2f2f22016-04-03 13:48:42 +0200205 p->lbprm.map.srv = calloc(act, sizeof(struct server *));
Willy Tarreauf89c1872009-10-01 11:19:37 +0200206 /* recounts servers and their weights */
Willy Tarreauf89c1872009-10-01 11:19:37 +0200207 recount_servers(p);
208 update_backend_weight(p);
209 recalc_server_map(p);
210}
211
212/*
213 * This function tries to find a running server with free connection slots for
214 * the proxy <px> following the round-robin method.
215 * If any server is found, it will be returned and px->lbprm.map.rr_idx will be updated
216 * to point to the next server. If no valid server is found, NULL is returned.
Willy Tarreau1b877482018-08-21 19:44:53 +0200217 *
218 * The lbprm's lock will be used.
Willy Tarreauf89c1872009-10-01 11:19:37 +0200219 */
220struct server *map_get_server_rr(struct proxy *px, struct server *srvtoavoid)
221{
222 int newidx, avoididx;
223 struct server *srv, *avoided;
224
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100225 HA_SPIN_LOCK(LBPRM_LOCK, &px->lbprm.lock);
Christopher Faulet5b517552017-06-09 14:17:53 +0200226 if (px->lbprm.tot_weight == 0) {
227 avoided = NULL;
228 goto out;
229 }
Willy Tarreauf89c1872009-10-01 11:19:37 +0200230
231 if (px->lbprm.map.rr_idx < 0 || px->lbprm.map.rr_idx >= px->lbprm.tot_weight)
232 px->lbprm.map.rr_idx = 0;
233 newidx = px->lbprm.map.rr_idx;
234
235 avoided = NULL;
236 avoididx = 0; /* shut a gcc warning */
237 do {
238 srv = px->lbprm.map.srv[newidx++];
Godbach8f9fd2f2013-08-07 09:48:23 +0800239 if (!srv->maxconn || (!srv->nbpend && srv->served < srv_dynamic_maxconn(srv))) {
Willy Tarreauf89c1872009-10-01 11:19:37 +0200240 /* make sure it is not the server we are try to exclude... */
Willy Tarreau03071f62017-11-05 10:59:12 +0100241 /* ...but remember that is was selected yet avoided */
242 avoided = srv;
243 avoididx = newidx;
Willy Tarreauf89c1872009-10-01 11:19:37 +0200244 if (srv != srvtoavoid) {
245 px->lbprm.map.rr_idx = newidx;
Willy Tarreau03071f62017-11-05 10:59:12 +0100246 goto out;
Willy Tarreauf89c1872009-10-01 11:19:37 +0200247 }
Willy Tarreauf89c1872009-10-01 11:19:37 +0200248 }
249 if (newidx == px->lbprm.tot_weight)
250 newidx = 0;
251 } while (newidx != px->lbprm.map.rr_idx);
252
253 if (avoided)
254 px->lbprm.map.rr_idx = avoididx;
255
Christopher Faulet5b517552017-06-09 14:17:53 +0200256 out:
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100257 HA_SPIN_UNLOCK(LBPRM_LOCK, &px->lbprm.lock);
Willy Tarreauf89c1872009-10-01 11:19:37 +0200258 /* return NULL or srvtoavoid if found */
259 return avoided;
260}
261
Willy Tarreau39c9ba72009-10-01 21:11:15 +0200262/*
263 * This function returns the running server from the map at the location
264 * pointed to by the result of a modulo operation on <hash>. The server map may
265 * be recomputed if required before being looked up. If any server is found, it
266 * will be returned. If no valid server is found, NULL is returned.
Willy Tarreau1b877482018-08-21 19:44:53 +0200267 *
268 * The lbprm's lock will be used.
Willy Tarreau39c9ba72009-10-01 21:11:15 +0200269 */
270struct server *map_get_server_hash(struct proxy *px, unsigned int hash)
271{
Willy Tarreau1b877482018-08-21 19:44:53 +0200272 struct server *srv = NULL;
273
274 HA_SPIN_LOCK(LBPRM_LOCK, &px->lbprm.lock);
275 if (px->lbprm.tot_weight)
276 srv = px->lbprm.map.srv[hash % px->lbprm.tot_weight];
277 HA_SPIN_UNLOCK(LBPRM_LOCK, &px->lbprm.lock);
278 return srv;
Willy Tarreau39c9ba72009-10-01 21:11:15 +0200279}
280
Willy Tarreauf89c1872009-10-01 11:19:37 +0200281
282/*
283 * Local variables:
284 * c-indent-level: 8
285 * c-basic-offset: 8
286 * End:
287 */