]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: stream: Attach the read side on the response as soon as possible
authorChristopher Faulet <cfaulet@haproxy.com>
Thu, 9 May 2019 09:46:52 +0000 (11:46 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 10 May 2019 09:47:00 +0000 (11:47 +0200)
A backend stream-interface attached to a reused connection remains in the state
SI_ST_CONN until some data are sent to validate the connection. But when the
url_param algorithm is used to balance connections, no data are sent while the
connection is not established. So it is a chicken and egg situation.

To solve the problem, if no error is detected and when the request channel is
waiting for the connect(), we mark the read side as attached on the response
channel as soon as possible and we wake the request channel up once. This
happens in 2 places. The first one is right after the connect(), when the
stream-interface is still in state SI_ST_CON, in the function
sess_update_st_con_tcp(). The second one is when an applet is used instead of a
real connection to a server, in the function sess_prepare_conn_req(). In fact,
it is done when the backend stream-interface is set to the state SI_ST_EST.

This patch must be backported to 1.9.

src/stream.c

index 8c2ea5561830ee996a2ae9c1121de4561eaffeb5..58e1cc11b8110db47f809d8c01305808ceaef094 100644 (file)
@@ -711,6 +711,16 @@ static int sess_update_st_con_tcp(struct stream *s)
                return 1;
        }
 
+       /* If the request channel is waiting for the connect(), we mark the read
+        * side as attached on the response channel and we wake up it once. So
+        * it will have a chance to forward data now.
+        */
+       if (req->flags & CF_WAKE_CONNECT) {
+               rep->flags |= CF_READ_ATTACHED;
+               req->flags |= CF_WAKE_ONCE;
+               req->flags &= ~CF_WAKE_CONNECT;
+       }
+
        /* we need to wait a bit more if there was no activity either */
        if (!(req->flags & CF_WRITE_ACTIVITY))
                return 1;
@@ -900,10 +910,6 @@ static void sess_establish(struct stream *s)
 
        si_rx_endp_more(si);
        rep->flags |= CF_READ_ATTACHED; /* producer is now attached */
-       if (req->flags & CF_WAKE_CONNECT) {
-               req->flags |= CF_WAKE_ONCE;
-               req->flags &= ~CF_WAKE_CONNECT;
-       }
        if (objt_cs(si->end)) {
                /* real connections have timeouts */
                req->wto = s->be->timeout.server;
@@ -1181,6 +1187,17 @@ static void sess_prepare_conn_req(struct stream *s)
                        return;
                }
 
+               /* For applets, there is no connection establishment, but if the
+                * request channel is waiting for it, we mark the read side as
+                * attached on the response channel and we wake up it once. So
+                * it will have a chance to forward data now.
+                */
+               if (s->req.flags & CF_WAKE_CONNECT) {
+                       s->res.flags |= CF_READ_ATTACHED;
+                       s->req.flags |= CF_WAKE_ONCE;
+                       s->req.flags &= ~CF_WAKE_CONNECT;
+               }
+
                if (tv_iszero(&s->logs.tv_request))
                        s->logs.tv_request = now;
                s->logs.t_queue   = tv_ms_elapsed(&s->logs.tv_accept, &now);