From 9054273da98be9a8270f33b64603d9ad81521d96 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 28 Sep 2021 13:21:05 +0200 Subject: [PATCH] v2.0.0-rc2 -------------------------------------------------------------------------------- * Switching from a thread-safe apr pollset (not supported under Windows) to a wakeable pollset implementation. * Adding a clear error in the logs if the pollset could not be created. --- ChangeLog | 6 ++++++ mod_http2/h2_mplx.c | 31 +++++++++++++++++++++++-------- mod_http2/h2_mplx.h | 4 ++-- mod_http2/h2_session.c | 6 +++++- mod_http2/h2_version.h | 2 +- mod_http2/h2_version.h.in | 2 +- test/load_test.py | 33 ++++++++++++++++++++++++++++++++- 7 files changed, 70 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index 509daf95..30e946ce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +v2.0.0-rc2 +-------------------------------------------------------------------------------- + * Switching from a thread-safe apr pollset (not supported under Windows) to + a wakeable pollset implementation. + * Adding a clear error in the logs if the pollset could not be created. + v2.0.0-rc1 -------------------------------------------------------------------------------- * HTTP/2 connections now use pollsets to monitor the status of the diff --git a/mod_http2/h2_mplx.c b/mod_http2/h2_mplx.c index 5cddc561..4e5584c9 100644 --- a/mod_http2/h2_mplx.c +++ b/mod_http2/h2_mplx.c @@ -222,7 +222,12 @@ h2_mplx *h2_mplx_c1_create(h2_stream *stream0, server_rec *s, apr_pool_t *parent m->mood_update_interval = apr_time_from_msec(100); status = mplx_pollset_create(m); - if (APR_SUCCESS != status) goto failure; + if (APR_SUCCESS != status) { + ap_log_cerror(APLOG_MARK, APLOG_ERR, status, m->c1, APLOGNO() + "nghttp2: could not create pollset"); + goto failure; + } + m->streams_to_poll = apr_array_make(m->pool, 10, sizeof(h2_stream*)); m->streams_ev_in = apr_array_make(m->pool, 10, sizeof(h2_stream*)); m->streams_ev_out = apr_array_make(m->pool, 10, sizeof(h2_stream*)); @@ -671,7 +676,9 @@ static conn_rec *s_next_c2(h2_mplx *m) stream->c2 = c2; ++m->processing_count; - mplx_pollset_add(m, conn_ctx); + APR_ARRAY_PUSH(m->streams_to_poll, h2_stream *) = stream; + apr_pollset_wakeup(m->pollset); + return c2; } @@ -890,7 +897,7 @@ static apr_status_t mplx_pollset_create(h2_mplx *m) /* stream0 output, pdf_out+pfd_in_consume per active streams */ max_pdfs = 1 + 2 * H2MIN(m->processing_max, m->max_streams); return apr_pollset_create(&m->pollset, max_pdfs, m->pool, - APR_POLLSET_THREADSAFE); + APR_POLLSET_WAKEABLE); } static apr_status_t mplx_pollset_add(h2_mplx *m, h2_conn_ctx_t *conn_ctx) @@ -963,11 +970,22 @@ static apr_status_t mplx_pollset_poll(h2_mplx *m, apr_interval_time_t timeout, ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, m->c1, "h2_mplx(%ld): enter polling timeout=%d", m->id, (int)apr_time_sec(timeout)); - H2_MPLX_LEAVE(m); do { + /* add streams we started processing in the meantime */ + if (m->streams_to_poll->nelts) { + for (i = 0; i < m->streams_to_poll->nelts; ++i) { + stream = APR_ARRAY_IDX(m->streams_to_poll, i, h2_stream*); + if (stream->c2 && (conn_ctx = h2_conn_ctx_get(stream->c2))) { + mplx_pollset_add(m, conn_ctx); + } + } + apr_array_clear(m->streams_to_poll); + } + + H2_MPLX_LEAVE(m); rv = apr_pollset_poll(m->pollset, timeout >= 0? timeout : -1, &nresults, &results); + H2_MPLX_ENTER(m); } while (APR_STATUS_IS_EINTR(rv)); - H2_MPLX_ENTER(m); if (APR_SUCCESS != rv) { if (APR_STATUS_IS_TIMEUP(rv)) { @@ -1062,9 +1080,6 @@ static apr_status_t mplx_pollset_poll(h2_mplx *m, apr_interval_time_t timeout, pfd->rtnevents); if (on_stream_input) { APR_ARRAY_PUSH(m->streams_ev_in, h2_stream*) = stream; - H2_MPLX_LEAVE(m); - on_stream_input(on_ctx, stream); - H2_MPLX_ENTER(m); } } } diff --git a/mod_http2/h2_mplx.h b/mod_http2/h2_mplx.h index 9489957e..6328ed29 100644 --- a/mod_http2/h2_mplx.h +++ b/mod_http2/h2_mplx.h @@ -31,7 +31,6 @@ */ struct apr_pool_t; -struct apr_array_header_t; struct apr_thread_mutex_t; struct apr_thread_cond_t; struct h2_bucket_beam; @@ -60,7 +59,7 @@ struct h2_mplx { struct h2_ihash_t *streams; /* all streams active */ struct h2_ihash_t *shold; /* all streams done with c2 processing ongoing */ - struct apr_array_header_t *spurge; /* all streams done, ready for destroy */ + apr_array_header_t *spurge; /* all streams done, ready for destroy */ struct h2_iqueue *q; /* all stream ids that need to be started */ @@ -80,6 +79,7 @@ struct h2_mplx { struct apr_thread_cond_t *join_wait; apr_pollset_t *pollset; /* pollset for c1/c2 IO events */ + apr_array_header_t *streams_to_poll; /* streams to add to the pollset */ apr_array_header_t *streams_ev_in; apr_array_header_t *streams_ev_out; diff --git a/mod_http2/h2_session.c b/mod_http2/h2_session.c index 44cefba5..574c858c 100644 --- a/mod_http2/h2_session.c +++ b/mod_http2/h2_session.c @@ -857,7 +857,11 @@ apr_status_t h2_session_create(h2_session **psession, conn_rec *c, request_rec * stream0 = h2_stream_create(0, session->pool, session, NULL, 0); stream0->c2 = session->c1; /* stream0's connection is the main connection */ session->mplx = h2_mplx_c1_create(stream0, s, session->pool, workers); - + if (!session->mplx) { + apr_pool_destroy(pool); + return APR_ENOTIMPL; + } + h2_c1_io_init(&session->io, c, s); session->padding_max = h2_config_sgeti(s, H2_CONF_PADDING_BITS); if (session->padding_max) { diff --git a/mod_http2/h2_version.h b/mod_http2/h2_version.h index 023cd502..b75e1a03 100644 --- a/mod_http2/h2_version.h +++ b/mod_http2/h2_version.h @@ -27,7 +27,7 @@ * @macro * Version number of the http2 module as c string */ -#define MOD_HTTP2_VERSION "2.0.0-rc1-git" +#define MOD_HTTP2_VERSION "2.0.0-rc2-git" /** * @macro diff --git a/mod_http2/h2_version.h.in b/mod_http2/h2_version.h.in index 0678660a..11e9679a 100644 --- a/mod_http2/h2_version.h.in +++ b/mod_http2/h2_version.h.in @@ -27,7 +27,7 @@ * @macro * Version number of the http2 module as c string */ -#define MOD_HTTP2_VERSION "@PACKAGE_VERSION@-rc1-git" +#define MOD_HTTP2_VERSION "@PACKAGE_VERSION@-rc2-git" /** * @macro diff --git a/test/load_test.py b/test/load_test.py index 93e65f92..187a2807 100644 --- a/test/load_test.py +++ b/test/load_test.py @@ -750,7 +750,38 @@ def main(cls): {"run": 19}, {"run": 20}, ], - } + }, + "m6": { + "title": "1k files, 1k-10MB, *conn, 10k req ({measure})", + "class": UrlsLoadTest, + "location": "/", + "file_count": 1024, + "file_sizes": [1, 2, 3, 4, 5, 10, 20, 30, 40, 50, 100, 10000], + "requests": 5000, + "warmup": True, + "measure": "req/s", + "protocol": 'h2', + "max_parallel": 6, + "row0_title": "protocol max", + "row_title": "{protocol} {max_parallel:3d}", + "rows": [ + {"protocol": 'h2', "max_parallel": 6}, + {"protocol": 'h2', "max_parallel": 6}, + {"protocol": 'h2', "max_parallel": 6}, + {"protocol": 'h2', "max_parallel": 6}, + {"protocol": 'h2', "max_parallel": 6}, + {"protocol": 'h2', "max_parallel": 6}, + ], + "col_title": "{clients}c", + "clients": 1, + "columns": [ + {"clients": 1, "requests": 1000}, + {"clients": 32, "requests": 16000}, + {"clients": 64, "requests": 32000}, + {"clients": 128, "requests": 64000}, + {"clients": 192, "requests": 96000}, + ], + }, } env = H2TestEnv()