diff --git a/include/proto/backend.h b/include/proto/backend.h index fc717179b..7414edeb6 100644 --- a/include/proto/backend.h +++ b/include/proto/backend.h @@ -46,7 +46,7 @@ int be_downtime(struct proxy *px); /* * This function tries to find a running server with free connection slots for * the proxy following the round-robin method. - * If any server is found, it will be returned and px->srv_rr_idx will be updated + * If any server is found, it will be returned and px->lbprm.map.rr_idx will be updated * to point to the next server. If no valid server is found, NULL is returned. */ static inline struct server *get_server_rr_with_conns(struct proxy *px) @@ -54,25 +54,25 @@ static inline struct server *get_server_rr_with_conns(struct proxy *px) int newidx; struct server *srv; - if (px->map_state & PR_MAP_RECALC) - recalc_server_map(px); - - if (px->srv_map_sz == 0) + if (px->lbprm.tot_weight == 0) return NULL; - if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz) - px->srv_rr_idx = 0; - newidx = px->srv_rr_idx; + if (px->lbprm.map.state & PR_MAP_RECALC) + recalc_server_map(px); + + if (px->lbprm.map.rr_idx < 0 || px->lbprm.map.rr_idx >= px->lbprm.tot_weight) + px->lbprm.map.rr_idx = 0; + newidx = px->lbprm.map.rr_idx; do { - srv = px->srv_map[newidx++]; + srv = px->lbprm.map.srv[newidx++]; if (!srv->maxconn || srv->cur_sess < srv_dynamic_maxconn(srv)) { - px->srv_rr_idx = newidx; + px->lbprm.map.rr_idx = newidx; return srv; } - if (newidx == px->srv_map_sz) + if (newidx == px->lbprm.tot_weight) newidx = 0; - } while (newidx != px->srv_rr_idx); + } while (newidx != px->lbprm.map.rr_idx); return NULL; } @@ -81,20 +81,20 @@ static inline struct server *get_server_rr_with_conns(struct proxy *px) /* * This function tries to find a running server for the proxy following * the round-robin method. - * If any server is found, it will be returned and px->srv_rr_idx will be updated + * If any server is found, it will be returned and px->lbprm.map.rr_idx will be updated * to point to the next server. If no valid server is found, NULL is returned. */ static inline struct server *get_server_rr(struct proxy *px) { - if (px->map_state & PR_MAP_RECALC) - recalc_server_map(px); - - if (px->srv_map_sz == 0) + if (px->lbprm.tot_weight == 0) return NULL; - if (px->srv_rr_idx < 0 || px->srv_rr_idx >= px->srv_map_sz) - px->srv_rr_idx = 0; - return px->srv_map[px->srv_rr_idx++]; + if (px->lbprm.map.state & PR_MAP_RECALC) + recalc_server_map(px); + + if (px->lbprm.map.rr_idx < 0 || px->lbprm.map.rr_idx >= px->lbprm.tot_weight) + px->lbprm.map.rr_idx = 0; + return px->lbprm.map.srv[px->lbprm.map.rr_idx++]; } @@ -110,21 +110,21 @@ static inline struct server *get_server_sh(struct proxy *px, { unsigned int h, l; - if (px->map_state & PR_MAP_RECALC) - recalc_server_map(px); - - if (px->srv_map_sz == 0) + if (px->lbprm.tot_weight == 0) return NULL; + if (px->lbprm.map.state & PR_MAP_RECALC) + recalc_server_map(px); + l = h = 0; if (px->srv_act > 1 || (px->srv_act == 0 && px->srv_bck > 1)) { while ((l + sizeof (int)) <= len) { h ^= ntohl(*(unsigned int *)(&addr[l])); l += sizeof (int); } - h %= px->srv_map_sz; + h %= px->lbprm.tot_weight; } - return px->srv_map[h]; + return px->lbprm.map.srv[h]; } /* @@ -144,12 +144,12 @@ static inline struct server *get_server_uh(struct proxy *px, char *uri, int uri_ unsigned long hash = 0; int c; - if (px->map_state & PR_MAP_RECALC) - recalc_server_map(px); - - if (px->srv_map_sz == 0) + if (px->lbprm.tot_weight == 0) return NULL; + if (px->lbprm.map.state & PR_MAP_RECALC) + recalc_server_map(px); + while (uri_len--) { c = *uri++; if (c == '?') @@ -157,7 +157,7 @@ static inline struct server *get_server_uh(struct proxy *px, char *uri, int uri_ hash = c + (hash << 6) + (hash << 16) - hash; } - return px->srv_map[hash % px->srv_map_sz]; + return px->lbprm.map.srv[hash % px->lbprm.tot_weight]; } diff --git a/include/types/proxy.h b/include/types/proxy.h index ecc4d9c63..03f9601ba 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -54,7 +54,7 @@ #define PR_MODE_HTTP 1 #define PR_MODE_HEALTH 2 -/* values for proxy->map_state */ +/* values for proxy->lbprm.map.state */ #define PR_MAP_RECALC (1 << 0) /* flag values for proxy->cap. This is a bitmask of capabilities supported by the proxy */ @@ -78,13 +78,21 @@ struct proxy { struct list acl; /* ACL declared on this proxy */ struct list block_cond; /* early blocking conditions (chained) */ struct list switching_rules; /* content switching rules (chained) */ - int map_state; /* PR_MAP_RECALC */ struct server *srv; /* known servers */ int srv_act, srv_bck; /* # of running servers */ - int tot_wact, tot_wbck; /* total weights of active and backup servers */ - struct server **srv_map; /* the server map used to apply weights */ - int srv_map_sz; /* the size of the effective server map */ - int srv_rr_idx; /* next server to be elected in round robin mode */ + + struct { + int tot_wact, tot_wbck; /* total effective weights of active and backup servers */ + int tot_weight; /* total effective weight of servers participating to LB */ + int tot_used; /* total number of servers used for LB */ + int wmult; /* ratio between user weight and effective weight */ + struct { + struct server **srv; /* the server map used to apply weights */ + int rr_idx; /* next server to be elected in round robin mode */ + int state; /* PR_MAP_RECALC */ + } map; /* LB parameters for map-based algorithms */ + } lbprm; /* LB parameters for all algorithms */ + char *cookie_name; /* name of the cookie to look for */ int cookie_len; /* strlen(cookie_name), computed only once */ char *url_param_name; /* name of the URL parameter used for hashing */ diff --git a/src/backend.c b/src/backend.c index 2ae25c36f..96de0ba37 100644 --- a/src/backend.c +++ b/src/backend.c @@ -54,50 +54,77 @@ void recount_servers(struct proxy *px) { struct server *srv; + int first_bkw = 0; - px->srv_act = 0; px->srv_bck = px->tot_wact = px->tot_wbck = 0; + px->srv_act = px->srv_bck = 0; + px->lbprm.tot_wact = px->lbprm.tot_wbck = 0; for (srv = px->srv; srv != NULL; srv = srv->next) { if (srv->state & SRV_RUNNING) { if (srv->state & SRV_BACKUP) { px->srv_bck++; - px->tot_wbck += srv->eweight; + px->lbprm.tot_wbck += srv->eweight; + if (px->srv_bck == 1) + first_bkw = srv->eweight; } else { px->srv_act++; - px->tot_wact += srv->eweight; + px->lbprm.tot_wact += srv->eweight; } } } + + if (px->srv_act) { + px->lbprm.tot_weight = px->lbprm.tot_wact; + px->lbprm.tot_used = px->srv_act; + } + else if (px->srv_bck) { + if (px->options & PR_O_USE_ALL_BK) { + px->lbprm.tot_weight = px->lbprm.tot_wbck; + px->lbprm.tot_used = px->srv_bck; + } + else { /* the first backup server is enough */ + px->lbprm.tot_weight = first_bkw; + px->lbprm.tot_used = 1; + } + } + else { + px->lbprm.tot_weight = 0; + px->lbprm.tot_used = 0; + } + } -/* This function recomputes the server map for proxy px. It - * relies on px->tot_wact and px->tot_wbck, so it must be - * called after recount_servers(). It also expects px->srv_map - * to be initialized to the largest value needed. +/* This function recomputes the server map for proxy px. It relies on + * px->lbprm.tot_wact, tot_wbck, tot_used, tot_weight, so it must be + * called after recount_servers(). It also expects px->lbprm.map.srv + * to be allocated with the largest size needed. It updates tot_weight. */ void recalc_server_map(struct proxy *px) { int o, tot, flag; struct server *cur, *best; - if (px->srv_act) { - flag = SRV_RUNNING; - tot = px->tot_wact; - } else if (px->srv_bck) { - flag = SRV_RUNNING | SRV_BACKUP; - if (px->options & PR_O_USE_ALL_BK) - tot = px->tot_wbck; - else - tot = 1; /* the first server is enough */ - } else { - px->srv_map_sz = 0; - px->map_state &= ~PR_MAP_RECALC; + switch (px->lbprm.tot_used) { + case 0: /* no server */ + px->lbprm.map.state &= ~PR_MAP_RECALC; return; + case 1: /* only one server, just fill first entry */ + tot = 1; + break; + default: + tot = px->lbprm.tot_weight; + break; } + /* here we *know* that we have some servers */ + if (px->srv_act) + flag = SRV_RUNNING; + else + flag = SRV_RUNNING | SRV_BACKUP; + /* this algorithm gives priority to the first server, which means that * it will respect the declaration order for equivalent weights, and * that whatever the weights, the first server called will always be - * the first declard. This is an important asumption for the backup + * the first declared. This is an important asumption for the backup * case, where we want the first server only. */ for (cur = px->srv; cur; cur = cur->next) @@ -116,6 +143,7 @@ void recalc_server_map(struct proxy *px) */ if (tot == 1) { best = cur; + /* note that best->wscore will be wrong but we don't care */ break; } @@ -127,11 +155,10 @@ void recalc_server_map(struct proxy *px) } } } - px->srv_map[o] = best; + px->lbprm.map.srv[o] = best; best->wscore -= tot; } - px->srv_map_sz = tot; - px->map_state &= ~PR_MAP_RECALC; + px->lbprm.map.state &= ~PR_MAP_RECALC; } /* @@ -150,12 +177,12 @@ struct server *get_server_ph(struct proxy *px, const char *uri, int uri_len) char *p; int plen; - if (px->map_state & PR_MAP_RECALC) - recalc_server_map(px); - - if (px->srv_map_sz == 0) + if (px->lbprm.tot_weight == 0) return NULL; + if (px->lbprm.map.state & PR_MAP_RECALC) + recalc_server_map(px); + p = memchr(uri, '?', uri_len); if (!p) return NULL; @@ -183,7 +210,7 @@ struct server *get_server_ph(struct proxy *px, const char *uri, int uri_len) uri_len--; p++; } - return px->srv_map[hash % px->srv_map_sz]; + return px->lbprm.map.srv[hash % px->lbprm.tot_weight]; } } diff --git a/src/cfgparse.c b/src/cfgparse.c index cd8bdbb8a..05864d82e 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -2652,6 +2652,8 @@ int readcfgfile(const char *file) curproxy->srv = next; } + curproxy->lbprm.wmult = 1; /* default weight multiplier */ + /* now, newsrv == curproxy->srv */ if (newsrv) { struct server *srv; @@ -2673,6 +2675,12 @@ int readcfgfile(const char *file) } } + /* It is sometimes useful to know what factor to apply + * to the backend's effective weight to know its real + * weight. + */ + curproxy->lbprm.wmult = pgcd; + act = bck = 0; for (srv = newsrv; srv; srv = srv->next) { srv->eweight = srv->uweight / pgcd; @@ -2686,9 +2694,9 @@ int readcfgfile(const char *file) if (act < bck) act = bck; - curproxy->srv_map = (struct server **)calloc(act, sizeof(struct server *)); + curproxy->lbprm.map.srv = (struct server **)calloc(act, sizeof(struct server *)); /* recounts servers and their weights */ - curproxy->map_state = PR_MAP_RECALC; + curproxy->lbprm.map.state = PR_MAP_RECALC; recount_servers(curproxy); recalc_server_map(curproxy); } diff --git a/src/checks.c b/src/checks.c index 77e9b513f..37132101b 100644 --- a/src/checks.c +++ b/src/checks.c @@ -63,7 +63,7 @@ static void set_server_down(struct server *s) s->state &= ~SRV_RUNNING; recount_servers(s->proxy); - s->proxy->map_state |= PR_MAP_RECALC; + s->proxy->lbprm.map.state |= PR_MAP_RECALC; /* we might have sessions queued on this server and waiting for * a connection. Those which are redispatchable will be queued @@ -479,7 +479,7 @@ void process_chk(struct task *t, struct timeval *next) } recount_servers(s->proxy); - s->proxy->map_state |= PR_MAP_RECALC; + s->proxy->lbprm.map.state |= PR_MAP_RECALC; /* check if we can handle some connections queued at the proxy. We * will take as many as we can handle. diff --git a/src/dumpstats.c b/src/dumpstats.c index fd16a6361..2c91b4391 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -842,18 +842,6 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, case DATA_ST_PX_BE: /* print the backend */ if (px->cap & PR_CAP_BE) { - int gcd = 1; - - if (px->map_state & PR_MAP_RECALC) - recalc_server_map(px); - - /* The GCD which was computed causes the total effective - * weight to appear lower than all weights. Let's - * recompute it. - */ - if (px->srv && px->srv->eweight) - gcd = px->srv->uweight / px->srv->eweight; - if (flags & STAT_FMT_HTML) { chunk_printf(&msg, sizeof(trash), /* name */ @@ -883,8 +871,9 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, px->failed_conns, px->failed_resp, px->retries, px->redispatches, human_time(now.tv_sec - px->last_change, 1), - (px->srv_map_sz > 0 || !px->srv) ? "UP" : "DOWN", - px->srv_map_sz * gcd, px->srv_act, px->srv_bck); + (px->lbprm.tot_weight > 0 || !px->srv) ? "UP" : "DOWN", + px->lbprm.tot_weight * px->lbprm.wmult, + px->srv_act, px->srv_bck); chunk_printf(&msg, sizeof(trash), /* rest of backend: nothing, down transformations, total downtime */ @@ -928,10 +917,11 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, px->denied_req, px->denied_resp, px->failed_conns, px->failed_resp, px->retries, px->redispatches, - (px->srv_map_sz > 0 || !px->srv) ? "UP" : "DOWN", - px->srv_map_sz * gcd, px->srv_act, px->srv_bck, + (px->lbprm.tot_weight > 0 || !px->srv) ? "UP" : "DOWN", + px->lbprm.tot_weight * px->lbprm.wmult, + px->srv_act, px->srv_bck, px->down_trans, now.tv_sec - px->last_change, - px->srv?be_downtime(px):0, + px->srv?be_downtime(px):0, relative_pid, px->uuid); } if (buffer_write_chunk(rep, &msg) != 0)