Reintroduce priority adjustment for DATA frame

This mechanism existed but was deleted. We bring it back in order to
prevent lower priority streams from starving.
This commit is contained in:
Tatsuhiro Tsujikawa 2013-12-05 23:12:18 +09:00
parent e596385fc0
commit 1dea4e154b
3 changed files with 34 additions and 6 deletions

View File

@ -48,7 +48,12 @@ typedef struct {
nghttp2_frame_category frame_cat; nghttp2_frame_category frame_cat;
void *frame; void *frame;
void *aux_data; void *aux_data;
int pri; /* The priority used in priority comparion */
int32_t pri;
/* The initial priority */
int32_t inipri;
/* The amount of priority decrement in next time */
uint32_t pri_decay;
int64_t seq; int64_t seq;
} nghttp2_outbound_item; } nghttp2_outbound_item;

View File

@ -424,7 +424,8 @@ static int outbound_item_update_pri
return 0; return 0;
} }
} }
item->pri = stream->pri; /* We only update initial priority */
item->inipri = stream->pri;
return 1; return 1;
} }
@ -442,10 +443,12 @@ void nghttp2_session_reprioritize_stream
return; return;
} }
stream->pri = pri; stream->pri = pri;
/* For submitted frames, we only update initial priority, so the
structure of the queue will remain unchanged. */
nghttp2_pq_update(&session->ob_pq, update_stream_pri, stream); nghttp2_pq_update(&session->ob_pq, update_stream_pri, stream);
nghttp2_pq_update(&session->ob_ss_pq, update_stream_pri, stream); nghttp2_pq_update(&session->ob_ss_pq, update_stream_pri, stream);
if(stream->deferred_data) { if(stream->deferred_data) {
stream->deferred_data->pri = pri; stream->deferred_data->inipri = pri;
} }
if(session->aob.item) { if(session->aob.item) {
outbound_item_update_pri(session->aob.item, stream); outbound_item_update_pri(session->aob.item, stream);
@ -471,6 +474,7 @@ int nghttp2_session_add_frame(nghttp2_session *session,
item->seq = session->next_seq++; item->seq = session->next_seq++;
/* Set priority to the default value at the moment. */ /* Set priority to the default value at the moment. */
item->pri = NGHTTP2_PRI_DEFAULT; item->pri = NGHTTP2_PRI_DEFAULT;
item->pri_decay = 1;
if(frame_cat == NGHTTP2_CAT_CTRL) { if(frame_cat == NGHTTP2_CAT_CTRL) {
nghttp2_frame *frame = (nghttp2_frame*)abs_frame; nghttp2_frame *frame = (nghttp2_frame*)abs_frame;
nghttp2_stream *stream = NULL; nghttp2_stream *stream = NULL;
@ -546,6 +550,7 @@ int nghttp2_session_add_frame(nghttp2_session *session,
free(item); free(item);
return r; return r;
} }
item->inipri = item->pri;
return 0; return 0;
} }
@ -1385,6 +1390,23 @@ nghttp2_outbound_item* nghttp2_session_pop_next_ob_item
} }
} }
/*
* Adjust priority of the |item|. In order to prevent the low priority
* streams from starving, lower the priority of the |item| by
* item->pri_decay. If the resulting priority exceeds
* NGHTTP2_PRI_DEFAULT, back to the original priority.
*/
static void adjust_pri(nghttp2_outbound_item *item)
{
if(item->pri >= (int32_t)(NGHTTP2_PRI_LOWEST - (item->pri_decay - 1))) {
item->pri = item->inipri;
item->pri_decay = 1;
return;
}
item->pri += (int32_t)(item->pri_decay - 1);
item->pri_decay <<= 1;
}
/* /*
* Called after a frame is sent. * Called after a frame is sent.
* *
@ -1563,6 +1585,7 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session)
} else { } else {
nghttp2_outbound_item* next_item; nghttp2_outbound_item* next_item;
next_item = nghttp2_session_get_next_ob_item(session); next_item = nghttp2_session_get_next_ob_item(session);
adjust_pri(session->aob.item);
/* If priority of this stream is higher or equal to other stream /* If priority of this stream is higher or equal to other stream
waiting at the top of the queue, we continue to send this waiting at the top of the queue, we continue to send this
data. */ data. */

View File

@ -1869,13 +1869,13 @@ void test_nghttp2_session_reprioritize_stream(void)
nghttp2_session_reprioritize_stream(session, stream, 120); nghttp2_session_reprioritize_stream(session, stream, 120);
CU_ASSERT(session->aob.item != NULL); CU_ASSERT(session->aob.item != NULL);
CU_ASSERT(120 == session->aob.item->pri); CU_ASSERT(120 == session->aob.item->inipri);
CU_ASSERT(120 == stream->pri); CU_ASSERT(120 == stream->pri);
CU_ASSERT(5000 == nghttp2_session_get_stream(session, 1)->pri); CU_ASSERT(5000 == nghttp2_session_get_stream(session, 1)->pri);
item = nghttp2_session_get_next_ob_item(session); item = nghttp2_session_get_next_ob_item(session);
CU_ASSERT(120 == item->pri); CU_ASSERT(5000 == item->inipri);
CU_ASSERT(NGHTTP2_HEADERS == OB_CTRL_TYPE(item)); CU_ASSERT(NGHTTP2_HEADERS == OB_CTRL_TYPE(item));
CU_ASSERT(3 == OB_CTRL(item)->hd.stream_id); CU_ASSERT(1 == OB_CTRL(item)->hd.stream_id);
nghttp2_session_del(session); nghttp2_session_del(session);