MEDIUM: threads/server: Make connection list (priv/idle/safe) thread-safe

For now, we have a list of each type per thread. So there is no need to lock
them. This is the easiest solution for now, but not the best one because there
is no sharing between threads. An idle connection on a thread will not be able
be used by a stream on another thread. So it could be a good idea to rework this
patch later.
This commit is contained in:
Christopher Faulet 2017-07-03 15:41:01 +02:00 committed by Willy Tarreau
parent ff8abcd31d
commit 40a007cf2a
5 changed files with 41 additions and 22 deletions

View File

@ -207,9 +207,9 @@ struct server {
struct list pendconns; /* pending connections */ struct list pendconns; /* pending connections */
struct list actconns; /* active connections */ struct list actconns; /* active connections */
struct list priv_conns; /* private idle connections attached to stream interfaces */ struct list *priv_conns; /* private idle connections attached to stream interfaces */
struct list idle_conns; /* sharable idle connections attached or not to a stream interface */ struct list *idle_conns; /* sharable idle connections attached or not to a stream interface */
struct list safe_conns; /* safe idle connections attached to stream interfaces, shared */ struct list *safe_conns; /* safe idle connections attached to stream interfaces, shared */
struct task *warmup; /* the task dedicated to the warmup when slowstart is set */ struct task *warmup; /* the task dedicated to the warmup when slowstart is set */
struct conn_src conn_src; /* connection source settings */ struct conn_src conn_src; /* connection source settings */

View File

@ -1066,20 +1066,19 @@ int connect_server(struct stream *s)
* idle| - | 1 | idle| - | 1 | idle| 2 | 1 | * idle| - | 1 | idle| - | 1 | idle| 2 | 1 |
* ----+-----+-----+ ----+-----+-----+ ----+-----+-----+ * ----+-----+-----+ ----+-----+-----+ ----+-----+-----+
*/ */
if (srv->idle_conns && !LIST_ISEMPTY(&srv->idle_conns[tid]) &&
if (!LIST_ISEMPTY(&srv->idle_conns) &&
((s->be->options & PR_O_REUSE_MASK) != PR_O_REUSE_NEVR && ((s->be->options & PR_O_REUSE_MASK) != PR_O_REUSE_NEVR &&
s->txn && (s->txn->flags & TX_NOT_FIRST))) { s->txn && (s->txn->flags & TX_NOT_FIRST))) {
srv_conn = LIST_ELEM(srv->idle_conns.n, struct connection *, list); srv_conn = LIST_ELEM(srv->idle_conns[tid].n, struct connection *, list);
} }
else if (!LIST_ISEMPTY(&srv->safe_conns) && else if (srv->safe_conns && !LIST_ISEMPTY(&srv->safe_conns[tid]) &&
((s->txn && (s->txn->flags & TX_NOT_FIRST)) || ((s->txn && (s->txn->flags & TX_NOT_FIRST)) ||
(s->be->options & PR_O_REUSE_MASK) >= PR_O_REUSE_AGGR)) { (s->be->options & PR_O_REUSE_MASK) >= PR_O_REUSE_AGGR)) {
srv_conn = LIST_ELEM(srv->safe_conns.n, struct connection *, list); srv_conn = LIST_ELEM(srv->safe_conns[tid].n, struct connection *, list);
} }
else if (!LIST_ISEMPTY(&srv->idle_conns) && else if (srv->idle_conns && !LIST_ISEMPTY(&srv->idle_conns[tid]) &&
(s->be->options & PR_O_REUSE_MASK) == PR_O_REUSE_ALWS) { (s->be->options & PR_O_REUSE_MASK) == PR_O_REUSE_ALWS) {
srv_conn = LIST_ELEM(srv->idle_conns.n, struct connection *, list); srv_conn = LIST_ELEM(srv->idle_conns[tid].n, struct connection *, list);
} }
/* If we've picked a connection from the pool, we now have to /* If we've picked a connection from the pool, we now have to

View File

@ -7666,9 +7666,9 @@ void hlua_init(void)
socket_tcp.obj_type = OBJ_TYPE_SERVER; socket_tcp.obj_type = OBJ_TYPE_SERVER;
LIST_INIT(&socket_tcp.actconns); LIST_INIT(&socket_tcp.actconns);
LIST_INIT(&socket_tcp.pendconns); LIST_INIT(&socket_tcp.pendconns);
LIST_INIT(&socket_tcp.priv_conns); socket_tcp.priv_conns = NULL;
LIST_INIT(&socket_tcp.idle_conns); socket_tcp.idle_conns = NULL;
LIST_INIT(&socket_tcp.safe_conns); socket_tcp.safe_conns = NULL;
socket_tcp.next_state = SRV_ST_RUNNING; /* early server setup */ socket_tcp.next_state = SRV_ST_RUNNING; /* early server setup */
socket_tcp.last_change = 0; socket_tcp.last_change = 0;
socket_tcp.id = "LUA-TCP-CONN"; socket_tcp.id = "LUA-TCP-CONN";
@ -7712,9 +7712,9 @@ void hlua_init(void)
socket_ssl.obj_type = OBJ_TYPE_SERVER; socket_ssl.obj_type = OBJ_TYPE_SERVER;
LIST_INIT(&socket_ssl.actconns); LIST_INIT(&socket_ssl.actconns);
LIST_INIT(&socket_ssl.pendconns); LIST_INIT(&socket_ssl.pendconns);
LIST_INIT(&socket_ssl.priv_conns); socket_tcp.priv_conns = NULL;
LIST_INIT(&socket_ssl.idle_conns); socket_tcp.idle_conns = NULL;
LIST_INIT(&socket_ssl.safe_conns); socket_tcp.safe_conns = NULL;
socket_ssl.next_state = SRV_ST_RUNNING; /* early server setup */ socket_ssl.next_state = SRV_ST_RUNNING; /* early server setup */
socket_ssl.last_change = 0; socket_ssl.last_change = 0;
socket_ssl.id = "LUA-SSL-CONN"; socket_ssl.id = "LUA-SSL-CONN";

View File

@ -4348,15 +4348,15 @@ void http_end_txn_clean_session(struct stream *s)
if (!srv) if (!srv)
si_idle_conn(&s->si[1], NULL); si_idle_conn(&s->si[1], NULL);
else if (srv_conn->flags & CO_FL_PRIVATE) else if (srv_conn->flags & CO_FL_PRIVATE)
si_idle_conn(&s->si[1], &srv->priv_conns); si_idle_conn(&s->si[1], (srv->priv_conns ? &srv->priv_conns[tid] : NULL));
else if (prev_flags & TX_NOT_FIRST) else if (prev_flags & TX_NOT_FIRST)
/* note: we check the request, not the connection, but /* note: we check the request, not the connection, but
* this is valid for strategies SAFE and AGGR, and in * this is valid for strategies SAFE and AGGR, and in
* case of ALWS, we don't care anyway. * case of ALWS, we don't care anyway.
*/ */
si_idle_conn(&s->si[1], &srv->safe_conns); si_idle_conn(&s->si[1], (srv->safe_conns ? &srv->safe_conns[tid] : NULL));
else else
si_idle_conn(&s->si[1], &srv->idle_conns); si_idle_conn(&s->si[1], (srv->idle_conns ? &srv->idle_conns[tid] : NULL));
} }
s->req.analysers = strm_li(s) ? strm_li(s)->analysers : 0; s->req.analysers = strm_li(s) ? strm_li(s)->analysers : 0;
s->res.analysers = 0; s->res.analysers = 0;

View File

@ -1511,6 +1511,7 @@ static void srv_settings_cpy(struct server *srv, struct server *src, int srv_tmp
static struct server *new_server(struct proxy *proxy) static struct server *new_server(struct proxy *proxy)
{ {
struct server *srv; struct server *srv;
int i;
srv = calloc(1, sizeof *srv); srv = calloc(1, sizeof *srv);
if (!srv) if (!srv)
@ -1520,9 +1521,20 @@ static struct server *new_server(struct proxy *proxy)
srv->proxy = proxy; srv->proxy = proxy;
LIST_INIT(&srv->actconns); LIST_INIT(&srv->actconns);
LIST_INIT(&srv->pendconns); LIST_INIT(&srv->pendconns);
LIST_INIT(&srv->priv_conns);
LIST_INIT(&srv->idle_conns); if ((srv->priv_conns = calloc(global.nbthread, sizeof(*srv->priv_conns))) == NULL)
LIST_INIT(&srv->safe_conns); goto free_srv;
if ((srv->idle_conns = calloc(global.nbthread, sizeof(*srv->idle_conns))) == NULL)
goto free_priv_conns;
if ((srv->safe_conns = calloc(global.nbthread, sizeof(*srv->safe_conns))) == NULL)
goto free_idle_conns;
for (i = 0; i < global.nbthread; i++) {
LIST_INIT(&srv->priv_conns[i]);
LIST_INIT(&srv->idle_conns[i]);
LIST_INIT(&srv->safe_conns[i]);
}
LIST_INIT(&srv->update_status); LIST_INIT(&srv->update_status);
srv->next_state = SRV_ST_RUNNING; /* early server setup */ srv->next_state = SRV_ST_RUNNING; /* early server setup */
@ -1537,6 +1549,14 @@ static struct server *new_server(struct proxy *proxy)
srv->xprt = srv->check.xprt = srv->agent.xprt = xprt_get(XPRT_RAW); srv->xprt = srv->check.xprt = srv->agent.xprt = xprt_get(XPRT_RAW);
return srv; return srv;
free_idle_conns:
free(srv->idle_conns);
free_priv_conns:
free(srv->priv_conns);
free_srv:
free(srv);
return NULL;
} }
/* /*