Remove restriction in regard to number of stream in dependency tree

Previously, the number of stream in one dependency tree (not including
root) is limited to 120.  This is due to the fact that we use
recursive calls to traverse trees.  Now we replaced recursive calls
with loop, we can remove this limitation.  Also now all streams are
descendant of root stream, rather than linked list of individual
subtree root.
This commit is contained in:
Tatsuhiro Tsujikawa 2015-08-13 23:32:13 +09:00
parent 8c8d1f6e14
commit d1e49a196d
5 changed files with 342 additions and 662 deletions

View File

@ -350,7 +350,9 @@ static int session_new(nghttp2_session **session_ptr,
goto fail_map;
}
nghttp2_stream_roots_init(&(*session_ptr)->roots);
nghttp2_stream_init(&(*session_ptr)->root, 0, NGHTTP2_STREAM_FLAG_NONE,
NGHTTP2_STREAM_INITIAL, NGHTTP2_DEFAULT_WEIGHT, 0, 0,
NULL);
(*session_ptr)->remote_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE;
(*session_ptr)->recv_window_size = 0;
@ -608,7 +610,7 @@ void nghttp2_session_del(nghttp2_session *session) {
settings = next;
}
nghttp2_stream_roots_free(&session->roots);
nghttp2_stream_free(&session->root);
/* Have to free streams first, so that we can check
stream->item->queued */
@ -633,7 +635,6 @@ nghttp2_session_reprioritize_stream(nghttp2_session *session,
const nghttp2_priority_spec *pri_spec_in) {
int rv;
nghttp2_stream *dep_stream = NULL;
nghttp2_stream *root_stream;
nghttp2_priority_spec pri_spec_default;
const nghttp2_priority_spec *pri_spec = pri_spec_in;
@ -665,32 +666,18 @@ nghttp2_session_reprioritize_stream(nghttp2_session *session,
}
if (pri_spec->stream_id == 0) {
nghttp2_stream_dep_remove_subtree(stream);
/* We have to update weight after removing stream from tree */
stream->weight = pri_spec->weight;
if (pri_spec->exclusive &&
session->roots.num_streams <= NGHTTP2_MAX_DEP_TREE_LENGTH) {
rv = nghttp2_stream_dep_all_your_stream_are_belong_to_us(stream, session);
} else {
rv = nghttp2_stream_dep_make_root(stream, session);
}
return rv;
}
assert(dep_stream);
if (nghttp2_stream_dep_subtree_find(stream, dep_stream)) {
dep_stream = &session->root;
} else if (nghttp2_stream_dep_subtree_find(stream, dep_stream)) {
DEBUGF(fprintf(stderr, "stream: cycle detected, dep_stream(%p)=%d "
"stream(%p)=%d\n",
dep_stream, dep_stream->stream_id, stream,
stream->stream_id));
nghttp2_stream_dep_remove_subtree(dep_stream);
nghttp2_stream_dep_make_root(dep_stream, session);
rv = nghttp2_stream_dep_add_subtree(&session->root, dep_stream, session);
if (rv != 0) {
return rv;
}
}
nghttp2_stream_dep_remove_subtree(stream);
@ -698,19 +685,10 @@ nghttp2_session_reprioritize_stream(nghttp2_session *session,
/* We have to update weight after removing stream from tree */
stream->weight = pri_spec->weight;
root_stream = nghttp2_stream_get_dep_root(dep_stream);
if (root_stream->num_substreams + stream->num_substreams >
NGHTTP2_MAX_DEP_TREE_LENGTH) {
stream->weight = NGHTTP2_DEFAULT_WEIGHT;
rv = nghttp2_stream_dep_make_root(stream, session);
if (pri_spec->exclusive) {
rv = nghttp2_stream_dep_insert_subtree(dep_stream, stream, session);
} else {
if (pri_spec->exclusive) {
rv = nghttp2_stream_dep_insert_subtree(dep_stream, stream, session);
} else {
rv = nghttp2_stream_dep_add_subtree(dep_stream, stream, session);
}
rv = nghttp2_stream_dep_add_subtree(dep_stream, stream, session);
}
if (rv != 0) {
@ -875,7 +853,6 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
int rv;
nghttp2_stream *stream;
nghttp2_stream *dep_stream = NULL;
nghttp2_stream *root_stream;
int stream_alloc = 0;
nghttp2_priority_spec pri_spec_default;
nghttp2_priority_spec *pri_spec = pri_spec_in;
@ -936,10 +913,10 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
flags |= NGHTTP2_STREAM_FLAG_PUSH;
}
nghttp2_stream_init(
stream, stream_id, flags, initial_state, pri_spec->weight,
&session->roots, session->remote_settings.initial_window_size,
session->local_settings.initial_window_size, stream_user_data);
nghttp2_stream_init(stream, stream_id, flags, initial_state, pri_spec->weight,
session->remote_settings.initial_window_size,
session->local_settings.initial_window_size,
stream_user_data);
if (stream_alloc) {
rv = nghttp2_map_insert(&session->streams, &stream->map_entry);
@ -980,42 +957,20 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
return stream;
}
if (pri_spec->stream_id == 0) {
++session->roots.num_streams;
if (pri_spec->exclusive &&
session->roots.num_streams <= NGHTTP2_MAX_DEP_TREE_LENGTH) {
rv = nghttp2_stream_dep_all_your_stream_are_belong_to_us(stream, session);
/* Since no dpri is changed in dependency tree, the above
function call never fail. */
assert(rv == 0);
} else {
nghttp2_stream_roots_add(&session->roots, stream);
}
return stream;
}
/* TODO Client does not have to track dependencies of streams except
for those which have upload data. Currently, we just track
everything. */
if (pri_spec->stream_id == 0) {
dep_stream = &session->root;
}
assert(dep_stream);
root_stream = nghttp2_stream_get_dep_root(dep_stream);
if (root_stream->num_substreams < NGHTTP2_MAX_DEP_TREE_LENGTH) {
if (pri_spec->exclusive) {
nghttp2_stream_dep_insert(dep_stream, stream);
} else {
nghttp2_stream_dep_add(dep_stream, stream);
}
if (pri_spec->exclusive) {
nghttp2_stream_dep_insert(dep_stream, stream);
} else {
stream->weight = NGHTTP2_DEFAULT_WEIGHT;
nghttp2_stream_roots_add(&session->roots, stream);
nghttp2_stream_dep_add(dep_stream, stream);
}
return stream;
@ -1107,7 +1062,9 @@ void nghttp2_session_destroy_stream(nghttp2_session *session,
mem = &session->mem;
nghttp2_stream_dep_remove(stream);
if (nghttp2_stream_in_dep_tree(stream)) {
nghttp2_stream_dep_remove(stream);
}
nghttp2_map_remove(&session->streams, stream->stream_id);
nghttp2_stream_free(stream);

View File

@ -153,7 +153,8 @@ typedef struct nghttp2_inflight_settings nghttp2_inflight_settings;
struct nghttp2_session {
nghttp2_map /* <nghttp2_stream*> */ streams;
nghttp2_stream_roots roots;
/* root of dependency tree*/
nghttp2_stream root;
/* Queue for outbound urgent frames (PING and SETTINGS) */
nghttp2_outbound_queue ob_urgent;
/* Queue for non-DATA frames */

View File

@ -32,8 +32,7 @@
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
uint8_t flags, nghttp2_stream_state initial_state,
int32_t weight, nghttp2_stream_roots *roots,
int32_t remote_initial_window_size,
int32_t weight, int32_t remote_initial_window_size,
int32_t local_initial_window_size,
void *stream_user_data) {
nghttp2_map_entry_init(&stream->map_entry, stream_id);
@ -58,15 +57,10 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
stream->closed_next = NULL;
stream->dpri = NGHTTP2_STREAM_DPRI_NO_ITEM;
stream->num_substreams = 1;
stream->weight = weight;
stream->sum_dep_weight = 0;
stream->sum_norest_weight = 0;
stream->roots = roots;
stream->root_prev = NULL;
stream->root_next = NULL;
stream->http_flags = NGHTTP2_HTTP_FLAG_NONE;
stream->content_length = -1;
stream->recv_content_length = 0;
@ -132,6 +126,72 @@ static int stream_push_item(nghttp2_stream *stream, nghttp2_session *session) {
return 0;
}
typedef enum {
DFS_NOERROR,
/* Don't traverse descendants */
DFS_SKIP_DESCENDANT,
/* Stop traversal, and return immediately */
DFS_ABORT
} dfs_error_code;
/* depth first traversal, starting at |stream|. |precb| is, if non
* NULL, called against stream before traversing its descendants.
* |postcb| is, if non NULL, called against stream just after
* traversing its all descendants. |data| is arbitrary pointer, which
* gets passed to |precb| and |postcb|.
*
* The application can change dfs behaviour by adjusting return value
* from |precb|. Returning DFS_NOERROR will resume traversal.
* Returning DFS_SKIP_DESCENDANT will skip all traversal for the
* descendant streams. Returning DFS_ABORT will immediately return
* from this function, and dfs returns DFS_ABORT. Returning any other
* values will also make this function return immediately, and dfs
* returns the value |precb| returned.
*/
static int dfs(nghttp2_stream *stream,
int (*precb)(nghttp2_stream *stream, void *data),
void (*postcb)(nghttp2_stream *stream, void *data), void *data) {
int rv;
nghttp2_stream *start;
start = stream;
for (;;) {
if (precb) {
rv = precb(stream, data);
switch (rv) {
case DFS_NOERROR:
break;
case DFS_SKIP_DESCENDANT:
goto back;
case DFS_ABORT:
default:
return rv;
}
}
if (!stream->dep_next) {
goto back;
}
stream = stream->dep_next;
continue;
back:
for (;;) {
if (postcb) {
postcb(stream, data);
}
if (stream == start) {
return 0;
}
if (stream->sib_next) {
stream = stream->sib_next;
break;
}
stream = stream->dep_prev;
}
}
}
static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) {
for (; stream->sib_next; stream = stream->sib_next)
;
@ -139,14 +199,6 @@ static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) {
return stream;
}
static void stream_update_dep_length(nghttp2_stream *stream, ssize_t delta) {
stream->num_substreams += delta;
if (stream->dep_prev) {
stream_update_dep_length(stream->dep_prev, delta);
}
}
int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
int32_t weight) {
weight = stream->weight * weight / stream->sum_dep_weight;
@ -154,26 +206,60 @@ int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
return nghttp2_max(1, weight);
}
static void stream_update_dep_set_rest(nghttp2_stream *stream) {
nghttp2_stream *si;
if (stream == NULL) {
return;
}
static int stream_update_dep_set_rest_precb(nghttp2_stream *stream,
void *data _U_) {
DEBUGF(fprintf(stderr, "stream: stream=%d is rest\n", stream->stream_id));
if (stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
return;
return DFS_SKIP_DESCENDANT;
}
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
stream->dpri = NGHTTP2_STREAM_DPRI_REST;
return DFS_SKIP_DESCENDANT;
}
return DFS_NOERROR;
}
static void stream_update_dep_set_rest(nghttp2_stream *stream) {
dfs(stream, stream_update_dep_set_rest_precb, NULL, NULL);
}
static int stream_update_dep_set_top_precb(nghttp2_stream *stream,
void *data _U_) {
stream->sum_norest_weight = 0;
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
return DFS_SKIP_DESCENDANT;
}
if (stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
DEBUGF(
fprintf(stderr, "stream: stream=%d item is top\n", stream->stream_id));
stream->dpri = NGHTTP2_STREAM_DPRI_TOP;
return DFS_SKIP_DESCENDANT;
}
return DFS_NOERROR;
}
static void stream_update_dep_set_top_postcb(nghttp2_stream *stream,
void *data) {
nghttp2_stream *start;
start = data;
if (start == stream) {
return;
}
for (si = stream->dep_next; si; si = si->sib_next) {
stream_update_dep_set_rest(si);
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP ||
(stream->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM &&
stream->sum_norest_weight > 0)) {
stream->dep_prev->sum_norest_weight += stream->weight;
}
}
@ -186,34 +272,42 @@ static void stream_update_dep_set_rest(nghttp2_stream *stream) {
* stream.
*/
static int stream_update_dep_set_top(nghttp2_stream *stream) {
nghttp2_stream *si;
dfs(stream, stream_update_dep_set_top_precb, stream_update_dep_set_top_postcb,
stream);
return stream->dpri == NGHTTP2_STREAM_DPRI_TOP ||
(stream->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM &&
stream->sum_norest_weight > 0);
}
if (!stream) {
return 0;
static int stream_update_dep_queue_top_precb(nghttp2_stream *stream,
void *data) {
int rv;
nghttp2_session *session;
session = data;
if (stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
return DFS_SKIP_DESCENDANT;
}
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
return 1;
}
if (!stream->item->queued) {
DEBUGF(fprintf(stderr, "stream: stream=%d enqueue\n", stream->stream_id));
rv = stream_push_item(stream, session);
stream->sum_norest_weight = 0;
if (stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
DEBUGF(
fprintf(stderr, "stream: stream=%d item is top\n", stream->stream_id));
stream->dpri = NGHTTP2_STREAM_DPRI_TOP;
return 1;
}
for (si = stream->dep_next; si; si = si->sib_next) {
if (stream_update_dep_set_top(si)) {
stream->sum_norest_weight += si->weight;
if (rv != 0) {
return rv;
}
}
return DFS_SKIP_DESCENDANT;
}
return stream->sum_norest_weight > 0;
if (stream->sum_norest_weight == 0) {
return DFS_SKIP_DESCENDANT;
}
return DFS_NOERROR;
}
/*
@ -228,39 +322,7 @@ static int stream_update_dep_set_top(nghttp2_stream *stream) {
*/
static int stream_update_dep_queue_top(nghttp2_stream *stream,
nghttp2_session *session) {
int rv;
nghttp2_stream *si;
if (stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
return 0;
}
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
if (!stream->item->queued) {
DEBUGF(fprintf(stderr, "stream: stream=%d enqueue\n", stream->stream_id));
rv = stream_push_item(stream, session);
if (rv != 0) {
return rv;
}
}
return 0;
}
if (stream->sum_norest_weight == 0) {
return 0;
}
for (si = stream->dep_next; si; si = si->sib_next) {
rv = stream_update_dep_queue_top(si, session);
if (rv != 0) {
return rv;
}
}
return 0;
return dfs(stream, stream_update_dep_queue_top_precb, NULL, session);
}
/*
@ -277,26 +339,33 @@ static void stream_update_dep_sum_norest_weight(nghttp2_stream *stream,
int32_t delta) {
int32_t old;
if (!stream) {
return;
}
for (;;) {
if (!stream) {
return;
}
assert(delta != 0);
assert(stream->sum_norest_weight + delta >= 0);
assert(delta != 0);
assert(stream->sum_norest_weight + delta >= 0);
old = stream->sum_norest_weight;
stream->sum_norest_weight += delta;
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;
}
if (old == 0) {
assert(delta > 0);
delta = stream->weight;
stream = stream->dep_prev;
continue;
}
assert(old > 0);
assert(old > 0);
if (stream->sum_norest_weight == 0) {
stream_update_dep_sum_norest_weight(stream->dep_prev, -stream->weight);
if (stream->sum_norest_weight == 0) {
delta = -stream->weight;
stream = stream->dep_prev;
continue;
}
break;
}
}
@ -317,21 +386,6 @@ static nghttp2_stream *stream_get_dep_blocking(nghttp2_stream *stream) {
#ifdef STREAM_DEP_DEBUG
static size_t check_stream_num(nghttp2_stream *stream) {
size_t n = 1;
nghttp2_stream *si;
for (si = stream->dep_next; si; si = si->sib_next) {
n += check_stream_num(si);
}
if (n != stream->num_substreams) {
fprintf(stderr, "num_substreams = %zu; want %zu\n", n,
stream->num_substreams);
assert(0);
}
return n;
}
static void ensure_rest_or_no_item(nghttp2_stream *stream) {
nghttp2_stream *si;
switch (stream->dpri) {
@ -384,8 +438,8 @@ static void check_sum_dep(nghttp2_stream *stream) {
n += si->weight;
}
if (n != stream->sum_dep_weight) {
fprintf(stderr, "sum_dep_weight = %d; want %d\n", n,
stream->sum_dep_weight);
fprintf(stderr, "stream(%p)=%d, sum_dep_weight = %d; want %d\n", stream,
stream->stream_id, n, stream->sum_dep_weight);
assert(0);
}
for (si = stream->dep_next; si; si = si->sib_next) {
@ -413,8 +467,8 @@ static int check_sum_norest(nghttp2_stream *stream) {
assert(0);
}
if (n != stream->sum_norest_weight) {
fprintf(stderr, "sum_norest_weight = %d; want %d\n", n,
stream->sum_norest_weight);
fprintf(stderr, "stream(%p)=%d, sum_norest_weight = %d; want %d\n", stream,
stream->stream_id, n, stream->sum_norest_weight);
assert(0);
}
return n > 0;
@ -442,7 +496,6 @@ static void validate_tree(nghttp2_stream *stream) {
for (; stream->dep_prev; stream = stream->dep_prev)
;
check_stream_num(stream);
check_dpri(stream);
check_sum_dep(stream);
check_sum_norest(stream);
@ -628,34 +681,40 @@ nghttp2_stream *nghttp2_stream_get_dep_root(nghttp2_stream *stream) {
return stream;
}
static int stream_dep_subtree_find_precb(nghttp2_stream *stream, void *data) {
nghttp2_stream *target;
target = data;
if (target == stream) {
return DFS_ABORT;
}
return DFS_NOERROR;
}
int nghttp2_stream_dep_subtree_find(nghttp2_stream *stream,
nghttp2_stream *target) {
if (stream == NULL) {
return 0;
}
if (stream == target) {
return 1;
}
if (nghttp2_stream_dep_subtree_find(stream->sib_next, target)) {
return 1;
}
return nghttp2_stream_dep_subtree_find(stream->dep_next, target);
return dfs(stream, stream_dep_subtree_find_precb, NULL, target) == DFS_ABORT;
}
int32_t nghttp2_stream_compute_effective_weight(nghttp2_stream *stream) {
int32_t weight;
if (!stream->dep_prev) {
return stream->weight;
assert(stream->dep_prev);
weight = stream->weight * 100;
for (;;) {
stream = stream->dep_prev;
/* Not consider weight of root; it could make weight too small */
if (!stream || !stream->dep_prev) {
break;
}
weight = stream->weight * weight / stream->sum_norest_weight;
}
weight = nghttp2_stream_compute_effective_weight(stream->dep_prev) *
stream->weight / stream->dep_prev->sum_norest_weight;
return nghttp2_max(1, weight);
return nghttp2_max(1, weight / 100);
}
void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
@ -677,10 +736,6 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
stream->sum_norest_weight = 0;
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) {
si->dep_prev = stream;
if (!blocking_stream && (si->dpri == NGHTTP2_STREAM_DPRI_TOP ||
@ -700,10 +755,6 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
dep_stream->sum_norest_weight = stream->weight;
}
stream_update_dep_length(dep_stream, 1);
++stream->roots->num_streams;
validate_tree(stream);
}
@ -823,8 +874,6 @@ void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
DEBUGF(fprintf(stderr, "stream: dep_add dep_stream(%p)=%d, stream(%p)=%d\n",
dep_stream, dep_stream->stream_id, stream, stream->stream_id));
stream_update_dep_length(dep_stream, 1);
dep_stream->sum_dep_weight += stream->weight;
if (dep_stream->dep_next == NULL) {
@ -833,13 +882,11 @@ void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
insert_link_dep(dep_stream, stream);
}
++stream->roots->num_streams;
validate_tree(stream);
}
void nghttp2_stream_dep_remove(nghttp2_stream *stream) {
nghttp2_stream *next, *dep_prev, *si, *blocking_stream;
nghttp2_stream *dep_prev, *si, *blocking_stream;
int32_t sum_dep_weight_delta, sum_norest_weight_delta;
assert(stream->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM);
@ -872,43 +919,19 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream) {
}
}
assert(stream->dep_prev);
dep_prev = stream->dep_prev;
if (dep_prev) {
stream_update_dep_length(dep_prev, -1);
dep_prev->sum_dep_weight += sum_dep_weight_delta;
dep_prev->sum_norest_weight += sum_norest_weight_delta;
}
dep_prev->sum_dep_weight += sum_dep_weight_delta;
dep_prev->sum_norest_weight += sum_norest_weight_delta;
if (stream->sib_prev) {
unlink_sib(stream);
validate_tree(stream->sib_prev->dep_prev);
} else if (stream->dep_prev) {
unlink_dep(stream);
validate_tree(stream->dep_prev);
} else {
nghttp2_stream_roots_remove(stream->roots, stream);
/* stream is a root of tree. Removing stream makes its
descendants a root of its own subtree. */
for (si = stream->dep_next; si;) {
next = si->sib_next;
si->dep_prev = NULL;
si->sib_prev = NULL;
si->sib_next = NULL;
nghttp2_stream_roots_add(si->roots, si);
validate_tree(si);
si = next;
}
unlink_dep(stream);
}
stream->num_substreams = 1;
stream->sum_dep_weight = 0;
stream->sum_norest_weight = 0;
@ -917,7 +940,7 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream) {
stream->sib_prev = NULL;
stream->sib_next = NULL;
--stream->roots->num_streams;
validate_tree(dep_prev);
}
int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
@ -927,15 +950,12 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
nghttp2_stream *dep_next;
nghttp2_stream *blocking_stream;
nghttp2_stream *si;
size_t delta_substreams;
int rv;
DEBUGF(fprintf(stderr, "stream: dep_insert_subtree dep_stream(%p)=%d "
"stream(%p)=%d\n",
dep_stream, dep_stream->stream_id, stream, stream->stream_id));
delta_substreams = stream->num_substreams;
blocking_stream = stream_get_dep_blocking(dep_stream);
if (blocking_stream) {
@ -943,9 +963,6 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
}
if (dep_stream->dep_next) {
/* dep_stream->num_substreams includes dep_stream itself */
stream->num_substreams += dep_stream->num_substreams - 1;
stream->sum_dep_weight += dep_stream->sum_dep_weight;
dep_stream->sum_dep_weight = stream->weight;
@ -977,8 +994,6 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
dep_stream->sum_dep_weight = stream->weight;
}
stream_update_dep_length(dep_stream, delta_substreams);
if (blocking_stream) {
validate_tree(dep_stream);
return 0;
@ -1029,8 +1044,6 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
dep_stream->sum_dep_weight = stream->weight;
}
stream_update_dep_length(dep_stream, stream->num_substreams);
blocking_stream = stream_get_dep_blocking(dep_stream);
if (blocking_stream) {
@ -1073,11 +1086,13 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) {
DEBUGF(fprintf(stderr, "stream: dep_remove_subtree stream(%p)=%d\n", stream,
stream->stream_id));
assert(stream->dep_prev);
dep_prev = stream->dep_prev;
if (stream->sib_prev) {
link_sib(stream->sib_prev, stream->sib_next);
dep_prev = stream->dep_prev;
} else if (stream->dep_prev) {
dep_prev = stream->dep_prev;
} else {
next = stream->sib_next;
link_dep(dep_prev, next);
@ -1085,189 +1100,26 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) {
if (next) {
next->sib_prev = NULL;
}
} else {
nghttp2_stream_roots_remove(stream->roots, stream);
dep_prev = NULL;
}
if (dep_prev) {
dep_prev->sum_dep_weight -= stream->weight;
dep_prev->sum_dep_weight -= stream->weight;
stream_update_dep_length(dep_prev, -stream->num_substreams);
blocking_stream = stream_get_dep_blocking(dep_prev);
blocking_stream = stream_get_dep_blocking(dep_prev);
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);
}
validate_tree(dep_prev);
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);
}
validate_tree(dep_prev);
stream->sib_prev = NULL;
stream->sib_next = NULL;
stream->dep_prev = NULL;
}
int nghttp2_stream_dep_make_root(nghttp2_stream *stream,
nghttp2_session *session) {
int rv;
DEBUGF(fprintf(stderr, "stream: dep_make_root stream(%p)=%d\n", stream,
stream->stream_id));
nghttp2_stream_roots_add(stream->roots, stream);
if (stream_update_dep_set_top(stream) == 0) {
validate_tree(stream);
return 0;
}
rv = stream_update_dep_queue_top(stream, session);
if (rv != 0) {
return rv;
}
validate_tree(stream);
return 0;
}
int
nghttp2_stream_dep_all_your_stream_are_belong_to_us(nghttp2_stream *stream,
nghttp2_session *session) {
nghttp2_stream *first, *si;
DEBUGF(fprintf(stderr, "stream: ALL YOUR STREAM ARE BELONG TO US "
"stream(%p)=%d\n",
stream, stream->stream_id));
first = stream->roots->head;
/* stream must not be include in stream->roots->head list */
assert(first != stream);
if (first) {
nghttp2_stream *prev;
prev = first;
DEBUGF(fprintf(stderr, "stream: root stream(%p)=%d\n", first,
first->stream_id));
stream->sum_dep_weight += first->weight;
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) {
assert(si != stream);
DEBUGF(
fprintf(stderr, "stream: root stream(%p)=%d\n", si, si->stream_id));
stream->sum_dep_weight += si->weight;
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);
si->dep_prev = stream;
prev = si;
}
if (stream->dep_next) {
nghttp2_stream *sib_next;
sib_next = stream->dep_next;
first->dep_prev = stream;
link_sib(first, sib_next);
link_dep(stream, prev);
} else {
link_dep(stream, first);
}
}
nghttp2_stream_roots_remove_all(stream->roots);
return nghttp2_stream_dep_make_root(stream, session);
}
int nghttp2_stream_in_dep_tree(nghttp2_stream *stream) {
return stream->dep_prev || stream->dep_next || stream->sib_prev ||
stream->sib_next || stream->root_next || stream->root_prev ||
stream->roots->head == stream;
}
void nghttp2_stream_roots_init(nghttp2_stream_roots *roots) {
roots->head = NULL;
roots->num_streams = 0;
}
void nghttp2_stream_roots_free(nghttp2_stream_roots *roots _U_) {}
void nghttp2_stream_roots_add(nghttp2_stream_roots *roots,
nghttp2_stream *stream) {
if (roots->head) {
stream->root_next = roots->head;
roots->head->root_prev = stream;
}
roots->head = stream;
}
void nghttp2_stream_roots_remove(nghttp2_stream_roots *roots,
nghttp2_stream *stream) {
nghttp2_stream *root_prev, *root_next;
root_prev = stream->root_prev;
root_next = stream->root_next;
if (root_prev) {
root_prev->root_next = root_next;
if (root_next) {
root_next->root_prev = root_prev;
}
} else {
if (root_next) {
root_next->root_prev = NULL;
}
roots->head = root_next;
}
stream->root_prev = NULL;
stream->root_next = NULL;
}
void nghttp2_stream_roots_remove_all(nghttp2_stream_roots *roots) {
nghttp2_stream *si, *next;
for (si = roots->head; si;) {
next = si->root_next;
si->root_prev = NULL;
si->root_next = NULL;
si = next;
}
roots->head = NULL;
stream->sib_next;
}

View File

@ -35,11 +35,6 @@
#include "nghttp2_pq.h"
#include "nghttp2_int.h"
/*
* Maximum number of streams in one dependency tree.
*/
#define NGHTTP2_MAX_DEP_TREE_LENGTH 120
/*
* If local peer is stream initiator:
* NGHTTP2_STREAM_OPENING : upon sending request HEADERS
@ -167,17 +162,11 @@ struct nghttp2_stream {
dep_prev and sib_prev are NULL. */
nghttp2_stream *dep_prev, *dep_next;
nghttp2_stream *sib_prev, *sib_next;
/* pointers to track dependency tree root streams. This is
doubly-linked list and first element is pointed by
roots->head. */
nghttp2_stream *root_prev, *root_next;
/* When stream is kept after closure, it may be kept in doubly
linked list pointed by nghttp2_session closed_stream_head.
closed_next points to the next stream object if it is the element
of the list. */
nghttp2_stream *closed_prev, *closed_next;
/* pointer to roots, which tracks dependency tree roots */
nghttp2_stream_roots *roots;
/* The arbitrary data provided by user for this stream. */
void *stream_user_data;
/* Item to send */
@ -187,8 +176,6 @@ struct nghttp2_stream {
/* categorized priority of this stream. Only stream bearing
NGHTTP2_STREAM_DPRI_TOP can send item. */
nghttp2_stream_dpri dpri;
/* the number of streams in subtree */
size_t num_substreams;
/* Current remote window size. This value is computed against the
current initial window size of remote endpoint. */
int32_t remote_window_size;
@ -231,8 +218,7 @@ struct nghttp2_stream {
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
uint8_t flags, nghttp2_stream_state initial_state,
int32_t weight, nghttp2_stream_roots *roots,
int32_t remote_initial_window_size,
int32_t weight, int32_t remote_initial_window_size,
int32_t local_initial_window_size,
void *stream_user_data);
@ -425,54 +411,9 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
*/
void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream);
/*
* Makes the |stream| as root. Updates dpri members in this
* dependency tree.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int nghttp2_stream_dep_make_root(nghttp2_stream *stream,
nghttp2_session *session);
/*
* Makes the |stream| as root and all existing root streams become
* direct children of |stream|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int
nghttp2_stream_dep_all_your_stream_are_belong_to_us(nghttp2_stream *stream,
nghttp2_session *session);
/*
* Returns nonzero if |stream| is in any dependency tree.
*/
int nghttp2_stream_in_dep_tree(nghttp2_stream *stream);
struct nghttp2_stream_roots {
nghttp2_stream *head;
int32_t num_streams;
};
void nghttp2_stream_roots_init(nghttp2_stream_roots *roots);
void nghttp2_stream_roots_free(nghttp2_stream_roots *roots);
void nghttp2_stream_roots_add(nghttp2_stream_roots *roots,
nghttp2_stream *stream);
void nghttp2_stream_roots_remove(nghttp2_stream_roots *roots,
nghttp2_stream *stream);
void nghttp2_stream_roots_remove_all(nghttp2_stream_roots *roots);
#endif /* NGHTTP2_STREAM */

View File

@ -3187,7 +3187,7 @@ void test_nghttp2_session_reprioritize_stream(void) {
nghttp2_session_reprioritize_stream(session, stream, &pri_spec);
CU_ASSERT(10 == stream->weight);
CU_ASSERT(NULL == stream->dep_prev);
CU_ASSERT(&session->root == stream->dep_prev);
/* If depenency to idle stream which is not in depdenency tree yet */
@ -4473,7 +4473,7 @@ void test_nghttp2_session_open_stream(void) {
CU_ASSERT(0 == session->num_outgoing_streams);
CU_ASSERT(NGHTTP2_STREAM_OPENED == stream->state);
CU_ASSERT(245 == stream->weight);
CU_ASSERT(NULL == stream->dep_prev);
CU_ASSERT(&session->root == stream->dep_prev);
CU_ASSERT(NGHTTP2_SHUT_NONE == stream->shut_flags);
stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
@ -4481,7 +4481,7 @@ void test_nghttp2_session_open_stream(void) {
NGHTTP2_STREAM_OPENING, NULL);
CU_ASSERT(1 == session->num_incoming_streams);
CU_ASSERT(1 == session->num_outgoing_streams);
CU_ASSERT(NULL == stream->dep_prev);
CU_ASSERT(&session->root == stream->dep_prev);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight);
CU_ASSERT(NGHTTP2_SHUT_NONE == stream->shut_flags);
@ -4490,7 +4490,7 @@ void test_nghttp2_session_open_stream(void) {
NGHTTP2_STREAM_RESERVED, NULL);
CU_ASSERT(1 == session->num_incoming_streams);
CU_ASSERT(1 == session->num_outgoing_streams);
CU_ASSERT(NULL == stream->dep_prev);
CU_ASSERT(&session->root == stream->dep_prev);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight);
CU_ASSERT(NGHTTP2_SHUT_RD == stream->shut_flags);
@ -4512,7 +4512,7 @@ void test_nghttp2_session_open_stream(void) {
stream = nghttp2_session_get_stream_raw(session, 1000000007);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight);
CU_ASSERT(NULL != stream->root_next);
CU_ASSERT(&session->root == stream->dep_prev);
/* Dependency to closed stream which is not in dependency tree */
session->last_recv_stream_id = 7;
@ -5603,12 +5603,14 @@ void test_nghttp2_pack_settings_payload(void) {
void test_nghttp2_session_stream_dep_add(void) {
nghttp2_session *session;
nghttp2_session_callbacks callbacks;
nghttp2_stream *a, *b, *c, *d, *e;
nghttp2_stream *a, *b, *c, *d, *e, *root;
memset(&callbacks, 0, sizeof(callbacks));
nghttp2_session_server_new(&session, &callbacks, NULL);
root = &session->root;
a = open_stream(session, 1);
c = open_stream_with_dep(session, 5, a);
@ -5622,24 +5624,17 @@ void test_nghttp2_session_stream_dep_add(void) {
* d
*/
CU_ASSERT(4 == a->num_substreams);
CU_ASSERT(1 == b->num_substreams);
CU_ASSERT(2 == c->num_substreams);
CU_ASSERT(1 == d->num_substreams);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 == a->sum_dep_weight);
CU_ASSERT(0 == b->sum_dep_weight);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
CU_ASSERT(0 == d->sum_dep_weight);
check_stream_dep_sib(a, NULL, b, NULL, NULL);
check_stream_dep_sib(a, root, b, NULL, NULL);
check_stream_dep_sib(b, a, NULL, NULL, c);
check_stream_dep_sib(c, a, d, b, NULL);
check_stream_dep_sib(d, c, NULL, NULL, NULL);
CU_ASSERT(4 == session->roots.num_streams);
CU_ASSERT(a == session->roots.head);
CU_ASSERT(NULL == a->root_next);
CU_ASSERT(a == session->root.dep_next);
e = open_stream_with_dep_excl(session, 9, a);
@ -5652,27 +5647,19 @@ void test_nghttp2_session_stream_dep_add(void) {
* d
*/
CU_ASSERT(5 == a->num_substreams);
CU_ASSERT(4 == e->num_substreams);
CU_ASSERT(1 == b->num_substreams);
CU_ASSERT(2 == c->num_substreams);
CU_ASSERT(1 == d->num_substreams);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 == e->sum_dep_weight);
CU_ASSERT(0 == b->sum_dep_weight);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
CU_ASSERT(0 == d->sum_dep_weight);
check_stream_dep_sib(a, NULL, e, NULL, NULL);
check_stream_dep_sib(a, root, e, NULL, NULL);
check_stream_dep_sib(e, a, b, NULL, NULL);
check_stream_dep_sib(b, e, NULL, NULL, c);
check_stream_dep_sib(c, e, d, b, NULL);
check_stream_dep_sib(d, c, NULL, NULL, NULL);
CU_ASSERT(5 == session->roots.num_streams);
CU_ASSERT(a == session->roots.head);
CU_ASSERT(NULL == a->root_next);
CU_ASSERT(a == session->root.dep_next);
nghttp2_session_del(session);
}
@ -5680,13 +5667,15 @@ void test_nghttp2_session_stream_dep_add(void) {
void test_nghttp2_session_stream_dep_remove(void) {
nghttp2_session *session;
nghttp2_session_callbacks callbacks;
nghttp2_stream *a, *b, *c, *d, *e, *f;
nghttp2_stream *a, *b, *c, *d, *e, *f, *root;
memset(&callbacks, 0, sizeof(callbacks));
/* Remove root */
nghttp2_session_server_new(&session, &callbacks, NULL);
root = &session->root;
a = open_stream(session, 1);
b = open_stream_with_dep(session, 3, a);
c = open_stream_with_dep(session, 5, a);
@ -5702,36 +5691,30 @@ void test_nghttp2_session_stream_dep_remove(void) {
nghttp2_stream_dep_remove(a);
/* becomes:
* b c
* |
* d
* c b
* |
* d
*/
CU_ASSERT(1 == a->num_substreams);
CU_ASSERT(1 == b->num_substreams);
CU_ASSERT(2 == c->num_substreams);
CU_ASSERT(1 == d->num_substreams);
CU_ASSERT(0 == a->sum_dep_weight);
CU_ASSERT(0 == b->sum_dep_weight);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
CU_ASSERT(0 == d->sum_dep_weight);
check_stream_dep_sib(a, NULL, NULL, NULL, NULL);
check_stream_dep_sib(b, NULL, NULL, NULL, NULL);
check_stream_dep_sib(c, NULL, d, NULL, NULL);
check_stream_dep_sib(b, root, NULL, c, NULL);
check_stream_dep_sib(c, root, d, NULL, b);
check_stream_dep_sib(d, c, NULL, NULL, NULL);
CU_ASSERT(3 == session->roots.num_streams);
CU_ASSERT(b == session->roots.head);
CU_ASSERT(c == b->root_next);
CU_ASSERT(NULL == c->root_next);
CU_ASSERT(c == session->root.dep_next);
nghttp2_session_del(session);
/* Remove right most stream */
nghttp2_session_server_new(&session, &callbacks, NULL);
root = &session->root;
a = open_stream(session, 1);
b = open_stream_with_dep(session, 3, a);
c = open_stream_with_dep(session, 5, a);
@ -5754,30 +5737,25 @@ void test_nghttp2_session_stream_dep_remove(void) {
* d
*/
CU_ASSERT(3 == a->num_substreams);
CU_ASSERT(1 == b->num_substreams);
CU_ASSERT(2 == c->num_substreams);
CU_ASSERT(1 == d->num_substreams);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
CU_ASSERT(0 == d->sum_dep_weight);
CU_ASSERT(0 == b->sum_dep_weight);
check_stream_dep_sib(a, NULL, c, NULL, NULL);
check_stream_dep_sib(a, root, c, NULL, NULL);
check_stream_dep_sib(b, NULL, NULL, NULL, NULL);
check_stream_dep_sib(c, a, d, NULL, NULL);
check_stream_dep_sib(d, c, NULL, NULL, NULL);
CU_ASSERT(3 == session->roots.num_streams);
CU_ASSERT(a == session->roots.head);
CU_ASSERT(NULL == a->root_next);
CU_ASSERT(a == session->root.dep_next);
nghttp2_session_del(session);
/* Remove left most stream */
nghttp2_session_server_new(&session, &callbacks, NULL);
root = &session->root;
a = open_stream(session, 1);
b = open_stream_with_dep(session, 3, a);
c = open_stream_with_dep(session, 5, a);
@ -5799,19 +5777,13 @@ void test_nghttp2_session_stream_dep_remove(void) {
* e--d--b
*/
CU_ASSERT(4 == a->num_substreams);
CU_ASSERT(1 == b->num_substreams);
CU_ASSERT(1 == c->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(0 == b->sum_dep_weight);
CU_ASSERT(0 == d->sum_dep_weight);
CU_ASSERT(0 == c->sum_dep_weight);
CU_ASSERT(0 == e->sum_dep_weight);
check_stream_dep_sib(a, NULL, e, NULL, NULL);
check_stream_dep_sib(a, root, e, NULL, NULL);
check_stream_dep_sib(b, a, NULL, d, NULL);
check_stream_dep_sib(c, NULL, NULL, NULL, NULL);
check_stream_dep_sib(d, a, NULL, e, b);
@ -5822,6 +5794,8 @@ void test_nghttp2_session_stream_dep_remove(void) {
/* Remove middle stream */
nghttp2_session_server_new(&session, &callbacks, NULL);
root = &session->root;
a = open_stream(session, 1);
b = open_stream_with_dep(session, 3, a);
c = open_stream_with_dep(session, 5, a);
@ -5836,13 +5810,6 @@ void test_nghttp2_session_stream_dep_remove(void) {
* f--e
*/
CU_ASSERT(6 == a->num_substreams);
CU_ASSERT(1 == b->num_substreams);
CU_ASSERT(3 == c->num_substreams);
CU_ASSERT(1 == d->num_substreams);
CU_ASSERT(1 == e->num_substreams);
CU_ASSERT(1 == f->num_substreams);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 3 == a->sum_dep_weight);
CU_ASSERT(0 == b->sum_dep_weight);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 == c->sum_dep_weight);
@ -5858,13 +5825,6 @@ void test_nghttp2_session_stream_dep_remove(void) {
* d--f--e--b
*/
CU_ASSERT(5 == a->num_substreams);
CU_ASSERT(1 == b->num_substreams);
CU_ASSERT(1 == c->num_substreams);
CU_ASSERT(1 == d->num_substreams);
CU_ASSERT(1 == e->num_substreams);
CU_ASSERT(1 == f->num_substreams);
/* c's weight 16 is distributed evenly to e and f. Each weight of e
and f becomes 8. */
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 + 8 * 2 == a->sum_dep_weight);
@ -5874,7 +5834,7 @@ void test_nghttp2_session_stream_dep_remove(void) {
CU_ASSERT(0 == e->sum_dep_weight);
CU_ASSERT(0 == f->sum_dep_weight);
check_stream_dep_sib(a, NULL, d, NULL, NULL);
check_stream_dep_sib(a, root, d, NULL, NULL);
check_stream_dep_sib(b, a, NULL, e, NULL);
check_stream_dep_sib(c, NULL, NULL, NULL, NULL);
check_stream_dep_sib(e, a, NULL, f, b);
@ -5887,13 +5847,15 @@ void test_nghttp2_session_stream_dep_remove(void) {
void test_nghttp2_session_stream_dep_add_subtree(void) {
nghttp2_session *session;
nghttp2_session_callbacks callbacks;
nghttp2_stream *a, *b, *c, *d, *e, *f;
nghttp2_stream *a, *b, *c, *d, *e, *f, *root;
memset(&callbacks, 0, sizeof(callbacks));
/* dep_stream has dep_next */
nghttp2_session_server_new(&session, &callbacks, NULL);
root = &session->root;
a = open_stream(session, 1);
b = open_stream_with_dep(session, 3, a);
c = open_stream_with_dep(session, 5, a);
@ -5909,6 +5871,7 @@ void test_nghttp2_session_stream_dep_add_subtree(void) {
* d
*/
nghttp2_stream_dep_remove_subtree(e);
nghttp2_stream_dep_add_subtree(a, e, session);
/* becomes
@ -5919,13 +5882,6 @@ void test_nghttp2_session_stream_dep_add_subtree(void) {
* f d
*/
CU_ASSERT(6 == a->num_substreams);
CU_ASSERT(1 == b->num_substreams);
CU_ASSERT(2 == c->num_substreams);
CU_ASSERT(1 == d->num_substreams);
CU_ASSERT(2 == e->num_substreams);
CU_ASSERT(1 == f->num_substreams);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 3 == a->sum_dep_weight);
CU_ASSERT(0 == b->sum_dep_weight);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
@ -5933,7 +5889,7 @@ void test_nghttp2_session_stream_dep_add_subtree(void) {
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == e->sum_dep_weight);
CU_ASSERT(0 == f->sum_dep_weight);
check_stream_dep_sib(a, NULL, e, NULL, NULL);
check_stream_dep_sib(a, root, e, NULL, NULL);
check_stream_dep_sib(b, a, NULL, c, NULL);
check_stream_dep_sib(c, a, d, e, b);
check_stream_dep_sib(d, c, NULL, NULL, NULL);
@ -5945,6 +5901,8 @@ void test_nghttp2_session_stream_dep_add_subtree(void) {
/* dep_stream has dep_next and now we insert subtree */
nghttp2_session_server_new(&session, &callbacks, NULL);
root = &session->root;
a = open_stream(session, 1);
b = open_stream_with_dep(session, 3, a);
c = open_stream_with_dep(session, 5, a);
@ -5960,6 +5918,7 @@ void test_nghttp2_session_stream_dep_add_subtree(void) {
* d
*/
nghttp2_stream_dep_remove_subtree(e);
nghttp2_stream_dep_insert_subtree(a, e, session);
/* becomes
@ -5972,13 +5931,6 @@ void test_nghttp2_session_stream_dep_add_subtree(void) {
* d
*/
CU_ASSERT(6 == a->num_substreams);
CU_ASSERT(1 == b->num_substreams);
CU_ASSERT(2 == c->num_substreams);
CU_ASSERT(1 == d->num_substreams);
CU_ASSERT(5 == e->num_substreams);
CU_ASSERT(1 == f->num_substreams);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight);
CU_ASSERT(0 == b->sum_dep_weight);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
@ -5986,7 +5938,7 @@ void test_nghttp2_session_stream_dep_add_subtree(void) {
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 3 == e->sum_dep_weight);
CU_ASSERT(0 == f->sum_dep_weight);
check_stream_dep_sib(a, NULL, e, NULL, NULL);
check_stream_dep_sib(a, root, e, NULL, NULL);
check_stream_dep_sib(e, a, f, NULL, NULL);
check_stream_dep_sib(f, e, NULL, NULL, c);
check_stream_dep_sib(b, e, NULL, c, NULL);
@ -5999,13 +5951,15 @@ void test_nghttp2_session_stream_dep_add_subtree(void) {
void test_nghttp2_session_stream_dep_remove_subtree(void) {
nghttp2_session *session;
nghttp2_session_callbacks callbacks;
nghttp2_stream *a, *b, *c, *d, *e;
nghttp2_stream *a, *b, *c, *d, *e, *root;
memset(&callbacks, 0, sizeof(callbacks));
/* Remove left most stream */
nghttp2_session_server_new(&session, &callbacks, NULL);
root = &session->root;
a = open_stream(session, 1);
b = open_stream_with_dep(session, 3, a);
c = open_stream_with_dep(session, 5, a);
@ -6026,17 +5980,12 @@ void test_nghttp2_session_stream_dep_remove_subtree(void) {
* b d
*/
CU_ASSERT(2 == a->num_substreams);
CU_ASSERT(1 == b->num_substreams);
CU_ASSERT(2 == c->num_substreams);
CU_ASSERT(1 == d->num_substreams);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight);
CU_ASSERT(0 == b->sum_dep_weight);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
CU_ASSERT(0 == d->sum_dep_weight);
check_stream_dep_sib(a, NULL, b, NULL, NULL);
check_stream_dep_sib(a, root, b, NULL, NULL);
check_stream_dep_sib(b, a, NULL, NULL, NULL);
check_stream_dep_sib(c, NULL, d, NULL, NULL);
check_stream_dep_sib(d, c, NULL, NULL, NULL);
@ -6046,6 +5995,8 @@ void test_nghttp2_session_stream_dep_remove_subtree(void) {
/* Remove right most stream */
nghttp2_session_server_new(&session, &callbacks, NULL);
root = &session->root;
a = open_stream(session, 1);
b = open_stream_with_dep(session, 3, a);
c = open_stream_with_dep(session, 5, a);
@ -6068,17 +6019,12 @@ void test_nghttp2_session_stream_dep_remove_subtree(void) {
* d
*/
CU_ASSERT(3 == a->num_substreams);
CU_ASSERT(1 == b->num_substreams);
CU_ASSERT(2 == c->num_substreams);
CU_ASSERT(1 == d->num_substreams);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight);
CU_ASSERT(0 == b->sum_dep_weight);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
CU_ASSERT(0 == d->sum_dep_weight);
check_stream_dep_sib(a, NULL, c, NULL, NULL);
check_stream_dep_sib(a, root, c, NULL, NULL);
check_stream_dep_sib(c, a, d, NULL, NULL);
check_stream_dep_sib(d, c, NULL, NULL, NULL);
check_stream_dep_sib(b, NULL, NULL, NULL, NULL);
@ -6088,6 +6034,8 @@ void test_nghttp2_session_stream_dep_remove_subtree(void) {
/* Remove middle stream */
nghttp2_session_server_new(&session, &callbacks, NULL);
root = &session->root;
a = open_stream(session, 1);
e = open_stream_with_dep(session, 9, a);
c = open_stream_with_dep(session, 5, a);
@ -6109,19 +6057,13 @@ void test_nghttp2_session_stream_dep_remove_subtree(void) {
* b--e d
*/
CU_ASSERT(3 == a->num_substreams);
CU_ASSERT(1 == b->num_substreams);
CU_ASSERT(1 == e->num_substreams);
CU_ASSERT(2 == c->num_substreams);
CU_ASSERT(1 == d->num_substreams);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 == a->sum_dep_weight);
CU_ASSERT(0 == b->sum_dep_weight);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
CU_ASSERT(0 == d->sum_dep_weight);
CU_ASSERT(0 == e->sum_dep_weight);
check_stream_dep_sib(a, NULL, b, NULL, NULL);
check_stream_dep_sib(a, root, b, NULL, NULL);
check_stream_dep_sib(b, a, NULL, NULL, e);
check_stream_dep_sib(e, a, NULL, b, NULL);
check_stream_dep_sib(c, NULL, d, NULL, NULL);
@ -6133,7 +6075,7 @@ void test_nghttp2_session_stream_dep_remove_subtree(void) {
void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
nghttp2_session *session;
nghttp2_session_callbacks callbacks;
nghttp2_stream *a, *b, *c, *d;
nghttp2_stream *a, *b, *c, *d, *root;
nghttp2_outbound_item *db, *dc;
nghttp2_mem *mem;
@ -6143,6 +6085,8 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
nghttp2_session_server_new(&session, &callbacks, NULL);
root = &session->root;
a = open_stream(session, 1);
b = open_stream_with_dep(session, 3, a);
@ -6154,8 +6098,7 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
*/
nghttp2_stream_dep_remove_subtree(c);
CU_ASSERT(0 ==
nghttp2_stream_dep_all_your_stream_are_belong_to_us(c, session));
CU_ASSERT(0 == nghttp2_stream_dep_insert_subtree(&session->root, c, session));
/*
* c
@ -6165,10 +6108,6 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
* b
*/
CU_ASSERT(3 == c->num_substreams);
CU_ASSERT(2 == a->num_substreams);
CU_ASSERT(1 == b->num_substreams);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight);
CU_ASSERT(0 == b->sum_dep_weight);
@ -6177,7 +6116,7 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
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, root, a, NULL, NULL);
check_stream_dep_sib(a, c, b, NULL, NULL);
check_stream_dep_sib(b, a, NULL, NULL, NULL);
@ -6185,6 +6124,8 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
nghttp2_session_server_new(&session, &callbacks, NULL);
root = &session->root;
a = open_stream(session, 1);
b = open_stream(session, 3);
c = open_stream(session, 5);
@ -6194,8 +6135,7 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
*/
nghttp2_stream_dep_remove_subtree(c);
CU_ASSERT(0 ==
nghttp2_stream_dep_all_your_stream_are_belong_to_us(c, session));
CU_ASSERT(0 == nghttp2_stream_dep_insert_subtree(&session->root, c, session));
/*
* c
@ -6203,10 +6143,6 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
* b--a
*/
CU_ASSERT(3 == c->num_substreams);
CU_ASSERT(1 == a->num_substreams);
CU_ASSERT(1 == b->num_substreams);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 == c->sum_dep_weight);
CU_ASSERT(0 == b->sum_dep_weight);
CU_ASSERT(0 == a->sum_dep_weight);
@ -6215,7 +6151,7 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
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, root, b, NULL, NULL);
check_stream_dep_sib(b, c, NULL, NULL, a);
check_stream_dep_sib(a, c, NULL, b, NULL);
@ -6223,6 +6159,8 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
nghttp2_session_server_new(&session, &callbacks, NULL);
root = &session->root;
a = open_stream(session, 1);
b = open_stream_with_dep(session, 3, a);
@ -6235,22 +6173,16 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
*/
nghttp2_stream_dep_remove_subtree(c);
CU_ASSERT(0 ==
nghttp2_stream_dep_all_your_stream_are_belong_to_us(c, session));
CU_ASSERT(0 == nghttp2_stream_dep_insert_subtree(&session->root, c, session));
/*
* c
* |
* a--d
* |
* b
* d--a
* |
* b
*/
CU_ASSERT(4 == c->num_substreams);
CU_ASSERT(1 == d->num_substreams);
CU_ASSERT(2 == a->num_substreams);
CU_ASSERT(1 == b->num_substreams);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 == c->sum_dep_weight);
CU_ASSERT(0 == d->sum_dep_weight);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight);
@ -6261,15 +6193,17 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
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(d, c, NULL, a, NULL);
check_stream_dep_sib(a, c, b, NULL, d);
check_stream_dep_sib(c, root, d, NULL, NULL);
check_stream_dep_sib(d, c, NULL, NULL, a);
check_stream_dep_sib(a, c, b, d, NULL);
check_stream_dep_sib(b, a, NULL, NULL, NULL);
nghttp2_session_del(session);
nghttp2_session_server_new(&session, &callbacks, NULL);
root = &session->root;
a = open_stream(session, 1);
b = open_stream_with_dep(session, 3, a);
@ -6286,15 +6220,14 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
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));
CU_ASSERT(0 == nghttp2_stream_dep_insert_subtree(&session->root, c, session));
/*
* c
* |
* a--d
* |
* b
* d--a
* |
* b
*/
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
@ -6305,15 +6238,17 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
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(c, root, d, NULL, NULL);
check_stream_dep_sib(d, c, NULL, NULL, a);
check_stream_dep_sib(a, c, b, d, NULL);
check_stream_dep_sib(b, a, NULL, NULL, NULL);
nghttp2_session_del(session);
nghttp2_session_server_new(&session, &callbacks, NULL);
root = &session->root;
a = open_stream(session, 1);
b = open_stream_with_dep(session, 3, a);
@ -6332,15 +6267,14 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
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));
CU_ASSERT(0 == nghttp2_stream_dep_insert_subtree(&session->root, c, session));
/*
* c
* |
* a--d
* |
* b
* d--a
* |
* b
*/
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
@ -6348,9 +6282,9 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
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(c, root, d, NULL, NULL);
check_stream_dep_sib(d, c, NULL, NULL, a);
check_stream_dep_sib(a, c, b, d, NULL);
check_stream_dep_sib(b, a, NULL, NULL, NULL);
nghttp2_session_del(session);
@ -6581,9 +6515,8 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
c = open_stream_with_dep(session, 5, a);
d = open_stream_with_dep(session, 7, c);
e = open_stream(session, 9);
e = open_stream_with_dep_weight(session, 9, 32, &session->root);
f = open_stream_with_dep(session, 11, e);
e->weight = 32;
/*
* a e
@ -6645,7 +6578,7 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
nghttp2_stream_dep_remove_subtree(b);
nghttp2_stream_dep_make_root(b, session);
CU_ASSERT(0 == nghttp2_stream_dep_add_subtree(&session->root, b, session));
/*
* a b
@ -6671,7 +6604,7 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
nghttp2_stream_dep_remove_subtree(a);
nghttp2_stream_dep_make_root(a, session);
CU_ASSERT(0 == nghttp2_stream_dep_add_subtree(&session->root, a, session));
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
@ -6684,7 +6617,7 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
nghttp2_stream_dep_remove_subtree(c);
nghttp2_stream_dep_make_root(c, session);
CU_ASSERT(0 == nghttp2_stream_dep_add_subtree(&session->root, c, session));
/*
* a b c
@ -6766,7 +6699,7 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
/* Remove subtree b */
nghttp2_stream_dep_remove_subtree(b);
nghttp2_stream_dep_make_root(b, session);
CU_ASSERT(0 == nghttp2_stream_dep_add_subtree(&session->root, b, session));
/*
* b a
@ -6813,6 +6746,7 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
da = create_data_ob_item(mem);
nghttp2_stream_attach_item(a, da, session);
nghttp2_stream_dep_remove_subtree(a);
nghttp2_stream_dep_add_subtree(b, a, session);
/*
@ -7039,7 +6973,7 @@ void test_nghttp2_session_large_dep_tree(void) {
nghttp2_session_callbacks callbacks;
size_t i;
nghttp2_stream *dep_stream = NULL;
nghttp2_stream *root_stream;
nghttp2_stream *stream;
int32_t stream_id;
memset(&callbacks, 0, sizeof(callbacks));
@ -7048,22 +6982,17 @@ void test_nghttp2_session_large_dep_tree(void) {
nghttp2_session_server_new(&session, &callbacks, NULL);
stream_id = 1;
for (i = 0; i < NGHTTP2_MAX_DEP_TREE_LENGTH; ++i) {
for (i = 0; i < 250; ++i) {
dep_stream = open_stream_with_dep(session, stream_id, dep_stream);
stream_id += 2;
}
root_stream = nghttp2_session_get_stream(session, 1);
/* Check that last dep_stream must be part of tree */
CU_ASSERT(nghttp2_stream_dep_subtree_find(root_stream, dep_stream));
dep_stream = open_stream_with_dep(session, stream_id, dep_stream);
/* We exceeded NGHTTP2_MAX_DEP_TREE_LENGTH limit. dep_stream is now
root node and has no descendants. */
CU_ASSERT(!nghttp2_stream_dep_subtree_find(root_stream, dep_stream));
CU_ASSERT(nghttp2_stream_in_dep_tree(dep_stream));
stream_id = 1;
for (i = 0; i < 250; ++i) {
stream = nghttp2_session_get_stream(session, stream_id);
CU_ASSERT(nghttp2_stream_dep_subtree_find(&session->root, stream));
CU_ASSERT(nghttp2_stream_in_dep_tree(stream));
}
nghttp2_session_del(session);
}