]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: mux-h2: add a per-connection list of blocked streams
authorWilly Tarreau <w@1wt.eu>
Wed, 2 Oct 2019 08:49:59 +0000 (10:49 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 2 Oct 2019 12:16:14 +0000 (14:16 +0200)
Currently the H2 mux doesn't have a list of all the streams blocking on
the H2 side. It only knows about those trying to send or waiting for a
connection window update. It is problematic to enforce timeouts because
we never know if a stream has to live as long as the data layer wants or
has to be timed out becase it's waiting for a stream window update. This
patch adds a new list, "blocked_list", to store streams blocking on
stream flow control, or later, dependencies. Streams blocked on sfctl
are now added there. It doesn't modify the rest of the logic.

src/mux_h2.c

index 816cddc5c16ff50edcccd57727f7e6be173931db..94d387a85e36672f452358570651731a57a7546e 100644 (file)
@@ -131,6 +131,7 @@ struct h2c {
        struct eb_root streams_by_id; /* all active streams by their ID */
        struct list send_list; /* list of blocked streams requesting to send */
        struct list fctl_list; /* list of streams blocked by connection's fctl */
+       struct list blocked_list; /* list of streams blocked for other reasons (e.g. sfctl, dep) */
        struct list sending_list; /* list of h2s scheduled to send data */
        struct buffer_wait buf_wait; /* wait list for buffer allocations */
        struct wait_event wait_event;  /* To be used if we're waiting for I/Os */
@@ -169,9 +170,9 @@ enum h2_ss {
 
 /* stream flags indicating the reason the stream is blocked */
 #define H2_SF_BLK_MBUSY         0x00000010 // blocked waiting for mux access (transient)
-#define H2_SF_BLK_MROOM         0x00000020 // blocked waiting for room in the mux
-#define H2_SF_BLK_MFCTL         0x00000040 // blocked due to mux fctl
-#define H2_SF_BLK_SFCTL         0x00000080 // blocked due to stream fctl
+#define H2_SF_BLK_MROOM         0x00000020 // blocked waiting for room in the mux (must be in send list)
+#define H2_SF_BLK_MFCTL         0x00000040 // blocked due to mux fctl (must be in fctl list)
+#define H2_SF_BLK_SFCTL         0x00000080 // blocked due to stream fctl (must be in blocked list)
 #define H2_SF_BLK_ANY           0x000000F0 // any of the reasons above
 
 /* stream flags indicating how data is supposed to be sent */
@@ -829,6 +830,7 @@ static int h2_init(struct connection *conn, struct proxy *prx, struct session *s
        h2c->streams_by_id = EB_ROOT;
        LIST_INIT(&h2c->send_list);
        LIST_INIT(&h2c->fctl_list);
+       LIST_INIT(&h2c->blocked_list);
        LIST_INIT(&h2c->sending_list);
        LIST_INIT(&h2c->buf_wait.list);
 
@@ -1901,7 +1903,8 @@ static void h2c_unblock_sfctl(struct h2c *h2c)
                h2s = container_of(node, struct h2s, by_id);
                if (h2s->flags & H2_SF_BLK_SFCTL && h2s_mws(h2s) > 0) {
                        h2s->flags &= ~H2_SF_BLK_SFCTL;
-                       if (h2s->send_wait && !LIST_ADDED(&h2s->list))
+                       LIST_DEL_INIT(&h2s->list);
+                       if (h2s->send_wait)
                                LIST_ADDQ(&h2c->send_list, &h2s->list);
                }
                node = eb32_next(node);
@@ -2239,7 +2242,8 @@ static int h2c_handle_window_update(struct h2c *h2c, struct h2s *h2s)
                h2s->sws += inc;
                if (h2s_mws(h2s) > 0 && (h2s->flags & H2_SF_BLK_SFCTL)) {
                        h2s->flags &= ~H2_SF_BLK_SFCTL;
-                       if (h2s->send_wait && !LIST_ADDED(&h2s->list))
+                       LIST_DEL_INIT(&h2s->list);
+                       if (h2s->send_wait)
                                LIST_ADDQ(&h2c->send_list, &h2s->list);
                }
        }
@@ -5120,6 +5124,7 @@ static size_t h2s_frt_make_resp_data(struct h2s *h2s, struct buffer *buf, size_t
                h2s->flags |= H2_SF_BLK_SFCTL;
                if (LIST_ADDED(&h2s->list))
                        LIST_DEL_INIT(&h2s->list);
+               LIST_ADDQ(&h2c->blocked_list, &h2s->list);
                TRACE_STATE("stream window <=0, flow-controlled", H2_EV_TX_FRAME|H2_EV_TX_DATA|H2_EV_H2S_FCTL, h2c->conn, h2s);
                goto end;
        }
@@ -5737,10 +5742,12 @@ static size_t h2_snd_buf(struct conn_stream *cs, struct buffer *buf, size_t coun
                else
                        cs->flags |= CS_FL_ERR_PENDING;
        }
-       if (total > 0) {
-               /* Ok we managed to send something, leave the send_list */
+
+       if (total > 0 && !(h2s->flags & H2_SF_BLK_SFCTL)) {
+               /* Ok we managed to send something, leave the send_list if we were still there */
                LIST_DEL_INIT(&h2s->list);
        }
+
        TRACE_LEAVE(H2_EV_H2S_SEND|H2_EV_STRM_SEND, h2s->h2c->conn, h2s);
        return total;
 }