/* This function is responsible for building the trees in case of fast * weighted least-conns. It also sets p->lbprm.wdiv to the eweight to * uweight ratio. Both active and backup groups are initialized. */ void fas_init_server_tree(struct proxy *p) { struct server *srv; struct eb_root init_head = EB_ROOT; p->lbprm.set_server_status_up = fas_set_server_status_up; p->lbprm.set_server_status_down = fas_set_server_status_down; p->lbprm.update_server_eweight = fas_update_server_weight; p->lbprm.server_take_conn = fas_srv_reposition; p->lbprm.server_drop_conn = fas_srv_reposition; p->lbprm.wdiv = BE_WEIGHT_SCALE; for (srv = p->srv; srv; srv = srv->next) { srv->eweight = (srv->uweight * p->lbprm.wdiv + p->lbprm.wmult - 1) / p->lbprm.wmult; srv_lb_commit_status(srv); } recount_servers(p); update_backend_weight(p); p->lbprm.fas.act = init_head; p->lbprm.fas.bck = init_head; /* queue active and backup servers in two distinct groups */ for (srv = p->srv; srv; srv = srv->next) { if (!srv_is_usable(srv)) continue; srv->lb_tree = (srv->state & SRV_BACKUP) ? &p->lbprm.fas.bck : &p->lbprm.fas.act; fas_queue_srv(srv); } }
/* This function is responsible for building the weight trees in case of fast * weighted round-robin. It also sets p->lbprm.wdiv to the eweight to uweight * ratio. Both active and backup groups are initialized. */ void fwrr_init_server_groups(struct proxy *p) { struct server *srv; struct eb_root init_head = EB_ROOT; p->lbprm.set_server_status_up = fwrr_set_server_status_up; p->lbprm.set_server_status_down = fwrr_set_server_status_down; p->lbprm.update_server_eweight = fwrr_update_server_weight; p->lbprm.wdiv = BE_WEIGHT_SCALE; for (srv = p->srv; srv; srv = srv->next) { srv->prev_eweight = srv->eweight = srv->uweight * BE_WEIGHT_SCALE; srv->prev_state = srv->state; } recount_servers(p); update_backend_weight(p); /* prepare the active servers group */ p->lbprm.fwrr.act.curr_pos = p->lbprm.fwrr.act.curr_weight = p->lbprm.fwrr.act.next_weight = p->lbprm.tot_wact; p->lbprm.fwrr.act.curr = p->lbprm.fwrr.act.t0 = p->lbprm.fwrr.act.t1 = init_head; p->lbprm.fwrr.act.init = &p->lbprm.fwrr.act.t0; p->lbprm.fwrr.act.next = &p->lbprm.fwrr.act.t1; /* prepare the backup servers group */ p->lbprm.fwrr.bck.curr_pos = p->lbprm.fwrr.bck.curr_weight = p->lbprm.fwrr.bck.next_weight = p->lbprm.tot_wbck; p->lbprm.fwrr.bck.curr = p->lbprm.fwrr.bck.t0 = p->lbprm.fwrr.bck.t1 = init_head; p->lbprm.fwrr.bck.init = &p->lbprm.fwrr.bck.t0; p->lbprm.fwrr.bck.next = &p->lbprm.fwrr.bck.t1; /* queue active and backup servers in two distinct groups */ for (srv = p->srv; srv; srv = srv->next) { if (!srv_is_usable(srv->state, srv->eweight)) continue; fwrr_queue_by_weight((srv->state & SRV_BACKUP) ? p->lbprm.fwrr.bck.init : p->lbprm.fwrr.act.init, srv); } }
/* This function updates the map according to server <srv>'s new state */ static void map_set_server_status_up(struct server *srv) { struct proxy *p = srv->proxy; if (srv->state == srv->prev_state && srv->eweight == srv->prev_eweight) return; if (!srv_is_usable(srv->state, srv->eweight)) goto out_update_state; /* FIXME: could be optimized since we know what changed */ recount_servers(p); update_backend_weight(p); p->lbprm.map.state |= LB_MAP_RECALC; out_update_state: srv->prev_state = srv->state; srv->prev_eweight = srv->eweight; }
/* This function is responsible of building the server MAP for map-based LB * algorithms, allocating the map, and setting p->lbprm.wmult to the GCD of the * weights if applicable. It should be called only once per proxy, at config * time. */ void init_server_map(struct proxy *p) { struct server *srv; int pgcd; int act, bck; p->lbprm.set_server_status_up = map_set_server_status_up; p->lbprm.set_server_status_down = map_set_server_status_down; p->lbprm.update_server_eweight = NULL; if (!p->srv) return; /* We will factor the weights to reduce the table, * using Euclide's largest common divisor algorithm. * Since we may have zero weights, we have to first * find a non-zero weight server. */ pgcd = 1; srv = p->srv; while (srv && !srv->uweight) srv = srv->next; if (srv) { pgcd = srv->uweight; /* note: cannot be zero */ while (pgcd > 1 && (srv = srv->next)) { int w = srv->uweight; while (w) { int t = pgcd % w; pgcd = w; w = t; } } } /* It is sometimes useful to know what factor to apply * to the backend's effective weight to know its real * weight. */ p->lbprm.wmult = pgcd; act = bck = 0; for (srv = p->srv; srv; srv = srv->next) { srv->eweight = srv->uweight / pgcd; srv->prev_eweight = srv->eweight; srv->prev_state = srv->state; if (srv->state & SRV_BACKUP) bck += srv->eweight; else act += srv->eweight; } /* this is the largest map we will ever need for this servers list */ if (act < bck) act = bck; if (!act) act = 1; p->lbprm.map.srv = (struct server **)calloc(act, sizeof(struct server *)); /* recounts servers and their weights */ p->lbprm.map.state = LB_MAP_RECALC; recount_servers(p); update_backend_weight(p); recalc_server_map(p); }