blob: 07baf5d21154cb12867c3d1a0ec51c9e8d63a5ce [file] [log] [blame]
Willy Tarreauf09c6602012-02-13 17:12:08 +01001/*
2 * First Available Server load balancing algorithm.
3 *
4 * Copyright 2000-2012 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>
16#include <eb32tree.h>
17
18#include <types/global.h>
19#include <types/server.h>
20
21#include <proto/backend.h>
22#include <proto/queue.h>
23
24
25/* Remove a server from a tree. It must have previously been dequeued. This
26 * function is meant to be called when a server is going down or has its
27 * weight disabled.
28 */
29static inline void fas_remove_from_tree(struct server *s)
30{
31 s->lb_tree = NULL;
32}
33
34/* simply removes a server from a tree */
35static inline void fas_dequeue_srv(struct server *s)
36{
37 eb32_delete(&s->lb_node);
38}
39
40/* Queue a server in its associated tree, assuming the weight is >0.
41 * Servers are sorted by unique ID so that we send all connections to the first
42 * available server in declaration order (or ID order) until its maxconn is
43 * reached. It is important to understand that the server weight is not used
44 * here.
45 */
46static inline void fas_queue_srv(struct server *s)
47{
48 s->lb_node.key = s->puid;
49 eb32_insert(s->lb_tree, &s->lb_node);
50}
51
52/* Re-position the server in the FS tree after it has been assigned one
53 * connection or after it has released one. Note that it is possible that
54 * the server has been moved out of the tree due to failed health-checks.
55 */
56static void fas_srv_reposition(struct server *s)
57{
58 if (!s->lb_tree)
59 return;
60 fas_dequeue_srv(s);
61 fas_queue_srv(s);
62}
63
64/* This function updates the server trees according to server <srv>'s new
65 * state. It should be called when server <srv>'s status changes to down.
66 * It is not important whether the server was already down or not. It is not
67 * important either that the new state is completely down (the caller may not
68 * know all the variables of a server's state).
69 */
70static void fas_set_server_status_down(struct server *srv)
71{
72 struct proxy *p = srv->proxy;
73
74 if (srv->state == srv->prev_state &&
75 srv->eweight == srv->prev_eweight)
76 return;
77
78 if (srv_is_usable(srv->state, srv->eweight))
79 goto out_update_state;
80
81 if (!srv_is_usable(srv->prev_state, srv->prev_eweight))
82 /* server was already down */
83 goto out_update_backend;
84
85 if (srv->state & SRV_BACKUP) {
86 p->lbprm.tot_wbck -= srv->prev_eweight;
87 p->srv_bck--;
88
89 if (srv == p->lbprm.fbck) {
90 /* we lost the first backup server in a single-backup
91 * configuration, we must search another one.
92 */
93 struct server *srv2 = p->lbprm.fbck;
94 do {
95 srv2 = srv2->next;
96 } while (srv2 &&
97 !((srv2->state & SRV_BACKUP) &&
98 srv_is_usable(srv2->state, srv2->eweight)));
99 p->lbprm.fbck = srv2;
100 }
101 } else {
102 p->lbprm.tot_wact -= srv->prev_eweight;
103 p->srv_act--;
104 }
105
106 fas_dequeue_srv(srv);
107 fas_remove_from_tree(srv);
108
109out_update_backend:
110 /* check/update tot_used, tot_weight */
111 update_backend_weight(p);
112 out_update_state:
113 srv->prev_state = srv->state;
114 srv->prev_eweight = srv->eweight;
115}
116
117/* This function updates the server trees according to server <srv>'s new
118 * state. It should be called when server <srv>'s status changes to up.
119 * It is not important whether the server was already down or not. It is not
120 * important either that the new state is completely UP (the caller may not
121 * know all the variables of a server's state). This function will not change
122 * the weight of a server which was already up.
123 */
124static void fas_set_server_status_up(struct server *srv)
125{
126 struct proxy *p = srv->proxy;
127
128 if (srv->state == srv->prev_state &&
129 srv->eweight == srv->prev_eweight)
130 return;
131
132 if (!srv_is_usable(srv->state, srv->eweight))
133 goto out_update_state;
134
135 if (srv_is_usable(srv->prev_state, srv->prev_eweight))
136 /* server was already up */
137 goto out_update_backend;
138
139 if (srv->state & SRV_BACKUP) {
140 srv->lb_tree = &p->lbprm.fas.bck;
141 p->lbprm.tot_wbck += srv->eweight;
142 p->srv_bck++;
143
144 if (!(p->options & PR_O_USE_ALL_BK)) {
145 if (!p->lbprm.fbck) {
146 /* there was no backup server anymore */
147 p->lbprm.fbck = srv;
148 } else {
149 /* we may have restored a backup server prior to fbck,
150 * in which case it should replace it.
151 */
152 struct server *srv2 = srv;
153 do {
154 srv2 = srv2->next;
155 } while (srv2 && (srv2 != p->lbprm.fbck));
156 if (srv2)
157 p->lbprm.fbck = srv;
158 }
159 }
160 } else {
161 srv->lb_tree = &p->lbprm.fas.act;
162 p->lbprm.tot_wact += srv->eweight;
163 p->srv_act++;
164 }
165
166 /* note that eweight cannot be 0 here */
167 fas_queue_srv(srv);
168
169 out_update_backend:
170 /* check/update tot_used, tot_weight */
171 update_backend_weight(p);
172 out_update_state:
173 srv->prev_state = srv->state;
174 srv->prev_eweight = srv->eweight;
175}
176
177/* This function must be called after an update to server <srv>'s effective
178 * weight. It may be called after a state change too.
179 */
180static void fas_update_server_weight(struct server *srv)
181{
182 int old_state, new_state;
183 struct proxy *p = srv->proxy;
184
185 if (srv->state == srv->prev_state &&
186 srv->eweight == srv->prev_eweight)
187 return;
188
189 /* If changing the server's weight changes its state, we simply apply
190 * the procedures we already have for status change. If the state
191 * remains down, the server is not in any tree, so it's as easy as
192 * updating its values. If the state remains up with different weights,
193 * there are some computations to perform to find a new place and
194 * possibly a new tree for this server.
195 */
196
197 old_state = srv_is_usable(srv->prev_state, srv->prev_eweight);
198 new_state = srv_is_usable(srv->state, srv->eweight);
199
200 if (!old_state && !new_state) {
201 srv->prev_state = srv->state;
202 srv->prev_eweight = srv->eweight;
203 return;
204 }
205 else if (!old_state && new_state) {
206 fas_set_server_status_up(srv);
207 return;
208 }
209 else if (old_state && !new_state) {
210 fas_set_server_status_down(srv);
211 return;
212 }
213
214 if (srv->lb_tree)
215 fas_dequeue_srv(srv);
216
217 if (srv->state & SRV_BACKUP) {
218 p->lbprm.tot_wbck += srv->eweight - srv->prev_eweight;
219 srv->lb_tree = &p->lbprm.fas.bck;
220 } else {
221 p->lbprm.tot_wact += srv->eweight - srv->prev_eweight;
222 srv->lb_tree = &p->lbprm.fas.act;
223 }
224
225 fas_queue_srv(srv);
226
227 update_backend_weight(p);
228 srv->prev_state = srv->state;
229 srv->prev_eweight = srv->eweight;
230}
231
232/* This function is responsible for building the trees in case of fast
233 * weighted least-conns. It also sets p->lbprm.wdiv to the eweight to
234 * uweight ratio. Both active and backup groups are initialized.
235 */
236void fas_init_server_tree(struct proxy *p)
237{
238 struct server *srv;
239 struct eb_root init_head = EB_ROOT;
240
241 p->lbprm.set_server_status_up = fas_set_server_status_up;
242 p->lbprm.set_server_status_down = fas_set_server_status_down;
243 p->lbprm.update_server_eweight = fas_update_server_weight;
244 p->lbprm.server_take_conn = fas_srv_reposition;
245 p->lbprm.server_drop_conn = fas_srv_reposition;
246
247 p->lbprm.wdiv = BE_WEIGHT_SCALE;
248 for (srv = p->srv; srv; srv = srv->next) {
249 srv->prev_eweight = srv->eweight = srv->uweight * BE_WEIGHT_SCALE;
250 srv->prev_state = srv->state;
251 }
252
253 recount_servers(p);
254 update_backend_weight(p);
255
256 p->lbprm.fas.act = init_head;
257 p->lbprm.fas.bck = init_head;
258
259 /* queue active and backup servers in two distinct groups */
260 for (srv = p->srv; srv; srv = srv->next) {
261 if (!srv_is_usable(srv->state, srv->eweight))
262 continue;
263 srv->lb_tree = (srv->state & SRV_BACKUP) ? &p->lbprm.fas.bck : &p->lbprm.fas.act;
264 fas_queue_srv(srv);
265 }
266}
267
268/* Return next server from the FS tree in backend <p>. If the tree is empty,
269 * return NULL. Saturated servers are skipped.
270 */
271struct server *fas_get_next_server(struct proxy *p, struct server *srvtoavoid)
272{
273 struct server *srv, *avoided;
274 struct eb32_node *node;
275
276 srv = avoided = NULL;
277
278 if (p->srv_act)
279 node = eb32_first(&p->lbprm.fas.act);
280 else if (p->lbprm.fbck)
281 return p->lbprm.fbck;
282 else if (p->srv_bck)
283 node = eb32_first(&p->lbprm.fas.bck);
284 else
285 return NULL;
286
287 while (node) {
288 /* OK, we have a server. However, it may be saturated, in which
289 * case we don't want to reconsider it for now, so we'll simply
290 * skip it. Same if it's the server we try to avoid, in which
291 * case we simply remember it for later use if needed.
292 */
293 struct server *s;
294
295 s = eb32_entry(node, struct server, lb_node);
296 if (!s->maxconn || (!s->nbpend && s->served < srv_dynamic_maxconn(s))) {
297 if (s != srvtoavoid) {
298 srv = s;
299 break;
300 }
301 avoided = s;
302 }
303 node = eb32_next(node);
304 }
305
306 if (!srv)
307 srv = avoided;
308
309 return srv;
310}
311
312
313/*
314 * Local variables:
315 * c-indent-level: 8
316 * c-basic-offset: 8
317 * End:
318 */