diff --git a/include/types/proxy.h b/include/types/proxy.h index 848014335..8aaa3a773 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -98,7 +98,8 @@ struct proxy { unsigned int feconn, feconn_max; /* # of active frontend sessions */ unsigned int beconn, beconn_max; /* # of active backend sessions */ unsigned int cum_feconn, cum_beconn; /* cumulated number of processed sessions */ - unsigned int maxconn; /* max # of active sessions */ + unsigned int maxconn; /* max # of active sessions on the frontend */ + unsigned int fullconn; /* #conns on backend above which servers are used at full load */ unsigned failed_conns, failed_resp; /* failed connect() and responses */ unsigned failed_secu; /* blocked responses because of security concerns */ int conn_retries; /* maximum number of connect retries */ diff --git a/src/cfgparse.c b/src/cfgparse.c index d70768592..42e250b2f 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -395,6 +395,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args) /* set default values */ curproxy->state = defproxy.state; curproxy->maxconn = defproxy.maxconn; + curproxy->fullconn = defproxy.fullconn; curproxy->conn_retries = defproxy.conn_retries; curproxy->options = defproxy.options; @@ -909,6 +910,13 @@ int cfg_parse_listen(const char *file, int linenum, char **args) } curproxy->maxconn = atol(args[1]); } + else if (!strcmp(args[0], "fullconn")) { /* fullconn */ + if (*(args[1]) == 0) { + Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]); + return -1; + } + curproxy->fullconn = atol(args[1]); + } else if (!strcmp(args[0], "grace")) { /* grace time (ms) */ if (*(args[1]) == 0) { Alert("parsing [%s:%d] : '%s' expects a time in milliseconds.\n", file, linenum, args[0]); @@ -1973,6 +1981,13 @@ int readcfgfile(const char *file) memcpy(curproxy->check_req, sslv3_client_hello_pkt, sizeof(sslv3_client_hello_pkt)); } + /* for backwards compatibility with "listen" instances, if + * fullconn is not set but maxconn is set, then maxconn + * is used. + */ + if (!curproxy->fullconn) + curproxy->fullconn = curproxy->maxconn; + /* first, we will invert the servers list order */ newsrv = NULL; while (curproxy->srv) { @@ -2035,13 +2050,18 @@ int readcfgfile(const char *file) */ newsrv = curproxy->srv; while (newsrv != NULL) { - if (newsrv->minconn >= newsrv->maxconn) { + if (newsrv->minconn > newsrv->maxconn) { /* Only 'minconn' was specified, or it was higher than or equal * to 'maxconn'. Let's turn this into maxconn and clean it, as * this will avoid further useless expensive computations. */ newsrv->maxconn = newsrv->minconn; - newsrv->minconn = 0; + } else if (newsrv->maxconn && !newsrv->minconn) { + /* minconn was not specified, so we set it to maxconn */ + newsrv->minconn = newsrv->maxconn; + } else if (!curproxy->fullconn) { + Alert("parsing [%s:%d] : fullconn is mandatory when minconn is set on a server.\n", file, linenum); + return -1; } if (newsrv->maxconn > 0) { diff --git a/src/queue.c b/src/queue.c index 8f0474cb8..611cfe95c 100644 --- a/src/queue.c +++ b/src/queue.c @@ -25,14 +25,21 @@ void **pool_pendconn = NULL; /* returns the effective dynamic maxconn for a server, considering the minconn - * and the proxy's usage relative to its saturation. + * and the proxy's usage relative to its dynamic connections limit. It is + * expected that 0 < s->minconn <= s->maxconn when this is called. */ unsigned int srv_dynamic_maxconn(const struct server *s) { - return (s->proxy->beconn >= s->proxy->maxconn) ? s->maxconn : - (s->minconn ? - MAX(s->maxconn * s->proxy->beconn / s->proxy->maxconn, s->minconn) - : s->maxconn); + if (s->proxy->beconn >= s->proxy->fullconn) + /* no fullconn or proxy is full */ + return s->maxconn; + + if (s->minconn == s->maxconn) + /* static limit */ + return s->maxconn; + + return MAX(s->minconn, + s->proxy->beconn * s->maxconn / s->proxy->fullconn); }