Commit a11fbf6e authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

Optimize connection level remote flow control

Previously when connection level remote flow control window gets 0, we
mark the stream having DATA frame with
NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL.  When connection level
WINDOW_UPDATE is received, we checks all existing streams, including
closed ones, and call nghttp2_stream_resume_deferred_data().  The
profiler shows this is expensive.

Now we prepare dedicated priority queue for DATA frames.  And we don't
mark stream with NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL when DATA
cannot be sent solely due to connection level flow control.  Instead,
we just queue DATA item to queue.  We won't pop DATA item from queue
when connection level remote window size is 0.  This way, we avoid the
expensive operation for all streams when WINDOW_UPDATE is arrived.
parent 9aa914c7
This diff is collapsed.
...@@ -136,10 +136,13 @@ typedef enum { ...@@ -136,10 +136,13 @@ typedef enum {
struct nghttp2_session { struct nghttp2_session {
nghttp2_map /* <nghttp2_stream*> */ streams; nghttp2_map /* <nghttp2_stream*> */ streams;
nghttp2_stream_roots roots; nghttp2_stream_roots roots;
/* Queue for outbound frames other than stream-creating HEADERS */ /* Queue for outbound frames other than stream-creating HEADERS and
DATA */
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_pq; nghttp2_pq /* <nghttp2_outbound_item*> */ ob_pq;
/* Queue for outbound stream-creating HEADERS frame */ /* Queue for outbound stream-creating HEADERS frame */
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_ss_pq; nghttp2_pq /* <nghttp2_outbound_item*> */ ob_ss_pq;
/* QUeue for DATA frame */
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_da_pq;
nghttp2_active_outbound_item aob; nghttp2_active_outbound_item aob;
nghttp2_inbound_frame iframe; nghttp2_inbound_frame iframe;
nghttp2_hd_deflater hd_deflater; nghttp2_hd_deflater hd_deflater;
......
...@@ -2563,7 +2563,7 @@ void test_nghttp2_session_on_window_update_received(void) ...@@ -2563,7 +2563,7 @@ void test_nghttp2_session_on_window_update_received(void)
data_item->frame_cat = NGHTTP2_CAT_DATA; data_item->frame_cat = NGHTTP2_CAT_DATA;
CU_ASSERT(0 == nghttp2_stream_attach_data(stream, data_item, CU_ASSERT(0 == nghttp2_stream_attach_data(stream, data_item,
&session->ob_pq, &session->ob_da_pq,
session->last_cycle)); session->last_cycle));
nghttp2_frame_window_update_init(&frame.window_update, NGHTTP2_FLAG_NONE, nghttp2_frame_window_update_init(&frame.window_update, NGHTTP2_FLAG_NONE,
...@@ -2575,7 +2575,7 @@ void test_nghttp2_session_on_window_update_received(void) ...@@ -2575,7 +2575,7 @@ void test_nghttp2_session_on_window_update_received(void)
CU_ASSERT(0 == nghttp2_stream_defer_data CU_ASSERT(0 == nghttp2_stream_defer_data
(stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL, (stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL,
&session->ob_pq, session->last_cycle)); &session->ob_da_pq, session->last_cycle));
CU_ASSERT(0 == nghttp2_session_on_window_update_received(session, &frame)); CU_ASSERT(0 == nghttp2_session_on_window_update_received(session, &frame));
CU_ASSERT(2 == user_data.frame_recv_cb_called); CU_ASSERT(2 == user_data.frame_recv_cb_called);
...@@ -4538,7 +4538,7 @@ void test_nghttp2_session_defer_data(void) ...@@ -4538,7 +4538,7 @@ void test_nghttp2_session_defer_data(void)
/* Resume deferred DATA */ /* Resume deferred DATA */
CU_ASSERT(0 == nghttp2_session_resume_data(session, 1)); CU_ASSERT(0 == nghttp2_session_resume_data(session, 1));
item = nghttp2_session_get_ob_pq_top(session); item = (nghttp2_outbound_item*)nghttp2_pq_top(&session->ob_da_pq);
OB_DATA(item)->data_prd.read_callback = OB_DATA(item)->data_prd.read_callback =
fixed_length_data_source_read_callback; fixed_length_data_source_read_callback;
ud.block_count = 1; ud.block_count = 1;
...@@ -4556,7 +4556,7 @@ void test_nghttp2_session_defer_data(void) ...@@ -4556,7 +4556,7 @@ void test_nghttp2_session_defer_data(void)
/* Resume deferred DATA */ /* Resume deferred DATA */
CU_ASSERT(0 == nghttp2_session_resume_data(session, 1)); CU_ASSERT(0 == nghttp2_session_resume_data(session, 1));
item = nghttp2_session_get_ob_pq_top(session); item = (nghttp2_outbound_item*)nghttp2_pq_top(&session->ob_da_pq);
OB_DATA(item)->data_prd.read_callback = OB_DATA(item)->data_prd.read_callback =
fixed_length_data_source_read_callback; fixed_length_data_source_read_callback;
ud.block_count = 1; ud.block_count = 1;
...@@ -5579,7 +5579,8 @@ void test_nghttp2_session_stream_dep_add_subtree(void) ...@@ -5579,7 +5579,8 @@ void test_nghttp2_session_stream_dep_add_subtree(void)
* d * d
*/ */
nghttp2_stream_dep_add_subtree(a, e, &session->ob_pq, session->last_cycle); nghttp2_stream_dep_add_subtree(a, e, &session->ob_da_pq,
session->last_cycle);
/* becomes /* becomes
* a * a
...@@ -5630,7 +5631,8 @@ void test_nghttp2_session_stream_dep_add_subtree(void) ...@@ -5630,7 +5631,8 @@ void test_nghttp2_session_stream_dep_add_subtree(void)
* d * d
*/ */
nghttp2_stream_dep_insert_subtree(a, e, &session->ob_pq, session->last_cycle); nghttp2_stream_dep_insert_subtree(a, e, &session->ob_da_pq,
session->last_cycle);
/* becomes /* becomes
* a * a
...@@ -5823,7 +5825,7 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) ...@@ -5823,7 +5825,7 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void)
nghttp2_stream_dep_remove_subtree(c); nghttp2_stream_dep_remove_subtree(c);
CU_ASSERT(0 == nghttp2_stream_dep_all_your_stream_are_belong_to_us CU_ASSERT(0 == nghttp2_stream_dep_all_your_stream_are_belong_to_us
(c, &session->ob_pq, session->last_cycle)); (c, &session->ob_da_pq, session->last_cycle));
/* /*
* c * c
...@@ -5861,7 +5863,7 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) ...@@ -5861,7 +5863,7 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void)
nghttp2_stream_dep_remove_subtree(c); nghttp2_stream_dep_remove_subtree(c);
CU_ASSERT(0 == nghttp2_stream_dep_all_your_stream_are_belong_to_us CU_ASSERT(0 == nghttp2_stream_dep_all_your_stream_are_belong_to_us
(c, &session->ob_pq, session->last_cycle)); (c, &session->ob_da_pq, session->last_cycle));
/* /*
* c * c
...@@ -5898,7 +5900,7 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) ...@@ -5898,7 +5900,7 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void)
nghttp2_stream_dep_remove_subtree(c); nghttp2_stream_dep_remove_subtree(c);
CU_ASSERT(0 == nghttp2_stream_dep_all_your_stream_are_belong_to_us CU_ASSERT(0 == nghttp2_stream_dep_all_your_stream_are_belong_to_us
(c, &session->ob_pq, session->last_cycle)); (c, &session->ob_da_pq, session->last_cycle));
/* /*
* c * c
...@@ -5951,7 +5953,7 @@ void test_nghttp2_session_stream_attach_data(void) ...@@ -5951,7 +5953,7 @@ void test_nghttp2_session_stream_attach_data(void)
db = create_data_ob_item(); db = create_data_ob_item();
nghttp2_stream_attach_data(b, db, &session->ob_pq, session->last_cycle); nghttp2_stream_attach_data(b, db, &session->ob_da_pq, session->last_cycle);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
...@@ -5966,7 +5968,7 @@ void test_nghttp2_session_stream_attach_data(void) ...@@ -5966,7 +5968,7 @@ void test_nghttp2_session_stream_attach_data(void)
dc = create_data_ob_item(); dc = create_data_ob_item();
nghttp2_stream_attach_data(c, dc, &session->ob_pq, session->last_cycle); nghttp2_stream_attach_data(c, dc, &session->ob_da_pq, session->last_cycle);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
...@@ -5982,7 +5984,7 @@ void test_nghttp2_session_stream_attach_data(void) ...@@ -5982,7 +5984,7 @@ void test_nghttp2_session_stream_attach_data(void)
da = create_data_ob_item(); da = create_data_ob_item();
nghttp2_stream_attach_data(a, da, &session->ob_pq, session->last_cycle); nghttp2_stream_attach_data(a, da, &session->ob_da_pq, session->last_cycle);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == b->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == b->dpri);
...@@ -5993,7 +5995,7 @@ void test_nghttp2_session_stream_attach_data(void) ...@@ -5993,7 +5995,7 @@ void test_nghttp2_session_stream_attach_data(void)
CU_ASSERT(1 == da->queued); CU_ASSERT(1 == da->queued);
nghttp2_stream_detach_data(a, &session->ob_pq, session->last_cycle); nghttp2_stream_detach_data(a, &session->ob_da_pq, session->last_cycle);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
...@@ -6005,7 +6007,7 @@ void test_nghttp2_session_stream_attach_data(void) ...@@ -6005,7 +6007,7 @@ void test_nghttp2_session_stream_attach_data(void)
dd = create_data_ob_item(); dd = create_data_ob_item();
nghttp2_stream_attach_data(d, dd, &session->ob_pq, session->last_cycle); nghttp2_stream_attach_data(d, dd, &session->ob_da_pq, session->last_cycle);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
...@@ -6017,7 +6019,7 @@ void test_nghttp2_session_stream_attach_data(void) ...@@ -6017,7 +6019,7 @@ void test_nghttp2_session_stream_attach_data(void)
CU_ASSERT(0 == dd->queued); CU_ASSERT(0 == dd->queued);
nghttp2_stream_detach_data(c, &session->ob_pq, session->last_cycle); nghttp2_stream_detach_data(c, &session->ob_da_pq, session->last_cycle);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
...@@ -6060,11 +6062,11 @@ void test_nghttp2_session_stream_attach_data_subtree(void) ...@@ -6060,11 +6062,11 @@ void test_nghttp2_session_stream_attach_data_subtree(void)
de = create_data_ob_item(); de = create_data_ob_item();
nghttp2_stream_attach_data(e, de, &session->ob_pq, session->last_cycle); nghttp2_stream_attach_data(e, de, &session->ob_da_pq, session->last_cycle);
db = create_data_ob_item(); db = create_data_ob_item();
nghttp2_stream_attach_data(b, db, &session->ob_pq, session->last_cycle); nghttp2_stream_attach_data(b, db, &session->ob_da_pq, session->last_cycle);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
...@@ -6079,7 +6081,8 @@ void test_nghttp2_session_stream_attach_data_subtree(void) ...@@ -6079,7 +6081,8 @@ void test_nghttp2_session_stream_attach_data_subtree(void)
/* Insert subtree e under a */ /* Insert subtree e under a */
nghttp2_stream_dep_remove_subtree(e); nghttp2_stream_dep_remove_subtree(e);
nghttp2_stream_dep_insert_subtree(a, e, &session->ob_pq, session->last_cycle); nghttp2_stream_dep_insert_subtree(a, e, &session->ob_da_pq,
session->last_cycle);
/* /*
* a * a
...@@ -6104,7 +6107,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void) ...@@ -6104,7 +6107,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void)
nghttp2_stream_dep_remove_subtree(b); nghttp2_stream_dep_remove_subtree(b);
nghttp2_stream_dep_make_root(b, &session->ob_pq, session->last_cycle); nghttp2_stream_dep_make_root(b, &session->ob_da_pq, session->last_cycle);
/* /*
* a b * a b
...@@ -6130,7 +6133,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void) ...@@ -6130,7 +6133,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void)
nghttp2_stream_dep_remove_subtree(a); nghttp2_stream_dep_remove_subtree(a);
nghttp2_stream_dep_make_root(a, &session->ob_pq, session->last_cycle); nghttp2_stream_dep_make_root(a, &session->ob_da_pq, session->last_cycle);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
...@@ -6143,7 +6146,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void) ...@@ -6143,7 +6146,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void)
nghttp2_stream_dep_remove_subtree(c); nghttp2_stream_dep_remove_subtree(c);
nghttp2_stream_dep_make_root(c, &session->ob_pq, session->last_cycle); nghttp2_stream_dep_make_root(c, &session->ob_da_pq, session->last_cycle);
/* /*
* a b c * a b c
...@@ -6162,12 +6165,13 @@ void test_nghttp2_session_stream_attach_data_subtree(void) ...@@ -6162,12 +6165,13 @@ void test_nghttp2_session_stream_attach_data_subtree(void)
dd = create_data_ob_item(); dd = create_data_ob_item();
nghttp2_stream_attach_data(d, dd, &session->ob_pq, session->last_cycle); nghttp2_stream_attach_data(d, dd, &session->ob_da_pq, session->last_cycle);
/* Add subtree c to a */ /* Add subtree c to a */
nghttp2_stream_dep_remove_subtree(c); nghttp2_stream_dep_remove_subtree(c);
nghttp2_stream_dep_add_subtree(a, c, &session->ob_pq, session->last_cycle); nghttp2_stream_dep_add_subtree(a, c, &session->ob_da_pq,
session->last_cycle);
/* /*
* a b * a b
...@@ -6194,7 +6198,8 @@ void test_nghttp2_session_stream_attach_data_subtree(void) ...@@ -6194,7 +6198,8 @@ void test_nghttp2_session_stream_attach_data_subtree(void)
/* Insert b under a */ /* Insert b under a */
nghttp2_stream_dep_remove_subtree(b); nghttp2_stream_dep_remove_subtree(b);
nghttp2_stream_dep_insert_subtree(a, b, &session->ob_pq, session->last_cycle); nghttp2_stream_dep_insert_subtree(a, b, &session->ob_da_pq,
session->last_cycle);
/* /*
* a * a
...@@ -6221,7 +6226,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void) ...@@ -6221,7 +6226,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void)
/* Remove subtree b */ /* Remove subtree b */
nghttp2_stream_dep_remove_subtree(b); nghttp2_stream_dep_remove_subtree(b);
nghttp2_stream_dep_make_root(b, &session->ob_pq, session->last_cycle); nghttp2_stream_dep_make_root(b, &session->ob_da_pq, session->last_cycle);
/* /*
* b a * b a
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment