]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MAJOR: backend: improve the connection reuse mechanism
authorWilly Tarreau <w@1wt.eu>
Thu, 6 Aug 2015 09:37:10 +0000 (11:37 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 6 Aug 2015 09:41:06 +0000 (11:41 +0200)
Now instead of closing the existing connection attached to the
stream interface, we first check if the one we pick was attached to
another stream interface, in which case the connections are swapped
if possible (eg: if the current connection is not private). That way
the previous connection remains attached to an existing session and
significantly increases the chances of being reused.

src/backend.c

index b31061a2395f7118a73a46447014f5eee87a40a5..93eecbf0c7e1913537d07811de6420bfacdba361 100644 (file)
@@ -1025,6 +1025,7 @@ int connect_server(struct stream *s)
 {
        struct connection *cli_conn;
        struct connection *srv_conn;
+       struct connection *old_conn;
        struct server *srv;
        int reuse = 0;
        int err;
@@ -1035,30 +1036,44 @@ int connect_server(struct stream *s)
                reuse = s->target == srv_conn->target;
 
        if (srv && !reuse) {
-               if (srv_conn) {
-                       srv_conn->owner = NULL;
-                       si_release_endpoint(&s->si[1]);
+               old_conn = srv_conn;
+               if (old_conn) {
                        srv_conn = NULL;
+                       old_conn->owner = NULL;
+                       si_detach_endpoint(&s->si[1]);
+                       /* note: if the connection was in a server's idle
+                        * queue, it doesn't get dequeued.
+                        */
                }
 
                if ((s->be->options & PR_O_REUSE_MASK) == PR_O_REUSE_ALWS &&
                    !LIST_ISEMPTY(&srv->idle_conns)) {
                        /* We're going to have to pick the first connection
                         * from this pool and use it for our purposes. We may
-                        * have to get rid of the current idle connection. It
-                        * may move to another pool, but we know we're not
-                        * interested in it.
+                        * have to get rid of the current idle connection, so
+                        * for this we try to swap it with the other owner's.
+                        * That way it may remain alive for others to pick.
                         */
-                       /* pick first connection. We know there's at least one */
                        srv_conn = LIST_ELEM(srv->idle_conns.n, struct connection *, list);
 
                        LIST_DEL(&srv_conn->list);
                        LIST_INIT(&srv_conn->list);
 
-                       si_detach_endpoint(srv_conn->owner);
+                       if (srv_conn->owner) {
+                               si_detach_endpoint(srv_conn->owner);
+                               if (old_conn && !(old_conn->flags & CO_FL_PRIVATE))
+                                       si_attach_conn(srv_conn->owner, old_conn);
+                       }
                        si_attach_conn(&s->si[1], srv_conn);
                        reuse = 1;
                }
+
+               if (old_conn && !old_conn->owner) {
+                       /* we couldn't swap our connection, let's release it */
+                       LIST_DEL(&old_conn->list);
+                       conn_force_close(old_conn);
+                       conn_free(old_conn);
+               }
        }
 
        if (reuse) {