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


Reply via email to