diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 88b5fb65..e6de0d43 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -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); diff --git a/lib/nghttp2_session.h b/lib/nghttp2_session.h index 87430bdb..5400a22c 100644 --- a/lib/nghttp2_session.h +++ b/lib/nghttp2_session.h @@ -153,7 +153,8 @@ typedef struct nghttp2_inflight_settings nghttp2_inflight_settings; struct nghttp2_session { nghttp2_map /* */ 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 */ diff --git a/lib/nghttp2_stream.c b/lib/nghttp2_stream.c index 0c74c03c..eccf8e62 100644 --- a/lib/nghttp2_stream.c +++ b/lib/nghttp2_stream.c @@ -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; } diff --git a/lib/nghttp2_stream.h b/lib/nghttp2_stream.h index 062ace00..72d1ae72 100644 --- a/lib/nghttp2_stream.h +++ b/lib/nghttp2_stream.h @@ -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 */ diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 45a80a98..84765359 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -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); }