/*
* This function tries to find a running server with free connection slots for
* the proxy <px> 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)
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;
}
/*
* This function tries to find a running server for the proxy <px> 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++];
}
{
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];
}
/*
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 == '?')
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];
}
#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 */
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 */
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)
*/
if (tot == 1) {
best = cur;
+ /* note that best->wscore will be wrong but we don't care */
break;
}
}
}
}
- 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;
}
/*
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;
uri_len--;
p++;
}
- return px->srv_map[hash % px->srv_map_sz];
+ return px->lbprm.map.srv[hash % px->lbprm.tot_weight];
}
}
curproxy->srv = next;
}
+ curproxy->lbprm.wmult = 1; /* default weight multiplier */
+
/* now, newsrv == curproxy->srv */
if (newsrv) {
struct server *srv;
}
}
+ /* 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;
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);
}
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
}
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.
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 */
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 */
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)