MEDIUM: servers: Add a command to limit the number of idling connections.
Add a new command, "pool-max-conn" that sets the maximum number of connections
waiting in the orphan idling connections list (as activated with idle-timeout).
Using "-1" means unlimited. Using pools is now dependant on this.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 9fca4bd..5b24fcf 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -11972,6 +11972,14 @@
Actions are disabled by default
+pool-max-conn <max>
+ Set the maximum number of idling connections for a server. -1 means unlimited
+ connections, 0 means no idle connections. The default is -1. When idle
+ connections are enabled, orphaned idle connections which do not belong to any
+ client session anymore are moved to a dedicated pool so that they remain
+ usable by future clients. This only applies to connections that can be shared
+ according to the same principles as those applying to "http-reuse".
+
port <port>
Using the "port" parameter, it becomes possible to use a different port to
send health-checks. On some servers, it may be desirable to dedicate a port
diff --git a/include/proto/connection.h b/include/proto/connection.h
index f84b75a..2cf37ab 100644
--- a/include/proto/connection.h
+++ b/include/proto/connection.h
@@ -558,6 +558,7 @@
LIST_INIT(&conn->session_list);
conn->send_wait = NULL;
conn->recv_wait = NULL;
+ conn->idle_time = 0;
}
/* sets <owner> as the connection's owner */
@@ -673,6 +674,13 @@
if (objt_conn(s->si[1].end) == conn)
s->si[1].end = NULL;
}
+ /* The connection is currently in the server's idle list, so tell it
+ * there's one less connection available in that list.
+ */
+ if (conn->idle_time > 0) {
+ struct server *srv = __objt_server(conn->target);
+ srv->curr_idle_conns--;
+ }
conn_force_unsubscribe(conn);
LIST_DEL(&conn->list);
diff --git a/include/types/connection.h b/include/types/connection.h
index bcc2965..eff1001 100644
--- a/include/types/connection.h
+++ b/include/types/connection.h
@@ -446,7 +446,7 @@
struct sockaddr_storage from; /* client address, or address to spoof when connecting to the server */
struct sockaddr_storage to; /* address reached by the client, or address to connect to */
} addr; /* addresses of the remote side, client for producer and server for consumer */
- unsigned int idle_time; /* Time the connection was added to the idle list */
+ unsigned int idle_time; /* Time the connection was added to the idle list, or 0 if not in the idle list */
};
/* PROTO token registration */
diff --git a/include/types/server.h b/include/types/server.h
index bb53523..2eef2c3 100644
--- a/include/types/server.h
+++ b/include/types/server.h
@@ -223,7 +223,9 @@
struct list *safe_conns; /* safe idle connections attached to stream interfaces, shared */
struct list *idle_orphan_conns; /* Orphan connections idling */
unsigned int idle_timeout; /* Time to keep an idling orphan connection alive */
- struct task **idle_task; /* task responsible for cleaning idle orphan connections */
+ unsigned int max_idle_conns; /* Max number of connection allowed in the orphan connections list */
+ unsigned int curr_idle_conns; /* Current number of orphan idling connections */
+ struct task **idle_task; /* task responsible for cleaning idle orphan connections */
struct task *warmup; /* the task dedicated to the warmup when slowstart is set */
struct conn_src conn_src; /* connection source settings */
diff --git a/src/backend.c b/src/backend.c
index e116757..83ae51d 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -1231,6 +1231,8 @@
*/
if (reuse && reuse_orphan) {
LIST_DEL(&srv_conn->list);
+ srv_conn->idle_time = 0;
+ srv->curr_idle_conns--;
LIST_ADDQ(&srv->idle_conns[tid], &srv_conn->list);
if (LIST_ISEMPTY(&srv->idle_orphan_conns[tid]))
task_unlink_wq(srv->idle_task[tid]);
diff --git a/src/cfgparse.c b/src/cfgparse.c
index ed09a4e..c3318a4 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -471,6 +471,7 @@
defproxy.defsrv.maxqueue = 0;
defproxy.defsrv.minconn = 0;
defproxy.defsrv.maxconn = 0;
+ defproxy.defsrv.max_idle_conns = -1;
defproxy.defsrv.slowstart = 0;
defproxy.defsrv.onerror = DEF_HANA_ONERR;
defproxy.defsrv.consecutive_errors_limit = DEF_HANA_ERRLIMIT;
diff --git a/src/server.c b/src/server.c
index bae9a3b..dc429d1 100644
--- a/src/server.c
+++ b/src/server.c
@@ -380,6 +380,20 @@
return 0;
}
+static int srv_parse_pool_max_conn(char **args, int *cur_arg, struct proxy *curproxy, struct server *newsrv, char **err)
+{
+ char *arg;
+
+ arg = args[*cur_arg + 1];
+ if (!*arg) {
+ memprintf(err, "'%s' expects <value> as argument.\n", args[*cur_arg]);
+ return ERR_ALERT | ERR_FATAL;
+ }
+ newsrv->max_idle_conns = atoi(arg);
+
+ return 0;
+}
+
/* parse the "id" server keyword */
static int srv_parse_id(char **args, int *cur_arg, struct proxy *curproxy, struct server *newsrv, char **err)
{
@@ -1230,6 +1244,7 @@
{ "no-send-proxy-v2", srv_parse_no_send_proxy_v2, 0, 1 }, /* Disable use of PROXY V2 protocol */
{ "non-stick", srv_parse_non_stick, 0, 1 }, /* Disable stick-table persistence */
{ "observe", srv_parse_observe, 1, 1 }, /* Enables health adjusting based on observing communication with the server */
+ { "pool-max-conn", srv_parse_pool_max_conn, 1, 1 }, /* Set the max number of orphan idle connections, 0 means unlimited */
{ "proto", srv_parse_proto, 1, 1 }, /* Set the proto to use for all outgoing connections */
{ "proxy-v2-options", srv_parse_proxy_v2_options, 1, 1 }, /* options for send-proxy-v2 */
{ "redir", srv_parse_redir, 1, 1 }, /* Enable redirection mode */
@@ -1665,6 +1680,7 @@
#endif
srv->mux_proto = src->mux_proto;
srv->idle_timeout = src->idle_timeout;
+ srv->max_idle_conns = src->max_idle_conns;
if (srv_tmpl)
srv->srvrq = src->srvrq;
@@ -1708,6 +1724,9 @@
srv->agent.server = srv;
srv->xprt = srv->check.xprt = srv->agent.xprt = xprt_get(XPRT_RAW);
+ srv->idle_timeout = 1000;
+ srv->max_idle_conns = -1;
+
return srv;
free_idle_conns:
@@ -1914,7 +1933,7 @@
px->srv_act++;
srv_lb_commit_status(srv);
- if (!srv->tmpl_info.prefix && srv->idle_timeout != 0) {
+ if (!srv->tmpl_info.prefix && srv->max_idle_conns != 0) {
int i;
srv->idle_orphan_conns = calloc(global.nbthread, sizeof(*srv->idle_orphan_conns));
@@ -2019,7 +2038,7 @@
/* Linked backwards first. This will be restablished after parsing. */
newsrv->next = px->srv;
px->srv = newsrv;
- if (newsrv->idle_timeout != 0) {
+ if (newsrv->max_idle_conns != 0) {
int i;
newsrv->idle_orphan_conns = calloc(global.nbthread, sizeof(*newsrv->idle_orphan_conns));
diff --git a/src/session.c b/src/session.c
index 2dfd1de..e5e5508 100644
--- a/src/session.c
+++ b/src/session.c
@@ -93,6 +93,8 @@
srv = objt_server(conn->target);
conn->owner = NULL;
if (srv && srv->idle_timeout > 0 &&
+ (srv->max_idle_conns == -1 ||
+ srv->max_idle_conns > srv->curr_idle_conns) &&
!(conn->flags & CO_FL_PRIVATE) &&
conn->mux->avail_streams(conn) ==
conn->mux->max_streams(conn)) {
@@ -100,6 +102,7 @@
LIST_ADDQ(&srv->idle_orphan_conns[tid],
&conn->list);
+ srv->curr_idle_conns++;
conn->idle_time = now_ms;
if (!(task_in_wq(srv->idle_task[tid])) &&