Optimize dependency based priority code to Firefox style tree

While this commit optimizes dependency routine to Firefox style tree,
the other use cases (e.g., linear chain) are also improved
dramatically as well.
This commit is contained in:
Tatsuhiro Tsujikawa 2015-06-19 19:36:24 +09:00
parent 5537503172
commit 46b70c1db8
4 changed files with 552 additions and 267 deletions

View File

@ -6306,8 +6306,8 @@ int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
return rv; return rv;
} }
session_outbound_item_schedule(session, stream->item, session_outbound_item_schedule(
stream->effective_weight); session, stream->item, nghttp2_stream_compute_effective_weight(stream));
return 0; return 0;
} }

View File

@ -60,7 +60,6 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
stream->dpri = NGHTTP2_STREAM_DPRI_NO_ITEM; stream->dpri = NGHTTP2_STREAM_DPRI_NO_ITEM;
stream->num_substreams = 1; stream->num_substreams = 1;
stream->weight = weight; stream->weight = weight;
stream->effective_weight = stream->weight;
stream->sum_dep_weight = 0; stream->sum_dep_weight = 0;
stream->sum_norest_weight = 0; stream->sum_norest_weight = 0;
@ -107,9 +106,9 @@ static int stream_push_item(nghttp2_stream *stream, nghttp2_session *session) {
weight. This will delay low priority stream, which is good. weight. This will delay low priority stream, which is good.
OTOH, this may incur delay for high priority item. Will OTOH, this may incur delay for high priority item. Will
see. */ see. */
item->cycle = item->cycle = session->last_cycle +
session->last_cycle + NGHTTP2_DATA_PAYLOADLEN * NGHTTP2_MAX_WEIGHT /
NGHTTP2_DATA_PAYLOADLEN * NGHTTP2_MAX_WEIGHT / stream->effective_weight; nghttp2_stream_compute_effective_weight(stream);
rv = nghttp2_pq_push(&session->ob_da_pq, item); rv = nghttp2_pq_push(&session->ob_da_pq, item);
if (rv != 0) { if (rv != 0) {
@ -133,13 +132,6 @@ static int stream_push_item(nghttp2_stream *stream, nghttp2_session *session) {
return 0; return 0;
} }
static nghttp2_stream *stream_first_sib(nghttp2_stream *stream) {
for (; stream->sib_prev; stream = stream->sib_prev)
;
return stream;
}
static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) { static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) {
for (; stream->sib_next; stream = stream->sib_next) for (; stream->sib_next; stream = stream->sib_next)
; ;
@ -147,17 +139,12 @@ static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) {
return stream; return stream;
} }
static nghttp2_stream *stream_update_dep_length(nghttp2_stream *stream, static void stream_update_dep_length(nghttp2_stream *stream, ssize_t delta) {
ssize_t delta) {
stream->num_substreams += delta; stream->num_substreams += delta;
stream = stream_first_sib(stream);
if (stream->dep_prev) { if (stream->dep_prev) {
return stream_update_dep_length(stream->dep_prev, delta); stream_update_dep_length(stream->dep_prev, delta);
} }
return stream;
} }
int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream, int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
@ -167,47 +154,6 @@ int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
return nghttp2_max(1, weight); return nghttp2_max(1, weight);
} }
int32_t nghttp2_stream_dep_distributed_effective_weight(nghttp2_stream *stream,
int32_t weight) {
if (stream->sum_norest_weight == 0) {
return stream->effective_weight;
}
weight = stream->effective_weight * weight / stream->sum_norest_weight;
return nghttp2_max(1, weight);
}
static void stream_update_dep_set_rest(nghttp2_stream *stream);
/* Updates effective_weight of descendant streams in subtree of
|stream|. We assume that stream->effective_weight is already set
right. */
static void stream_update_dep_effective_weight(nghttp2_stream *stream) {
nghttp2_stream *si;
DEBUGF(fprintf(stderr, "stream: update_dep_effective_weight "
"stream(%p)=%d, weight=%d, sum_norest_weight=%d\n",
stream, stream->stream_id, stream->weight,
stream->sum_norest_weight));
/* stream->sum_norest_weight == 0 means there is no
NGHTTP2_STREAM_DPRI_TOP under stream */
if (stream->dpri != NGHTTP2_STREAM_DPRI_NO_ITEM ||
stream->sum_norest_weight == 0) {
return;
}
for (si = stream->dep_next; si; si = si->sib_next) {
if (si->dpri != NGHTTP2_STREAM_DPRI_REST) {
si->effective_weight =
nghttp2_stream_dep_distributed_effective_weight(stream, si->weight);
stream_update_dep_effective_weight(si);
}
}
}
static void stream_update_dep_set_rest(nghttp2_stream *stream) { static void stream_update_dep_set_rest(nghttp2_stream *stream) {
if (stream == NULL) { if (stream == NULL) {
return; return;
@ -233,27 +179,41 @@ static void stream_update_dep_set_rest(nghttp2_stream *stream) {
/* /*
* Performs dfs starting |stream|, search stream which can become * Performs dfs starting |stream|, search stream which can become
* NGHTTP2_STREAM_DPRI_TOP and set its dpri. * NGHTTP2_STREAM_DPRI_TOP and set its dpri. This function also
* updates sum_norest_weight if stream->dpri ==
* NGHTTP2_STREAM_DPRI_NO_ITEM. This function returns nonzero if
* stream's subtree contains at least one NGHTTP2_STRAEM_DPRI_TOP
* stream.
*/ */
static void stream_update_dep_set_top(nghttp2_stream *stream) { static int stream_update_dep_set_top(nghttp2_stream *stream) {
nghttp2_stream *si; nghttp2_stream *si;
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) { if (!stream) {
return; return 0;
} }
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
return 1;
}
stream->sum_norest_weight = 0;
if (stream->dpri == NGHTTP2_STREAM_DPRI_REST) { if (stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
DEBUGF( DEBUGF(
fprintf(stderr, "stream: stream=%d item is top\n", stream->stream_id)); fprintf(stderr, "stream: stream=%d item is top\n", stream->stream_id));
stream->dpri = NGHTTP2_STREAM_DPRI_TOP; stream->dpri = NGHTTP2_STREAM_DPRI_TOP;
return; return 1;
} }
for (si = stream->dep_next; si; si = si->sib_next) { for (si = stream->dep_next; si; si = si->sib_next) {
stream_update_dep_set_top(si); if (stream_update_dep_set_top(si)) {
stream->sum_norest_weight += si->weight;
}
} }
return stream->sum_norest_weight > 0;
} }
/* /*
@ -288,6 +248,10 @@ static int stream_update_dep_queue_top(nghttp2_stream *stream,
return 0; return 0;
} }
if (stream->sum_norest_weight == 0) {
return 0;
}
for (si = stream->dep_next; si; si = si->sib_next) { for (si = stream->dep_next; si; si = si->sib_next) {
rv = stream_update_dep_queue_top(si, session); rv = stream_update_dep_queue_top(si, session);
@ -300,72 +264,108 @@ static int stream_update_dep_queue_top(nghttp2_stream *stream,
} }
/* /*
* Updates stream->sum_norest_weight recursively. We have to gather * Updates stream->sum_norest_weight recursively towards root.
* effective sum of weight of descendants. If stream->dpri == * |delta| must not be 0. We have to gather effective sum of weight
* NGHTTP2_STREAM_DPRI_NO_ITEM, we have to go deeper and check that * of descendants. |delta| is added to stream->sum_norest_weight. If
* any of its descendants has dpri value of NGHTTP2_STREAM_DPRI_TOP. * stream->sum_norest_weight becomes 0, we have to update parent
* If so, we have to add weight of its direct descendants to * stream, decreasing its sum_norest_weight by stream->weight. If
* stream->sum_norest_weight. To make this work, this function * stream->sum_norest_weight becomes from 0 to positive, then we have
* returns 1 if any of its descendants has dpri value of * to update parent stream, increasing its sum_norest_weight by
* NGHTTP2_STREAM_DPRI_TOP, otherwise 0. * stream->weight. Otherwise, we stop recursive call.
*/ */
static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream) { static void stream_update_dep_sum_norest_weight(nghttp2_stream *stream,
nghttp2_stream *si; int32_t delta) {
int32_t old;
stream->sum_norest_weight = 0; if (!stream) {
return;
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
return 1;
} }
if (stream->dpri == NGHTTP2_STREAM_DPRI_REST) { assert(delta != 0);
return 0; assert(stream->sum_norest_weight + delta >= 0);
old = stream->sum_norest_weight;
stream->sum_norest_weight += delta;
if (old == 0) {
assert(delta > 0);
stream_update_dep_sum_norest_weight(stream->dep_prev, stream->weight);
return;
} }
for (si = stream->dep_next; si; si = si->sib_next) { assert(old > 0);
if (stream_update_dep_sum_norest_weight(si)) { if (stream->sum_norest_weight == 0) {
stream->sum_norest_weight += si->weight; stream_update_dep_sum_norest_weight(stream->dep_prev, -stream->weight);
}
}
/*
* Returns stream whose dpri is NGHTTP2_STREAM_DPRI_NO_ITEM along the
* path following stream->dep_prev (stream's ancestors, including
* itself). In other words, find stream which blocks the descendant
* streams. If there is no such stream, returns NULL.
*/
static nghttp2_stream *stream_get_dep_blocking(nghttp2_stream *stream) {
for (; stream; stream = stream->dep_prev) {
if (stream->dpri != NGHTTP2_STREAM_DPRI_NO_ITEM) {
return stream;
} }
} }
return NULL;
return stream->sum_norest_weight > 0;
} }
static int stream_update_dep_on_attach_item(nghttp2_stream *stream, static int stream_update_dep_on_attach_item(nghttp2_stream *stream,
nghttp2_session *session) { nghttp2_session *session) {
nghttp2_stream *root_stream; nghttp2_stream *blocking_stream;
int rv;
stream->dpri = NGHTTP2_STREAM_DPRI_REST; stream->dpri = NGHTTP2_STREAM_DPRI_REST;
stream_update_dep_set_rest(stream->dep_next); blocking_stream = stream_get_dep_blocking(stream->dep_prev);
root_stream = nghttp2_stream_get_dep_root(stream); /* If we found REST or TOP in ascendants, we don't have to update
any metadata. */
if (blocking_stream) {
return 0;
}
DEBUGF(fprintf(stderr, "root=%p, stream=%p\n", root_stream, stream)); stream->dpri = NGHTTP2_STREAM_DPRI_TOP;
if (stream->sum_norest_weight == 0) {
stream_update_dep_sum_norest_weight(stream->dep_prev, stream->weight);
} else {
stream_update_dep_set_rest(stream->dep_next);
}
stream_update_dep_set_top(root_stream); if (!stream->item->queued) {
DEBUGF(fprintf(stderr, "stream: stream=%d enqueue\n", stream->stream_id));
rv = stream_push_item(stream, session);
stream_update_dep_sum_norest_weight(root_stream); if (rv != 0) {
stream_update_dep_effective_weight(root_stream); return rv;
}
}
return stream_update_dep_queue_top(root_stream, session); return 0;
} }
static int stream_update_dep_on_detach_item(nghttp2_stream *stream, static int stream_update_dep_on_detach_item(nghttp2_stream *stream,
nghttp2_session *session) { nghttp2_session *session) {
nghttp2_stream *root_stream; if (stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
stream->dpri = NGHTTP2_STREAM_DPRI_NO_ITEM;
return 0;
}
assert(stream->dpri == NGHTTP2_STREAM_DPRI_TOP);
stream->dpri = NGHTTP2_STREAM_DPRI_NO_ITEM; stream->dpri = NGHTTP2_STREAM_DPRI_NO_ITEM;
root_stream = nghttp2_stream_get_dep_root(stream); if (stream_update_dep_set_top(stream) == 0) {
stream_update_dep_sum_norest_weight(stream->dep_prev, -stream->weight);
return 0;
}
stream_update_dep_set_top(root_stream); return stream_update_dep_queue_top(stream->dep_next, session);
stream_update_dep_sum_norest_weight(root_stream);
stream_update_dep_effective_weight(root_stream);
return stream_update_dep_queue_top(root_stream, session);
} }
int nghttp2_stream_attach_item(nghttp2_stream *stream, int nghttp2_stream_attach_item(nghttp2_stream *stream,
@ -465,22 +465,8 @@ void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream) {
} }
nghttp2_stream *nghttp2_stream_get_dep_root(nghttp2_stream *stream) { nghttp2_stream *nghttp2_stream_get_dep_root(nghttp2_stream *stream) {
for (;;) { for (; stream->dep_prev; stream = stream->dep_prev)
if (stream->sib_prev) { ;
stream = stream->sib_prev;
continue;
}
if (stream->dep_prev) {
stream = stream->dep_prev;
continue;
}
break;
}
return stream; return stream;
} }
@ -501,12 +487,25 @@ int nghttp2_stream_dep_subtree_find(nghttp2_stream *stream,
return nghttp2_stream_dep_subtree_find(stream->dep_next, target); return nghttp2_stream_dep_subtree_find(stream->dep_next, target);
} }
int32_t nghttp2_stream_compute_effective_weight(nghttp2_stream *stream) {
int32_t weight;
if (!stream->dep_prev) {
return stream->weight;
}
weight = nghttp2_stream_compute_effective_weight(stream->dep_prev) *
stream->weight / stream->dep_prev->sum_norest_weight;
return nghttp2_max(1, weight);
}
void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
nghttp2_stream *stream) { nghttp2_stream *stream) {
nghttp2_stream *si; nghttp2_stream *si;
nghttp2_stream *root_stream; nghttp2_stream *blocking_stream;
assert(stream->item == NULL); assert(stream->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM);
DEBUGF(fprintf(stderr, DEBUGF(fprintf(stderr,
"stream: dep_insert dep_stream(%p)=%d, stream(%p)=%d\n", "stream: dep_insert dep_stream(%p)=%d, stream(%p)=%d\n",
@ -515,34 +514,57 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
stream->sum_dep_weight = dep_stream->sum_dep_weight; stream->sum_dep_weight = dep_stream->sum_dep_weight;
dep_stream->sum_dep_weight = stream->weight; dep_stream->sum_dep_weight = stream->weight;
blocking_stream = stream_get_dep_blocking(dep_stream);
stream->sum_norest_weight = 0;
if (dep_stream->dep_next) { if (dep_stream->dep_next) {
assert(dep_stream->num_substreams >= 1);
/* num_substreams includes node itself */
stream->num_substreams = dep_stream->num_substreams;
for (si = dep_stream->dep_next; si; si = si->sib_next) { for (si = dep_stream->dep_next; si; si = si->sib_next) {
stream->num_substreams += si->num_substreams; si->dep_prev = stream;
if (!blocking_stream && (si->dpri == NGHTTP2_STREAM_DPRI_TOP ||
(si->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM &&
si->sum_norest_weight))) {
stream->sum_norest_weight += si->weight;
}
} }
stream->dep_next = dep_stream->dep_next; stream->dep_next = dep_stream->dep_next;
stream->dep_next->dep_prev = stream;
} }
dep_stream->dep_next = stream; dep_stream->dep_next = stream;
stream->dep_prev = dep_stream; stream->dep_prev = dep_stream;
root_stream = stream_update_dep_length(dep_stream, 1); if (stream->sum_norest_weight) {
dep_stream->sum_norest_weight = stream->weight;
}
stream_update_dep_sum_norest_weight(root_stream); stream_update_dep_length(dep_stream, 1);
stream_update_dep_effective_weight(root_stream);
++stream->roots->num_streams; ++stream->roots->num_streams;
} }
static void link_dep(nghttp2_stream *dep_stream, nghttp2_stream *stream) { static void set_dep_prev(nghttp2_stream *stream, nghttp2_stream *dep) {
dep_stream->dep_next = stream; for (; stream; stream = stream->sib_next) {
stream->dep_prev = dep_stream; stream->dep_prev = dep;
}
} }
static void link_sib(nghttp2_stream *prev_stream, nghttp2_stream *stream) { static void link_dep(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
prev_stream->sib_next = stream; dep_stream->dep_next = stream;
stream->sib_prev = prev_stream; if (stream) {
stream->dep_prev = dep_stream;
}
}
static void link_sib(nghttp2_stream *a, nghttp2_stream *b) {
a->sib_next = b;
if (b) {
b->sib_prev = a;
}
} }
static void insert_link_dep(nghttp2_stream *dep_stream, static void insert_link_dep(nghttp2_stream *dep_stream,
@ -555,8 +577,6 @@ static void insert_link_dep(nghttp2_stream *dep_stream,
link_sib(stream, sib_next); link_sib(stream, sib_next);
sib_next->dep_prev = NULL;
link_dep(dep_stream, stream); link_dep(dep_stream, stream);
} }
@ -574,10 +594,11 @@ static void unlink_sib(nghttp2_stream *stream) {
* | * |
* dep_next * dep_next
*/ */
dep_next->dep_prev = NULL;
link_sib(prev, dep_next); link_sib(prev, dep_next);
set_dep_prev(dep_next, stream->dep_prev);
if (stream->sib_next) { if (stream->sib_next) {
link_sib(stream_last_sib(dep_next), stream->sib_next); link_sib(stream_last_sib(dep_next), stream->sib_next);
} }
@ -613,9 +634,12 @@ static void unlink_dep(nghttp2_stream *stream) {
*/ */
link_dep(prev, dep_next); link_dep(prev, dep_next);
set_dep_prev(dep_next, stream->dep_prev);
if (stream->sib_next) { if (stream->sib_next) {
link_sib(stream_last_sib(dep_next), stream->sib_next); link_sib(stream_last_sib(dep_next), stream->sib_next);
} }
} else if (stream->sib_next) { } else if (stream->sib_next) {
/* /*
* prev * prev
@ -634,14 +658,12 @@ static void unlink_dep(nghttp2_stream *stream) {
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
nghttp2_stream *stream) { nghttp2_stream *stream) {
nghttp2_stream *root_stream; assert(stream->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM);
assert(stream->item == NULL);
DEBUGF(fprintf(stderr, "stream: dep_add dep_stream(%p)=%d, stream(%p)=%d\n", DEBUGF(fprintf(stderr, "stream: dep_add dep_stream(%p)=%d, stream(%p)=%d\n",
dep_stream, dep_stream->stream_id, stream, stream->stream_id)); dep_stream, dep_stream->stream_id, stream, stream->stream_id));
root_stream = stream_update_dep_length(dep_stream, 1); stream_update_dep_length(dep_stream, 1);
dep_stream->sum_dep_weight += stream->weight; dep_stream->sum_dep_weight += stream->weight;
@ -651,38 +673,50 @@ void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
insert_link_dep(dep_stream, stream); insert_link_dep(dep_stream, stream);
} }
stream_update_dep_sum_norest_weight(root_stream);
stream_update_dep_effective_weight(root_stream);
++stream->roots->num_streams; ++stream->roots->num_streams;
} }
void nghttp2_stream_dep_remove(nghttp2_stream *stream) { void nghttp2_stream_dep_remove(nghttp2_stream *stream) {
nghttp2_stream *prev, *next, *dep_prev, *si, *root_stream; nghttp2_stream *next, *dep_prev, *si, *blocking_stream;
int32_t sum_dep_weight_delta; int32_t sum_dep_weight_delta, sum_norest_weight_delta;
root_stream = NULL; assert(stream->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM);
DEBUGF(fprintf(stderr, "stream: dep_remove stream(%p)=%d\n", stream, DEBUGF(fprintf(stderr, "stream: dep_remove stream(%p)=%d\n", stream,
stream->stream_id)); stream->stream_id));
blocking_stream = stream_get_dep_blocking(stream->dep_prev);
/* Distribute weight of |stream| to direct descendants */ /* Distribute weight of |stream| to direct descendants */
sum_dep_weight_delta = -stream->weight; sum_dep_weight_delta = -stream->weight;
sum_norest_weight_delta = 0;
/* blocking_stream == NULL means that ascendants are all
NGHTTP2_STREAM_DPRI_NO_ITEM */
if (!blocking_stream && stream->sum_norest_weight) {
sum_norest_weight_delta -= stream->weight;
}
for (si = stream->dep_next; si; si = si->sib_next) { for (si = stream->dep_next; si; si = si->sib_next) {
si->weight = nghttp2_stream_dep_distributed_weight(stream, si->weight); si->weight = nghttp2_stream_dep_distributed_weight(stream, si->weight);
sum_dep_weight_delta += si->weight; sum_dep_weight_delta += si->weight;
if (!blocking_stream &&
(si->dpri == NGHTTP2_STREAM_DPRI_TOP ||
(si->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM && si->sum_norest_weight))) {
sum_norest_weight_delta += si->weight;
}
} }
prev = stream_first_sib(stream); dep_prev = stream->dep_prev;
dep_prev = prev->dep_prev;
if (dep_prev) { if (dep_prev) {
root_stream = stream_update_dep_length(dep_prev, -1); stream_update_dep_length(dep_prev, -1);
dep_prev->sum_dep_weight += sum_dep_weight_delta; dep_prev->sum_dep_weight += sum_dep_weight_delta;
dep_prev->sum_norest_weight += sum_norest_weight_delta;
} }
if (stream->sib_prev) { if (stream->sib_prev) {
@ -702,22 +736,15 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream) {
si->sib_prev = NULL; si->sib_prev = NULL;
si->sib_next = NULL; si->sib_next = NULL;
/* We already distributed weight of |stream| to this. */
si->effective_weight = si->weight;
nghttp2_stream_roots_add(si->roots, si); nghttp2_stream_roots_add(si->roots, si);
si = next; si = next;
} }
} }
if (root_stream) {
stream_update_dep_sum_norest_weight(root_stream);
stream_update_dep_effective_weight(root_stream);
}
stream->num_substreams = 1; stream->num_substreams = 1;
stream->sum_dep_weight = 0; stream->sum_dep_weight = 0;
stream->sum_norest_weight = 0;
stream->dep_prev = NULL; stream->dep_prev = NULL;
stream->dep_next = NULL; stream->dep_next = NULL;
@ -732,7 +759,8 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
nghttp2_session *session) { nghttp2_session *session) {
nghttp2_stream *last_sib; nghttp2_stream *last_sib;
nghttp2_stream *dep_next; nghttp2_stream *dep_next;
nghttp2_stream *root_stream; nghttp2_stream *blocking_stream;
nghttp2_stream *si;
size_t delta_substreams; size_t delta_substreams;
DEBUGF(fprintf(stderr, "stream: dep_insert_subtree dep_stream(%p)=%d " DEBUGF(fprintf(stderr, "stream: dep_insert_subtree dep_stream(%p)=%d "
@ -741,7 +769,7 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
delta_substreams = stream->num_substreams; delta_substreams = stream->num_substreams;
stream_update_dep_set_rest(stream); blocking_stream = stream_get_dep_blocking(dep_stream);
if (dep_stream->dep_next) { if (dep_stream->dep_next) {
/* dep_stream->num_substreams includes dep_stream itself */ /* dep_stream->num_substreams includes dep_stream itself */
@ -752,7 +780,9 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
dep_next = dep_stream->dep_next; dep_next = dep_stream->dep_next;
stream_update_dep_set_rest(dep_next); if (!blocking_stream && dep_stream->sum_norest_weight) {
stream_update_dep_set_rest(dep_next);
}
link_dep(dep_stream, stream); link_dep(dep_stream, stream);
@ -760,11 +790,13 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
last_sib = stream_last_sib(stream->dep_next); last_sib = stream_last_sib(stream->dep_next);
link_sib(last_sib, dep_next); link_sib(last_sib, dep_next);
dep_next->dep_prev = NULL;
} else { } else {
link_dep(stream, dep_next); link_dep(stream, dep_next);
} }
for (si = dep_next; si; si = si->sib_next) {
si->dep_prev = stream;
}
} else { } else {
link_dep(dep_stream, stream); link_dep(dep_stream, stream);
@ -772,27 +804,33 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
dep_stream->sum_dep_weight = stream->weight; dep_stream->sum_dep_weight = stream->weight;
} }
root_stream = stream_update_dep_length(dep_stream, delta_substreams); stream_update_dep_length(dep_stream, delta_substreams);
stream_update_dep_set_top(root_stream); if (blocking_stream) {
stream_update_dep_set_rest(stream);
stream_update_dep_sum_norest_weight(root_stream); return 0;
stream_update_dep_effective_weight(root_stream); }
return stream_update_dep_queue_top(root_stream, session); if (stream_update_dep_set_top(stream) == 0) {
return 0;
}
dep_stream->sum_norest_weight = stream->weight;
stream_update_dep_sum_norest_weight(dep_stream->dep_prev, dep_stream->weight);
return stream_update_dep_queue_top(stream, session);
} }
int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
nghttp2_stream *stream, nghttp2_stream *stream,
nghttp2_session *session) { nghttp2_session *session) {
nghttp2_stream *root_stream; nghttp2_stream *blocking_stream;
DEBUGF(fprintf(stderr, "stream: dep_add_subtree dep_stream(%p)=%d " DEBUGF(fprintf(stderr, "stream: dep_add_subtree dep_stream(%p)=%d "
"stream(%p)=%d\n", "stream(%p)=%d\n",
dep_stream, dep_stream->stream_id, stream, stream->stream_id)); dep_stream, dep_stream->stream_id, stream, stream->stream_id));
stream_update_dep_set_rest(stream);
if (dep_stream->dep_next) { if (dep_stream->dep_next) {
dep_stream->sum_dep_weight += stream->weight; dep_stream->sum_dep_weight += stream->weight;
@ -804,46 +842,52 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
dep_stream->sum_dep_weight = stream->weight; dep_stream->sum_dep_weight = stream->weight;
} }
root_stream = stream_update_dep_length(dep_stream, stream->num_substreams); stream_update_dep_length(dep_stream, stream->num_substreams);
stream_update_dep_set_top(root_stream); blocking_stream = stream_get_dep_blocking(dep_stream);
stream_update_dep_sum_norest_weight(root_stream); if (blocking_stream) {
stream_update_dep_effective_weight(root_stream); /* We cannot make any assumption for stream if its dpri is not
NGHTTP2_DPRI_TOP. Just dfs under stream here. */
stream_update_dep_set_rest(stream);
return stream_update_dep_queue_top(root_stream, session); return 0;
}
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
stream_update_dep_sum_norest_weight(dep_stream, stream->weight);
return 0;
}
if (stream_update_dep_set_top(stream) == 0) {
return 0;
}
/* Newly added subtree contributes to dep_stream's
sum_norest_weight */
stream_update_dep_sum_norest_weight(dep_stream, stream->weight);
return stream_update_dep_queue_top(stream, session);
} }
void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) { void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) {
nghttp2_stream *prev, *next, *dep_prev, *root_stream; nghttp2_stream *next, *dep_prev, *blocking_stream;
DEBUGF(fprintf(stderr, "stream: dep_remove_subtree stream(%p)=%d\n", stream, DEBUGF(fprintf(stderr, "stream: dep_remove_subtree stream(%p)=%d\n", stream,
stream->stream_id)); stream->stream_id));
if (stream->sib_prev) { if (stream->sib_prev) {
prev = stream->sib_prev; link_sib(stream->sib_prev, stream->sib_next);
dep_prev = stream->dep_prev;
prev->sib_next = stream->sib_next;
if (prev->sib_next) {
prev->sib_next->sib_prev = prev;
}
prev = stream_first_sib(prev);
dep_prev = prev->dep_prev;
} else if (stream->dep_prev) { } else if (stream->dep_prev) {
dep_prev = stream->dep_prev; dep_prev = stream->dep_prev;
next = stream->sib_next; next = stream->sib_next;
dep_prev->dep_next = next; link_dep(dep_prev, next);
if (next) { if (next) {
next->dep_prev = dep_prev;
next->sib_prev = NULL; next->sib_prev = NULL;
} }
} else { } else {
nghttp2_stream_roots_remove(stream->roots, stream); nghttp2_stream_roots_remove(stream->roots, stream);
@ -853,10 +897,15 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) {
if (dep_prev) { if (dep_prev) {
dep_prev->sum_dep_weight -= stream->weight; dep_prev->sum_dep_weight -= stream->weight;
root_stream = stream_update_dep_length(dep_prev, -stream->num_substreams); stream_update_dep_length(dep_prev, -stream->num_substreams);
stream_update_dep_sum_norest_weight(root_stream); blocking_stream = stream_get_dep_blocking(dep_prev);
stream_update_dep_effective_weight(root_stream);
if (!blocking_stream && (stream->dpri == NGHTTP2_STREAM_DPRI_TOP ||
(stream->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM &&
stream->sum_norest_weight))) {
stream_update_dep_sum_norest_weight(dep_prev, -stream->weight);
}
} }
stream->sib_prev = NULL; stream->sib_prev = NULL;
@ -871,14 +920,9 @@ int nghttp2_stream_dep_make_root(nghttp2_stream *stream,
nghttp2_stream_roots_add(stream->roots, stream); nghttp2_stream_roots_add(stream->roots, stream);
stream_update_dep_set_rest(stream); if (stream_update_dep_set_top(stream) == 0) {
return 0;
stream->effective_weight = stream->weight; }
stream_update_dep_set_top(stream);
stream_update_dep_sum_norest_weight(stream);
stream_update_dep_effective_weight(stream);
return stream_update_dep_queue_top(stream, session); return stream_update_dep_queue_top(stream, session);
} }
@ -908,6 +952,13 @@ nghttp2_stream_dep_all_your_stream_are_belong_to_us(nghttp2_stream *stream,
stream->sum_dep_weight += first->weight; stream->sum_dep_weight += first->weight;
stream->num_substreams += first->num_substreams; stream->num_substreams += first->num_substreams;
if (stream->dpri != NGHTTP2_STREAM_DPRI_NO_ITEM &&
(first->dpri == NGHTTP2_STREAM_DPRI_TOP ||
(first->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM &&
first->sum_norest_weight))) {
stream_update_dep_set_rest(first);
}
for (si = first->root_next; si; si = si->root_next) { for (si = first->root_next; si; si = si->root_next) {
assert(si != stream); assert(si != stream);
@ -918,7 +969,15 @@ nghttp2_stream_dep_all_your_stream_are_belong_to_us(nghttp2_stream *stream,
stream->sum_dep_weight += si->weight; stream->sum_dep_weight += si->weight;
stream->num_substreams += si->num_substreams; stream->num_substreams += si->num_substreams;
if (stream->dpri != NGHTTP2_STREAM_DPRI_NO_ITEM &&
(si->dpri == NGHTTP2_STREAM_DPRI_TOP ||
(si->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM &&
si->sum_norest_weight))) {
stream_update_dep_set_rest(si);
}
link_sib(prev, si); link_sib(prev, si);
si->dep_prev = stream;
prev = si; prev = si;
} }
@ -928,8 +987,7 @@ nghttp2_stream_dep_all_your_stream_are_belong_to_us(nghttp2_stream *stream,
sib_next = stream->dep_next; sib_next = stream->dep_next;
sib_next->dep_prev = NULL; first->dep_prev = stream;
link_sib(first, sib_next); link_sib(first, sib_next);
link_dep(stream, prev); link_dep(stream, prev);
} else { } else {

View File

@ -209,13 +209,14 @@ struct nghttp2_stream {
int32_t local_window_size; int32_t local_window_size;
/* weight of this stream */ /* weight of this stream */
int32_t weight; int32_t weight;
/* effective weight of this stream in belonging dependency tree */ /* sum of weight of direct descendants */
int32_t effective_weight;
/* sum of weight (not effective_weight) of direct descendants */
int32_t sum_dep_weight; int32_t sum_dep_weight;
/* sum of weight of direct descendants which have at least one /* sum of weight of direct descendants which have at least one
descendant with dpri == NGHTTP2_STREAM_DPRI_TOP. We use this descendant with dpri == NGHTTP2_STREAM_DPRI_TOP. We use this
value to calculate effective weight. */ value to calculate effective weight. This value is only
meaningful iff dpri == NGHTTP2_STREAM_DPRI_NO_ITEM and all
streams along the path to the root stream (follow dep_prev) have
NGHTTP2_STREAM_DPRI_NO_ITEM. */
int32_t sum_norest_weight; int32_t sum_norest_weight;
nghttp2_stream_state state; nghttp2_stream_state state;
/* status code from remote server */ /* status code from remote server */
@ -325,21 +326,12 @@ int nghttp2_stream_dep_subtree_find(nghttp2_stream *stream,
/* /*
* Computes distributed weight of a stream of the |weight| under the * Computes distributed weight of a stream of the |weight| under the
* |stream| if |stream| is removed from a dependency tree. The result * |stream| if |stream| is removed from a dependency tree.
* is computed using stream->weight rather than
* stream->effective_weight.
*/ */
int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream, int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
int32_t weight); int32_t weight);
/* int32_t nghttp2_stream_compute_effective_weight(nghttp2_stream *stream);
* Computes effective weight of a stream of the |weight| under the
* |stream|. The result is computed using stream->effective_weight
* rather than stream->weight. This function is used to determine
* weight in dependency tree.
*/
int32_t nghttp2_stream_dep_distributed_effective_weight(nghttp2_stream *stream,
int32_t weight);
/* /*
* Makes the |stream| depend on the |dep_stream|. This dependency is * Makes the |stream| depend on the |dep_stream|. This dependency is

View File

@ -5526,7 +5526,7 @@ void test_nghttp2_session_stream_dep_add(void) {
check_stream_dep_sib(a, NULL, b, NULL, NULL); check_stream_dep_sib(a, NULL, b, NULL, NULL);
check_stream_dep_sib(b, a, NULL, NULL, c); check_stream_dep_sib(b, a, NULL, NULL, c);
check_stream_dep_sib(c, NULL, d, b, NULL); check_stream_dep_sib(c, a, d, b, NULL);
check_stream_dep_sib(d, c, NULL, NULL, NULL); check_stream_dep_sib(d, c, NULL, NULL, NULL);
CU_ASSERT(4 == session->roots.num_streams); CU_ASSERT(4 == session->roots.num_streams);
@ -5559,7 +5559,7 @@ void test_nghttp2_session_stream_dep_add(void) {
check_stream_dep_sib(a, NULL, e, NULL, NULL); check_stream_dep_sib(a, NULL, e, NULL, NULL);
check_stream_dep_sib(e, a, b, NULL, NULL); check_stream_dep_sib(e, a, b, NULL, NULL);
check_stream_dep_sib(b, e, NULL, NULL, c); check_stream_dep_sib(b, e, NULL, NULL, c);
check_stream_dep_sib(c, NULL, d, b, NULL); check_stream_dep_sib(c, e, d, b, NULL);
check_stream_dep_sib(d, c, NULL, NULL, NULL); check_stream_dep_sib(d, c, NULL, NULL, NULL);
CU_ASSERT(5 == session->roots.num_streams); CU_ASSERT(5 == session->roots.num_streams);
@ -5621,7 +5621,7 @@ void test_nghttp2_session_stream_dep_remove(void) {
nghttp2_session_del(session); nghttp2_session_del(session);
/* Remove left most stream */ /* Remove right most stream */
nghttp2_session_server_new(&session, &callbacks, NULL); nghttp2_session_server_new(&session, &callbacks, NULL);
a = open_stream(session, 1); a = open_stream(session, 1);
@ -5667,19 +5667,20 @@ void test_nghttp2_session_stream_dep_remove(void) {
nghttp2_session_del(session); nghttp2_session_del(session);
/* Remove right most stream */ /* Remove left most stream */
nghttp2_session_server_new(&session, &callbacks, NULL); nghttp2_session_server_new(&session, &callbacks, NULL);
a = open_stream(session, 1); a = open_stream(session, 1);
b = open_stream_with_dep(session, 3, a); b = open_stream_with_dep(session, 3, a);
c = open_stream_with_dep(session, 5, a); c = open_stream_with_dep(session, 5, a);
d = open_stream_with_dep(session, 7, c); d = open_stream_with_dep(session, 7, c);
e = open_stream_with_dep(session, 9, c);
/* a /* a
* | * |
* c--b * c--b
* | * |
* d * e--d
*/ */
nghttp2_stream_dep_remove(c); nghttp2_stream_dep_remove(c);
@ -5687,23 +5688,26 @@ void test_nghttp2_session_stream_dep_remove(void) {
/* becomes: /* becomes:
* a * a
* | * |
* d--b * e--d--b
*/ */
CU_ASSERT(3 == a->num_substreams); CU_ASSERT(4 == a->num_substreams);
CU_ASSERT(1 == b->num_substreams); CU_ASSERT(1 == b->num_substreams);
CU_ASSERT(1 == c->num_substreams); CU_ASSERT(1 == c->num_substreams);
CU_ASSERT(1 == d->num_substreams); CU_ASSERT(1 == d->num_substreams);
CU_ASSERT(1 == e->num_substreams);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 == a->sum_dep_weight); CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 == a->sum_dep_weight);
CU_ASSERT(0 == b->sum_dep_weight); CU_ASSERT(0 == b->sum_dep_weight);
CU_ASSERT(0 == d->sum_dep_weight); CU_ASSERT(0 == d->sum_dep_weight);
CU_ASSERT(0 == c->sum_dep_weight); CU_ASSERT(0 == c->sum_dep_weight);
CU_ASSERT(0 == e->sum_dep_weight);
check_stream_dep_sib(a, NULL, d, NULL, NULL); check_stream_dep_sib(a, NULL, e, NULL, NULL);
check_stream_dep_sib(b, NULL, NULL, d, NULL); check_stream_dep_sib(b, a, NULL, d, NULL);
check_stream_dep_sib(c, NULL, NULL, NULL, NULL); check_stream_dep_sib(c, NULL, NULL, NULL, NULL);
check_stream_dep_sib(d, a, NULL, NULL, b); check_stream_dep_sib(d, a, NULL, e, b);
check_stream_dep_sib(e, a, NULL, NULL, d);
nghttp2_session_del(session); nghttp2_session_del(session);
@ -5763,10 +5767,10 @@ void test_nghttp2_session_stream_dep_remove(void) {
CU_ASSERT(0 == f->sum_dep_weight); CU_ASSERT(0 == f->sum_dep_weight);
check_stream_dep_sib(a, NULL, d, NULL, NULL); check_stream_dep_sib(a, NULL, d, NULL, NULL);
check_stream_dep_sib(b, NULL, NULL, e, NULL); check_stream_dep_sib(b, a, NULL, e, NULL);
check_stream_dep_sib(c, NULL, NULL, NULL, NULL); check_stream_dep_sib(c, NULL, NULL, NULL, NULL);
check_stream_dep_sib(e, NULL, NULL, f, b); check_stream_dep_sib(e, a, NULL, f, b);
check_stream_dep_sib(f, NULL, NULL, d, e); check_stream_dep_sib(f, a, NULL, d, e);
check_stream_dep_sib(d, a, NULL, NULL, f); check_stream_dep_sib(d, a, NULL, NULL, f);
nghttp2_session_del(session); nghttp2_session_del(session);
@ -5822,8 +5826,8 @@ void test_nghttp2_session_stream_dep_add_subtree(void) {
CU_ASSERT(0 == f->sum_dep_weight); CU_ASSERT(0 == f->sum_dep_weight);
check_stream_dep_sib(a, NULL, e, NULL, NULL); check_stream_dep_sib(a, NULL, e, NULL, NULL);
check_stream_dep_sib(b, NULL, NULL, c, NULL); check_stream_dep_sib(b, a, NULL, c, NULL);
check_stream_dep_sib(c, NULL, d, e, b); check_stream_dep_sib(c, a, d, e, b);
check_stream_dep_sib(d, c, NULL, NULL, NULL); check_stream_dep_sib(d, c, NULL, NULL, NULL);
check_stream_dep_sib(e, a, f, NULL, c); check_stream_dep_sib(e, a, f, NULL, c);
check_stream_dep_sib(f, e, NULL, NULL, NULL); check_stream_dep_sib(f, e, NULL, NULL, NULL);
@ -5877,8 +5881,8 @@ void test_nghttp2_session_stream_dep_add_subtree(void) {
check_stream_dep_sib(a, NULL, e, NULL, NULL); check_stream_dep_sib(a, NULL, e, NULL, NULL);
check_stream_dep_sib(e, a, f, NULL, NULL); check_stream_dep_sib(e, a, f, NULL, NULL);
check_stream_dep_sib(f, e, NULL, NULL, c); check_stream_dep_sib(f, e, NULL, NULL, c);
check_stream_dep_sib(b, NULL, NULL, c, NULL); check_stream_dep_sib(b, e, NULL, c, NULL);
check_stream_dep_sib(c, NULL, d, f, b); check_stream_dep_sib(c, e, d, f, b);
check_stream_dep_sib(d, c, NULL, NULL, NULL); check_stream_dep_sib(d, c, NULL, NULL, NULL);
nghttp2_session_del(session); nghttp2_session_del(session);
@ -6011,7 +6015,7 @@ void test_nghttp2_session_stream_dep_remove_subtree(void) {
check_stream_dep_sib(a, NULL, b, NULL, NULL); check_stream_dep_sib(a, NULL, b, NULL, NULL);
check_stream_dep_sib(b, a, NULL, NULL, e); check_stream_dep_sib(b, a, NULL, NULL, e);
check_stream_dep_sib(e, NULL, NULL, b, NULL); check_stream_dep_sib(e, a, NULL, b, NULL);
check_stream_dep_sib(c, NULL, d, NULL, NULL); check_stream_dep_sib(c, NULL, d, NULL, NULL);
check_stream_dep_sib(d, c, NULL, NULL, NULL); check_stream_dep_sib(d, c, NULL, NULL, NULL);
@ -6022,6 +6026,10 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
nghttp2_session *session; nghttp2_session *session;
nghttp2_session_callbacks callbacks; nghttp2_session_callbacks callbacks;
nghttp2_stream *a, *b, *c, *d; nghttp2_stream *a, *b, *c, *d;
nghttp2_outbound_item *db, *dc;
nghttp2_mem *mem;
mem = nghttp2_mem_default();
memset(&callbacks, 0, sizeof(callbacks)); memset(&callbacks, 0, sizeof(callbacks));
@ -6057,6 +6065,10 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight); CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight);
CU_ASSERT(0 == b->sum_dep_weight); CU_ASSERT(0 == b->sum_dep_weight);
CU_ASSERT(0 == a->sum_norest_weight);
CU_ASSERT(0 == b->sum_norest_weight);
CU_ASSERT(0 == c->sum_norest_weight);
check_stream_dep_sib(c, NULL, a, NULL, NULL); check_stream_dep_sib(c, NULL, a, NULL, NULL);
check_stream_dep_sib(a, c, b, NULL, NULL); check_stream_dep_sib(a, c, b, NULL, NULL);
check_stream_dep_sib(b, a, NULL, NULL, NULL); check_stream_dep_sib(b, a, NULL, NULL, NULL);
@ -6066,9 +6078,7 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
nghttp2_session_server_new(&session, &callbacks, NULL); nghttp2_session_server_new(&session, &callbacks, NULL);
a = open_stream(session, 1); a = open_stream(session, 1);
b = open_stream(session, 3); b = open_stream(session, 3);
c = open_stream(session, 5); c = open_stream(session, 5);
/* /*
@ -6093,9 +6103,13 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
CU_ASSERT(0 == b->sum_dep_weight); CU_ASSERT(0 == b->sum_dep_weight);
CU_ASSERT(0 == a->sum_dep_weight); CU_ASSERT(0 == a->sum_dep_weight);
CU_ASSERT(0 == a->sum_norest_weight);
CU_ASSERT(0 == b->sum_norest_weight);
CU_ASSERT(0 == c->sum_norest_weight);
check_stream_dep_sib(c, NULL, b, NULL, NULL); check_stream_dep_sib(c, NULL, b, NULL, NULL);
check_stream_dep_sib(b, c, NULL, NULL, a); check_stream_dep_sib(b, c, NULL, NULL, a);
check_stream_dep_sib(a, NULL, NULL, b, NULL); check_stream_dep_sib(a, c, NULL, b, NULL);
nghttp2_session_del(session); nghttp2_session_del(session);
@ -6134,8 +6148,100 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight); CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight);
CU_ASSERT(0 == b->sum_dep_weight); CU_ASSERT(0 == b->sum_dep_weight);
CU_ASSERT(0 == a->sum_norest_weight);
CU_ASSERT(0 == b->sum_norest_weight);
CU_ASSERT(0 == c->sum_norest_weight);
CU_ASSERT(0 == d->sum_norest_weight);
check_stream_dep_sib(c, NULL, a, NULL, NULL); check_stream_dep_sib(c, NULL, a, NULL, NULL);
check_stream_dep_sib(d, NULL, NULL, a, NULL); check_stream_dep_sib(d, c, NULL, a, NULL);
check_stream_dep_sib(a, c, b, NULL, d);
check_stream_dep_sib(b, a, NULL, NULL, NULL);
nghttp2_session_del(session);
nghttp2_session_server_new(&session, &callbacks, NULL);
a = open_stream(session, 1);
b = open_stream_with_dep(session, 3, a);
c = open_stream(session, 5);
d = open_stream_with_dep(session, 7, c);
/* a c
* | |
* b d
*/
db = create_data_ob_item(mem);
nghttp2_stream_attach_item(b, db, session);
nghttp2_stream_dep_remove_subtree(c);
CU_ASSERT(0 ==
nghttp2_stream_dep_all_your_stream_are_belong_to_us(c, session));
/*
* c
* |
* a--d
* |
* b
*/
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
CU_ASSERT(16 == a->sum_norest_weight);
CU_ASSERT(16 == c->sum_norest_weight);
CU_ASSERT(0 == d->sum_norest_weight);
check_stream_dep_sib(c, NULL, a, NULL, NULL);
check_stream_dep_sib(d, c, NULL, a, NULL);
check_stream_dep_sib(a, c, b, NULL, d);
check_stream_dep_sib(b, a, NULL, NULL, NULL);
nghttp2_session_del(session);
nghttp2_session_server_new(&session, &callbacks, NULL);
a = open_stream(session, 1);
b = open_stream_with_dep(session, 3, a);
c = open_stream(session, 5);
d = open_stream_with_dep(session, 7, c);
/* a c
* | |
* b d
*/
db = create_data_ob_item(mem);
dc = create_data_ob_item(mem);
nghttp2_stream_attach_item(b, db, session);
nghttp2_stream_attach_item(c, dc, session);
nghttp2_stream_dep_remove_subtree(c);
CU_ASSERT(0 ==
nghttp2_stream_dep_all_your_stream_are_belong_to_us(c, session));
/*
* c
* |
* a--d
* |
* b
*/
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == b->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
check_stream_dep_sib(c, NULL, a, NULL, NULL);
check_stream_dep_sib(d, c, NULL, a, NULL);
check_stream_dep_sib(a, c, b, NULL, d); check_stream_dep_sib(a, c, b, NULL, d);
check_stream_dep_sib(b, a, NULL, NULL, NULL); check_stream_dep_sib(b, a, NULL, NULL, NULL);
@ -6145,7 +6251,7 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
void test_nghttp2_session_stream_attach_item(void) { void test_nghttp2_session_stream_attach_item(void) {
nghttp2_session *session; nghttp2_session *session;
nghttp2_session_callbacks callbacks; nghttp2_session_callbacks callbacks;
nghttp2_stream *a, *b, *c, *d; nghttp2_stream *a, *b, *c, *d, *e;
nghttp2_outbound_item *da, *db, *dc, *dd; nghttp2_outbound_item *da, *db, *dc, *dd;
nghttp2_mem *mem; nghttp2_mem *mem;
@ -6176,7 +6282,7 @@ void test_nghttp2_session_stream_attach_item(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
CU_ASSERT(16 == b->effective_weight); CU_ASSERT(16 == nghttp2_stream_compute_effective_weight(b));
CU_ASSERT(16 == a->sum_norest_weight); CU_ASSERT(16 == a->sum_norest_weight);
@ -6191,8 +6297,8 @@ void test_nghttp2_session_stream_attach_item(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
CU_ASSERT(16 * 16 / 32 == b->effective_weight); CU_ASSERT(16 * 16 / 32 == nghttp2_stream_compute_effective_weight(b));
CU_ASSERT(16 * 16 / 32 == c->effective_weight); CU_ASSERT(16 * 16 / 32 == nghttp2_stream_compute_effective_weight(c));
CU_ASSERT(32 == a->sum_norest_weight); CU_ASSERT(32 == a->sum_norest_weight);
@ -6207,7 +6313,7 @@ void test_nghttp2_session_stream_attach_item(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
CU_ASSERT(16 == a->effective_weight); CU_ASSERT(16 == nghttp2_stream_compute_effective_weight(a));
CU_ASSERT(1 == da->queued); CU_ASSERT(1 == da->queued);
@ -6218,8 +6324,8 @@ void test_nghttp2_session_stream_attach_item(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
CU_ASSERT(16 * 16 / 32 == b->effective_weight); CU_ASSERT(16 * 16 / 32 == nghttp2_stream_compute_effective_weight(b));
CU_ASSERT(16 * 16 / 32 == c->effective_weight); CU_ASSERT(16 * 16 / 32 == nghttp2_stream_compute_effective_weight(c));
dd = create_data_ob_item(mem); dd = create_data_ob_item(mem);
@ -6230,8 +6336,8 @@ void test_nghttp2_session_stream_attach_item(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == d->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == d->dpri);
CU_ASSERT(16 * 16 / 32 == b->effective_weight); CU_ASSERT(16 * 16 / 32 == nghttp2_stream_compute_effective_weight(b));
CU_ASSERT(16 * 16 / 32 == c->effective_weight); CU_ASSERT(16 * 16 / 32 == nghttp2_stream_compute_effective_weight(c));
CU_ASSERT(0 == dd->queued); CU_ASSERT(0 == dd->queued);
@ -6242,8 +6348,8 @@ void test_nghttp2_session_stream_attach_item(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri);
CU_ASSERT(16 * 16 / 32 == b->effective_weight); CU_ASSERT(16 * 16 / 32 == nghttp2_stream_compute_effective_weight(b));
CU_ASSERT(16 * 16 / 32 == d->effective_weight); CU_ASSERT(16 * 16 / 32 == nghttp2_stream_compute_effective_weight(d));
CU_ASSERT(1 == dd->queued); CU_ASSERT(1 == dd->queued);
@ -6254,10 +6360,58 @@ void test_nghttp2_session_stream_attach_item(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri);
CU_ASSERT(16 * 16 / 16 == d->effective_weight); CU_ASSERT(16 * 16 / 16 == nghttp2_stream_compute_effective_weight(d));
CU_ASSERT(1 == dd->queued); CU_ASSERT(1 == dd->queued);
/* exercises insertion */
e = open_stream_with_dep_excl(session, 9, a);
/* a
* |
* e
* |
* c--b
* |
* d
*/
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == b->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri);
CU_ASSERT(16 * 16 / 16 == nghttp2_stream_compute_effective_weight(d));
CU_ASSERT(16 == a->sum_norest_weight);
CU_ASSERT(16 == e->sum_norest_weight);
CU_ASSERT(16 == c->sum_norest_weight);
CU_ASSERT(0 == b->sum_norest_weight);
/* exercises deletion */
nghttp2_stream_dep_remove(e);
/* a
* |
* c--b
* |
* d
*/
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == b->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri);
CU_ASSERT(16 * 16 / 16 == nghttp2_stream_compute_effective_weight(d));
/* e's weight 16 is distributed equally among c and b, both now have
weight 8 each. */
CU_ASSERT(8 == a->sum_norest_weight);
CU_ASSERT(16 == c->sum_norest_weight);
CU_ASSERT(0 == b->sum_norest_weight);
nghttp2_session_del(session); nghttp2_session_del(session);
} }
@ -6265,7 +6419,7 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
nghttp2_session *session; nghttp2_session *session;
nghttp2_session_callbacks callbacks; nghttp2_session_callbacks callbacks;
nghttp2_stream *a, *b, *c, *d, *e, *f; nghttp2_stream *a, *b, *c, *d, *e, *f;
nghttp2_outbound_item *db, *dd, *de; nghttp2_outbound_item *da, *db, *dd, *de;
nghttp2_mem *mem; nghttp2_mem *mem;
mem = nghttp2_mem_default(); mem = nghttp2_mem_default();
@ -6281,6 +6435,8 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
e = open_stream(session, 9); e = open_stream(session, 9);
f = open_stream_with_dep(session, 11, e); f = open_stream_with_dep(session, 11, e);
e->weight = 32;
/* /*
* a e * a e
* | | * | |
@ -6304,8 +6460,12 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(16 == b->effective_weight); CU_ASSERT(16 == nghttp2_stream_compute_effective_weight(b));
CU_ASSERT(16 == e->effective_weight); CU_ASSERT(32 == nghttp2_stream_compute_effective_weight(e));
CU_ASSERT(16 == a->sum_norest_weight);
CU_ASSERT(0 == c->sum_norest_weight);
CU_ASSERT(0 == d->sum_norest_weight);
/* Insert subtree e under a */ /* Insert subtree e under a */
@ -6329,7 +6489,9 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(16 == e->effective_weight); CU_ASSERT(16 == nghttp2_stream_compute_effective_weight(e));
CU_ASSERT(32 == a->sum_norest_weight);
/* Remove subtree b */ /* Remove subtree b */
@ -6354,8 +6516,8 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(16 == b->effective_weight); CU_ASSERT(16 == nghttp2_stream_compute_effective_weight(b));
CU_ASSERT(16 == e->effective_weight); CU_ASSERT(16 == nghttp2_stream_compute_effective_weight(e));
/* Remove subtree a */ /* Remove subtree a */
@ -6391,10 +6553,15 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(32 == a->sum_norest_weight);
CU_ASSERT(0 == c->sum_norest_weight);
dd = create_data_ob_item(mem); dd = create_data_ob_item(mem);
nghttp2_stream_attach_item(d, dd, session); nghttp2_stream_attach_item(d, dd, session);
CU_ASSERT(16 == c->sum_norest_weight);
/* Add subtree c to a */ /* Add subtree c to a */
nghttp2_stream_dep_remove_subtree(c); nghttp2_stream_dep_remove_subtree(c);
@ -6415,11 +6582,11 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(16 == b->effective_weight); CU_ASSERT(16 == nghttp2_stream_compute_effective_weight(b));
CU_ASSERT(16 * 16 / 32 == e->effective_weight); CU_ASSERT(16 * 16 / 48 == nghttp2_stream_compute_effective_weight(d));
CU_ASSERT(16 * 16 / 32 == e->effective_weight); CU_ASSERT(16 * 32 / 48 == nghttp2_stream_compute_effective_weight(e));
CU_ASSERT(32 == a->sum_norest_weight); CU_ASSERT(48 == a->sum_norest_weight);
CU_ASSERT(16 == c->sum_norest_weight); CU_ASSERT(16 == c->sum_norest_weight);
/* Insert b under a */ /* Insert b under a */
@ -6444,10 +6611,9 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(16 == b->effective_weight); CU_ASSERT(16 == nghttp2_stream_compute_effective_weight(b));
CU_ASSERT(16 == a->sum_norest_weight); CU_ASSERT(16 == a->sum_norest_weight);
CU_ASSERT(0 == b->sum_norest_weight);
/* Remove subtree b */ /* Remove subtree b */
@ -6470,7 +6636,76 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(0 == a->sum_norest_weight); CU_ASSERT(0 == a->sum_norest_weight);
CU_ASSERT(0 == b->sum_norest_weight);
/* Remove subtree c, and detach item from b, and then re-add
subtree c under b */
nghttp2_stream_dep_remove_subtree(c);
nghttp2_stream_detach_item(b, session);
nghttp2_stream_dep_add_subtree(b, c, session);
/*
* b a
* |
* e--c
* | |
* f d
*/
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == b->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(48 == b->sum_norest_weight);
/* Attach data to a, and add subtree a under b */
da = create_data_ob_item(mem);
nghttp2_stream_attach_item(a, da, session);
nghttp2_stream_dep_add_subtree(b, a, session);
/*
* b
* |
* a--e--c
* | |
* f d
*/
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == b->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(64 == b->sum_norest_weight);
/* Remove subtree c, and add under f */
nghttp2_stream_dep_remove_subtree(c);
nghttp2_stream_dep_insert_subtree(f, c, session);
/*
* b
* |
* a--e
* |
* f
* |
* c
* |
* d
*/
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == b->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == d->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(48 == b->sum_norest_weight);
nghttp2_session_del(session); nghttp2_session_del(session);
} }