MEDIUM: threads/server: Make connection list (priv/idle/safe) thread-safe
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 3 Jul 2017 13:41:01 +0000 (15:41 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 31 Oct 2017 12:58:30 +0000 (13:58 +0100)
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.

include/types/server.h
src/backend.c
src/hlua.c
src/proto_http.c
src/server.c

index 69397c1..ecf04d7 100644 (file)
@@ -207,9 +207,9 @@ struct server {
 
        struct list pendconns;                  /* pending connections */
        struct list actconns;                   /* active connections */
-       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 safe_conns;                 /* safe idle connections attached to stream interfaces, shared */
+       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 *safe_conns;                /* safe idle connections attached to stream interfaces, shared */
        struct task *warmup;                    /* the task dedicated to the warmup when slowstart is set */
 
        struct conn_src conn_src;               /* connection source settings */
index 475efa3..5e51f39 100644 (file)
@@ -1066,20 +1066,19 @@ int connect_server(struct stream *s)
                 *  idle|  -  |  1  |    idle|  -  |  1  |   idle|  2  |  1  |
                 *  ----+-----+-----+    ----+-----+-----+   ----+-----+-----+
                 */
-
-               if (!LIST_ISEMPTY(&srv->idle_conns) &&
+               if (srv->idle_conns && !LIST_ISEMPTY(&srv->idle_conns[tid]) &&
                    ((s->be->options & PR_O_REUSE_MASK) != PR_O_REUSE_NEVR &&
                     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->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) {
-                       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
index 137117c..36b1b3f 100644 (file)
@@ -7666,9 +7666,9 @@ void hlua_init(void)
        socket_tcp.obj_type = OBJ_TYPE_SERVER;
        LIST_INIT(&socket_tcp.actconns);
        LIST_INIT(&socket_tcp.pendconns);
-       LIST_INIT(&socket_tcp.priv_conns);
-       LIST_INIT(&socket_tcp.idle_conns);
-       LIST_INIT(&socket_tcp.safe_conns);
+       socket_tcp.priv_conns = NULL;
+       socket_tcp.idle_conns = NULL;
+       socket_tcp.safe_conns = NULL;
        socket_tcp.next_state = SRV_ST_RUNNING; /* early server setup */
        socket_tcp.last_change = 0;
        socket_tcp.id = "LUA-TCP-CONN";
@@ -7712,9 +7712,9 @@ void hlua_init(void)
        socket_ssl.obj_type = OBJ_TYPE_SERVER;
        LIST_INIT(&socket_ssl.actconns);
        LIST_INIT(&socket_ssl.pendconns);
-       LIST_INIT(&socket_ssl.priv_conns);
-       LIST_INIT(&socket_ssl.idle_conns);
-       LIST_INIT(&socket_ssl.safe_conns);
+       socket_tcp.priv_conns = NULL;
+       socket_tcp.idle_conns = NULL;
+       socket_tcp.safe_conns = NULL;
        socket_ssl.next_state = SRV_ST_RUNNING; /* early server setup */
        socket_ssl.last_change = 0;
        socket_ssl.id = "LUA-SSL-CONN";
index cfc0e72..cf1cc7a 100644 (file)
@@ -4348,15 +4348,15 @@ void http_end_txn_clean_session(struct stream *s)
                if (!srv)
                        si_idle_conn(&s->si[1], NULL);
                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)
                        /* note: we check the request, not the connection, but
                         * this is valid for strategies SAFE and AGGR, and in
                         * 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
-                       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->res.analysers = 0;
index 01a7d9b..4c70ac4 100644 (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)
 {
        struct server *srv;
+       int i;
 
        srv = calloc(1, sizeof *srv);
        if (!srv)
@@ -1520,9 +1521,20 @@ static struct server *new_server(struct proxy *proxy)
        srv->proxy = proxy;
        LIST_INIT(&srv->actconns);
        LIST_INIT(&srv->pendconns);
-       LIST_INIT(&srv->priv_conns);
-       LIST_INIT(&srv->idle_conns);
-       LIST_INIT(&srv->safe_conns);
+
+       if ((srv->priv_conns = calloc(global.nbthread, sizeof(*srv->priv_conns))) == NULL)
+               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);
 
        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);
 
        return srv;
+
+  free_idle_conns:
+       free(srv->idle_conns);
+  free_priv_conns:
+       free(srv->priv_conns);
+  free_srv:
+       free(srv);
+       return NULL;
 }
 
 /*