|
|
- commit 5a9c875f0f1ee83bd5889dd1ad53e9da43e6c34e
- Author: Willy Tarreau <w@1wt.eu>
- Date: Fri Aug 2 07:52:08 2019 +0200
-
- BUG/MEDIUM: mux-h2: split the stream's and connection's window sizes
-
- The SETTINGS frame parser updates all streams' window for each
- INITIAL_WINDOW_SIZE setting received on the connection (like h2spec
- does in test 6.5.3), which can start to be expensive if repeated when
- there are many streams (up to 100 by default). A quick test shows that
- it's possible to parse only 35000 settings per second on a 3 GHz core
- for 100 streams, which is rather small.
-
- Given that window sizes are relative and may be negative, there's no
- point in pre-initializing them for each stream and update them from
- the settings. Instead, let's make them relative to the connection's
- initial window size so that any change immediately affects all streams.
- The only thing that remains needed is to wake up the streams that were
- unblocked by the update, which is now done once at the end of
- h2_process_demux() instead of once per setting. This now results in
- 5.7 million settings being processed per second, which is way better.
-
- In order to keep the change small, the h2s' mws field was renamed to
- "sws" for "stream window size", and an h2s_mws() function was added
- to add it to the connection's initial window setting and determine the
- window size to use when muxing. The h2c_update_all_ws() function was
- renamed to h2c_unblock_sfctl() since it's now only used to unblock
- previously blocked streams.
-
- This needs to be backported to all versions till 1.8.
-
- (cherry picked from commit 1d4a0f88100daeb17dd0c9470c659b1ec288bc07)
- [wt: context adjustment, port to legacy parts]
- Signed-off-by: Willy Tarreau <w@1wt.eu>
-
- diff --git a/src/mux_h2.c b/src/mux_h2.c
- index d605fe94..f90e9435 100644
- --- a/src/mux_h2.c
- +++ b/src/mux_h2.c
- @@ -208,7 +208,7 @@ struct h2s {
- struct eb32_node by_id; /* place in h2c's streams_by_id */
- int32_t id; /* stream ID */
- uint32_t flags; /* H2_SF_* */
- - int mws; /* mux window size for this stream */
- + int sws; /* stream window size, to be added to the mux's initial window size */
- enum h2_err errcode; /* H2 err code (H2_ERR_*) */
- enum h2_ss st;
- uint16_t status; /* HTTP response status */
- @@ -707,6 +707,14 @@ static inline __maybe_unused int h2s_id(const struct h2s *h2s)
- return h2s ? h2s->id : 0;
- }
-
- +/* returns the sum of the stream's own window size and the mux's initial
- + * window, which together form the stream's effective window size.
- + */
- +static inline int h2s_mws(const struct h2s *h2s)
- +{
- + return h2s->sws + h2s->h2c->miw;
- +}
- +
- /* returns true of the mux is currently busy as seen from stream <h2s> */
- static inline __maybe_unused int h2c_mux_busy(const struct h2c *h2c, const struct h2s *h2s)
- {
- @@ -945,7 +953,7 @@ static struct h2s *h2s_new(struct h2c *h2c, int id)
- LIST_INIT(&h2s->sending_list);
- h2s->h2c = h2c;
- h2s->cs = NULL;
- - h2s->mws = h2c->miw;
- + h2s->sws = 0;
- h2s->flags = H2_SF_NONE;
- h2s->errcode = H2_ERR_NO_ERROR;
- h2s->st = H2_SS_IDLE;
- @@ -1543,30 +1551,23 @@ static void h2_wake_some_streams(struct h2c *h2c, int last)
- }
- }
-
- -/* Increase all streams' outgoing window size by the difference passed in
- - * argument. This is needed upon receipt of the settings frame if the initial
- - * window size is different. The difference may be negative and the resulting
- - * window size as well, for the time it takes to receive some window updates.
- +/* Wake up all blocked streams whose window size has become positive after the
- + * mux's initial window was adjusted. This should be done after having processed
- + * SETTINGS frames which have updated the mux's initial window size.
- */
- -static void h2c_update_all_ws(struct h2c *h2c, int diff)
- +static void h2c_unblock_sfctl(struct h2c *h2c)
- {
- struct h2s *h2s;
- struct eb32_node *node;
-
- - if (!diff)
- - return;
- -
- node = eb32_first(&h2c->streams_by_id);
- while (node) {
- h2s = container_of(node, struct h2s, by_id);
- - h2s->mws += diff;
- -
- - if (h2s->mws > 0 && (h2s->flags & H2_SF_BLK_SFCTL)) {
- + 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_ADDQ(&h2c->send_list, &h2s->list);
- }
- -
- node = eb32_next(node);
- }
- }
- @@ -1607,7 +1608,6 @@ static int h2c_handle_settings(struct h2c *h2c)
- error = H2_ERR_FLOW_CONTROL_ERROR;
- goto fail;
- }
- - h2c_update_all_ws(h2c, arg - h2c->miw);
- h2c->miw = arg;
- break;
- case H2_SETTINGS_MAX_FRAME_SIZE:
- @@ -1869,13 +1869,13 @@ static int h2c_handle_window_update(struct h2c *h2c, struct h2s *h2s)
- goto strm_err;
- }
-
- - if (h2s->mws >= 0 && h2s->mws + inc < 0) {
- + if (h2s_mws(h2s) >= 0 && h2s_mws(h2s) + inc < 0) {
- error = H2_ERR_FLOW_CONTROL_ERROR;
- goto strm_err;
- }
-
- - h2s->mws += inc;
- - if (h2s->mws > 0 && (h2s->flags & H2_SF_BLK_SFCTL)) {
- + 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_ADDQ(&h2c->send_list, &h2s->list);
- @@ -2237,6 +2237,7 @@ static void h2_process_demux(struct h2c *h2c)
- struct h2s *h2s = NULL, *tmp_h2s;
- struct h2_fh hdr;
- unsigned int padlen = 0;
- + int32_t old_iw = h2c->miw;
-
- if (h2c->st0 >= H2_CS_ERROR)
- return;
- @@ -2625,6 +2626,9 @@ static void h2_process_demux(struct h2c *h2c)
- h2s_notify_recv(h2s);
- }
-
- + if (old_iw != h2c->miw)
- + h2c_unblock_sfctl(h2c);
- +
- h2c_restart_reading(h2c, 0);
- }
-
- @@ -4259,8 +4263,8 @@ static size_t h2s_frt_make_resp_data(struct h2s *h2s, const struct buffer *buf,
- if (size > max)
- size = max;
-
- - if (size > h2s->mws)
- - size = h2s->mws;
- + if (size > h2s_mws(h2s))
- + size = h2s_mws(h2s);
-
- if (size <= 0) {
- h2s->flags |= H2_SF_BLK_SFCTL;
- @@ -4362,7 +4366,7 @@ static size_t h2s_frt_make_resp_data(struct h2s *h2s, const struct buffer *buf,
- ofs += size;
- total += size;
- h1m->curr_len -= size;
- - h2s->mws -= size;
- + h2s->sws -= size;
- h2c->mws -= size;
-
- if (size && !h1m->curr_len && (h1m->flags & H1_MF_CHNK)) {
- @@ -4390,7 +4394,7 @@ static size_t h2s_frt_make_resp_data(struct h2s *h2s, const struct buffer *buf,
- }
-
- end:
- - trace("[%d] sent simple H2 DATA response (sid=%d) = %d bytes out (%u in, st=%s, ep=%u, es=%s, h2cws=%d h2sws=%d) data=%u", h2c->st0, h2s->id, size+9, (unsigned int)total, h1m_state_str(h1m->state), h1m->err_pos, h1m_state_str(h1m->err_state), h2c->mws, h2s->mws, (unsigned int)b_data(buf));
- + trace("[%d] sent simple H2 DATA response (sid=%d) = %d bytes out (%u in, st=%s, ep=%u, es=%s, h2cws=%d h2sws=%d) data=%u", h2c->st0, h2s->id, size+9, (unsigned int)total, h1m_state_str(h1m->state), h1m->err_pos, h1m_state_str(h1m->err_state), h2c->mws, h2s_mws(h2s), (unsigned int)b_data(buf));
- return total;
- }
-
- @@ -4937,7 +4941,7 @@ static size_t h2s_htx_frt_make_resp_data(struct h2s *h2s, struct buffer *buf, si
- */
- if (unlikely(fsize == count &&
- htx->used == 1 && type == HTX_BLK_DATA &&
- - fsize <= h2s->mws && fsize <= h2c->mws && fsize <= h2c->mfs)) {
- + fsize <= h2s_mws(h2s) && fsize <= h2c->mws && fsize <= h2c->mfs)) {
- void *old_area = mbuf->area;
-
- if (b_data(mbuf)) {
- @@ -4972,7 +4976,7 @@ static size_t h2s_htx_frt_make_resp_data(struct h2s *h2s, struct buffer *buf, si
- h2_set_frame_size(outbuf.area, fsize);
-
- /* update windows */
- - h2s->mws -= fsize;
- + h2s->sws -= fsize;
- h2c->mws -= fsize;
-
- /* and exchange with our old area */
- @@ -5024,7 +5028,7 @@ static size_t h2s_htx_frt_make_resp_data(struct h2s *h2s, struct buffer *buf, si
- if (!fsize)
- goto send_empty;
-
- - if (h2s->mws <= 0) {
- + if (h2s_mws(h2s) <= 0) {
- h2s->flags |= H2_SF_BLK_SFCTL;
- if (LIST_ADDED(&h2s->list))
- LIST_DEL_INIT(&h2s->list);
- @@ -5034,8 +5038,8 @@ static size_t h2s_htx_frt_make_resp_data(struct h2s *h2s, struct buffer *buf, si
- if (fsize > count)
- fsize = count;
-
- - if (fsize > h2s->mws)
- - fsize = h2s->mws; // >0
- + if (fsize > h2s_mws(h2s))
- + fsize = h2s_mws(h2s); // >0
-
- if (h2c->mfs && fsize > h2c->mfs)
- fsize = h2c->mfs; // >0
- @@ -5071,7 +5075,7 @@ static size_t h2s_htx_frt_make_resp_data(struct h2s *h2s, struct buffer *buf, si
-
- /* now let's copy this this into the output buffer */
- memcpy(outbuf.area + 9, htx_get_blk_ptr(htx, blk), fsize);
- - h2s->mws -= fsize;
- + h2s->sws -= fsize;
- h2c->mws -= fsize;
- count -= fsize;
-
|