Author: rhuijben
Date: Thu Nov 26 10:07:47 2015
New Revision: 1716592
URL: http://svn.apache.org/viewvc?rev=1716592&view=rev
Log:
Implement basic windowing support for http/2. For now just use a constant
window for the connection and each stream and update it when it falls under
a treshold.
* protocols/http2_protocol.c
(serf_http2_protocol_t): Add some vars.
(http2_send_window_update): New function.
(serf__http2_protocol_init,
serf__http2_protocol_init_server): Initialize dynamic window state.
Use http2_send_window_update instead of hardcoded window update.
(http2_process): Update window when needed.
* protocols/http2_protocol.h
(serf_http2_stream_t): Add some vars.
* protocols/http2_stream.c
(serf_http2__stream_create): Initialize dynamic window state.
Modified:
serf/trunk/protocols/http2_protocol.c
serf/trunk/protocols/http2_protocol.h
serf/trunk/protocols/http2_stream.c
Modified: serf/trunk/protocols/http2_protocol.c
URL:
http://svn.apache.org/viewvc/serf/trunk/protocols/http2_protocol.c?rev=1716592&r1=1716591&r2=1716592&view=diff
==============================================================================
--- serf/trunk/protocols/http2_protocol.c (original)
+++ serf/trunk/protocols/http2_protocol.c Thu Nov 26 10:07:47 2015
@@ -161,6 +161,9 @@ struct serf_http2_protocol_t
apr_int32_t rl_next_streamid;
bool rl_push_enabled;
+ apr_uint32_t rl_window_upd_below;
+ apr_uint32_t rl_window_upd_to;
+
serf_http2_stream_t *first;
serf_http2_stream_t *last;
@@ -232,6 +235,59 @@ http2_protocol_cleanup(void *state)
return APR_SUCCESS;
}
+static void http2_send_window_update(serf_http2_protocol_t *h2,
+ serf_http2_stream_t *stream)
+{
+ apr_uint32_t increase;
+ apr_uint32_t *window;
+ apr_int32_t *stream_id;
+ serf_bucket_t *bkt;
+ apr_status_t status;
+ struct window_update_t
+ {
+ unsigned char v3, v2, v1, v0;
+ } window_update;
+
+ if (!stream) {
+ if (h2->rl_window >= h2->rl_window_upd_to)
+ return;
+
+ increase = h2->rl_window_upd_to - h2->rl_window;
+ window = &h2->rl_window;
+ stream_id = NULL;
+ }
+ else {
+ if (stream->rl_window >= stream->rl_window_upd_to)
+ return;
+
+ increase = stream->rl_window_upd_to - stream->rl_window;
+ window = &stream->rl_window;
+ stream_id = &stream->streamid;
+ }
+
+ window_update.v3 = (increase >> 24) & 0xFF;
+ window_update.v2 = (increase >> 16) & 0xFF;
+ window_update.v1 = (increase >> 8) & 0xFF;
+ window_update.v0 = increase & 0xFF;
+
+ bkt = serf_bucket_simple_copy_create((void *)&window_update,
+ sizeof(window_update),
+ h2->allocator);
+
+ bkt = serf__bucket_http2_frame_create(bkt, HTTP2_FRAME_TYPE_WINDOW_UPDATE,
+ 0, stream_id, NULL, NULL/* stream */,
+ h2->lr_max_framesize,
+ h2->allocator);
+ status = serf_http2__enqueue_frame(h2, bkt, FALSE);
+
+ if (!status) {
+ /* Update our administration */
+ (*window) += increase;
+ }
+
+ /* Ignore connection broken statee. Move along */
+}
+
void serf__http2_protocol_init(serf_connection_t *conn)
{
serf_http2_protocol_t *h2;
@@ -268,6 +324,9 @@ void serf__http2_protocol_init(serf_conn
h2->lr_hpack_table_size = HTTP2_DEFAULT_HPACK_TABLE_SIZE;
h2->lr_push_enabled = TRUE;
+ h2->rl_window_upd_below = 16 * 1024 * 1024; /* 16 MB*/
+ h2->rl_window_upd_to = 128 * 1024 * 1024; /* 128 MB */
+
h2->setting_acks = 0;
h2->enforce_flow_control = TRUE;
h2->continuation_bucket = NULL;
@@ -298,31 +357,16 @@ void serf__http2_protocol_init(serf_conn
tmp = SERF_BUCKET_SIMPLE_STRING(HTTP2_CONNECTION_PREFIX, h2->allocator);
serf_pump__add_output(h2->pump, tmp, false);
- /* And now a settings frame and a huge window */
- {
- serf_bucket_t *window_size;
-
- tmp = serf__bucket_http2_frame_create(NULL, HTTP2_FRAME_TYPE_SETTINGS,
+ /* And now a settings frame */
+ tmp = serf__bucket_http2_frame_create(NULL, HTTP2_FRAME_TYPE_SETTINGS,
0,
NULL, NULL, NULL, /* stream: 0 */
h2->lr_max_framesize,
h2->allocator);
+ serf_http2__enqueue_frame(h2, tmp, FALSE);
- serf_http2__enqueue_frame(h2, tmp, FALSE);
-
- /* Add 1GB to the current window. */
- window_size = serf_bucket_create_numberv(conn->allocator, "4",
- 0x40000000);
- tmp = serf__bucket_http2_frame_create(window_size,
- HTTP2_FRAME_TYPE_WINDOW_UPDATE,
- 0,
- NULL, NULL, NULL, /* stream: 0 */
- h2->lr_max_framesize,
- h2->allocator);
- serf_http2__enqueue_frame(h2, tmp, FALSE);
-
- h2->rl_window += 0x40000000; /* And update our own administration */
- }
+ /* And an initial window update */
+ http2_send_window_update(h2, NULL);
}
void serf__http2_protocol_init_server(serf_incoming_t *client)
@@ -363,6 +407,9 @@ void serf__http2_protocol_init_server(se
h2->lr_hpack_table_size = HTTP2_DEFAULT_HPACK_TABLE_SIZE;
h2->lr_push_enabled = TRUE;
+ h2->rl_window_upd_below = 16 * 1024 * 1024; /* 16 MB*/
+ h2->rl_window_upd_to = 128 * 1024 * 1024; /* 128 MB */
+
h2->setting_acks = 0;
h2->enforce_flow_control = TRUE;
h2->continuation_bucket = NULL;
@@ -383,31 +430,17 @@ void serf__http2_protocol_init_server(se
client->perform_teardown = http2_incoming_teardown;
client->protocol_baton = h2;
- /* Send a settings frame and a huge window */
- {
- serf_bucket_t *window_size;
-
- tmp = serf__bucket_http2_frame_create(NULL, HTTP2_FRAME_TYPE_SETTINGS,
- 0,
- NULL, NULL, NULL, /* stream: 0 */
- h2->lr_max_framesize,
- h2->allocator);
-
- serf_http2__enqueue_frame(h2, tmp, FALSE);
+ /* Send a settings frame */
+ tmp = serf__bucket_http2_frame_create(NULL, HTTP2_FRAME_TYPE_SETTINGS,
+ 0,
+ NULL, NULL, NULL, /* stream: 0 */
+ h2->lr_max_framesize,
+ h2->allocator);
- /* Add 1GB to the current window. */
- window_size = serf_bucket_create_numberv(h2->allocator, "4",
- 0x40000000);
- tmp = serf__bucket_http2_frame_create(window_size,
- HTTP2_FRAME_TYPE_WINDOW_UPDATE,
- 0,
- NULL, NULL, NULL, /* stream: 0 */
- h2->lr_max_framesize,
- h2->allocator);
- serf_http2__enqueue_frame(h2, tmp, FALSE);
+ serf_http2__enqueue_frame(h2, tmp, FALSE);
- h2->rl_window += 0x40000000; /* And update our own administration */
- }
+ /* And an initial window update*/
+ http2_send_window_update(h2, NULL);
}
/* Creates a HTTP/2 request from a serf request */
@@ -1131,6 +1164,9 @@ http2_process(serf_http2_protocol_t *h2)
else
h2->rl_window -= remaining;
+ if (h2->rl_window < h2->rl_window_upd_below)
+ http2_send_window_update(h2, NULL);
+
if (stream)
{
if (stream->rl_window < remaining)
@@ -1144,6 +1180,14 @@ http2_process(serf_http2_protocol_t *h2)
}
else
stream->rl_window -= remaining;
+
+ /* If the stream is not at the end, perhaps we
+ should allow it to send more data */
+ if (!(frameflags & HTTP2_FLAG_END_STREAM)
+ && stream->rl_window <
stream->rl_window_upd_below) {
+
+ http2_send_window_update(h2, stream);
+ }
}
}
Modified: serf/trunk/protocols/http2_protocol.h
URL:
http://svn.apache.org/viewvc/serf/trunk/protocols/http2_protocol.h?rev=1716592&r1=1716591&r2=1716592&view=diff
==============================================================================
--- serf/trunk/protocols/http2_protocol.h (original)
+++ serf/trunk/protocols/http2_protocol.h Thu Nov 26 10:07:47 2015
@@ -127,6 +127,9 @@ typedef struct serf_http2_stream_t
apr_uint32_t lr_window; /* local->remote */
apr_uint32_t rl_window; /* remote->local */
+ apr_uint32_t rl_window_upd_below;
+ apr_uint32_t rl_window_upd_to;
+
/* -1 until allocated. Odd is client side initiated, even server side */
apr_int32_t streamid;
Modified: serf/trunk/protocols/http2_stream.c
URL:
http://svn.apache.org/viewvc/serf/trunk/protocols/http2_stream.c?rev=1716592&r1=1716591&r2=1716592&view=diff
==============================================================================
--- serf/trunk/protocols/http2_stream.c (original)
+++ serf/trunk/protocols/http2_stream.c Thu Nov 26 10:07:47 2015
@@ -65,6 +65,9 @@ serf_http2__stream_create(serf_http2_pro
stream->lr_window = lr_window;
stream->rl_window = rl_window;
+ stream->rl_window_upd_below = 1024 * 1024;
+ stream->rl_window_upd_to = 16 * 1024 * 1024;
+
if (streamid >= 0)
stream->streamid = streamid;
else