From ac86b51e37c45da7175bc3bffd4d36576054cdf9 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Mon, 14 Apr 2014 23:53:54 +0900 Subject: [PATCH 1/5] Implement simplified dependency based priority --- lib/includes/nghttp2/nghttp2.h | 180 +++---- lib/nghttp2_frame.c | 91 ++-- lib/nghttp2_frame.h | 3 +- lib/nghttp2_priority_spec.c | 27 +- lib/nghttp2_session.c | 342 ++++---------- lib/nghttp2_session.h | 24 - lib/nghttp2_stream.c | 341 ++++++------- lib/nghttp2_stream.h | 96 ++-- lib/nghttp2_submit.c | 90 ++-- src/app_helper.cc | 46 +- src/nghttp.cc | 31 +- tests/main.c | 2 + tests/nghttp2_frame_test.c | 94 +--- tests/nghttp2_session_test.c | 840 ++++++++++++++++++++------------- tests/nghttp2_session_test.h | 1 + tests/nghttp2_test_helper.c | 17 +- tests/nghttp2_test_helper.h | 5 + 17 files changed, 954 insertions(+), 1276 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index c97dac81..6cae2f78 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -114,21 +114,21 @@ typedef struct { /** * @macro * - * The default weight of priority group. + * The default weight of stream dependency. */ #define NGHTTP2_DEFAULT_WEIGHT 16 /** * @macro * - * The maximum weight of priority group. + * The maximum weight of stream dependency. */ #define NGHTTP2_MAX_WEIGHT 256 /** * @macro * - * The minimum weight of priority group. + * The minimum weight of stream dependency. */ #define NGHTTP2_MIN_WEIGHT 1 @@ -482,13 +482,9 @@ typedef enum { */ NGHTTP2_FLAG_PAD_HIGH = 0x10, /** - * The PRIORITY_GROUP flag. + * The PRIORITY flag. */ - NGHTTP2_FLAG_PRIORITY_GROUP = 0x20, - /** - * The PRIORITY_DEPENDENCY flag. - */ - NGHTTP2_FLAG_PRIORITY_DEPENDENCY = 0x40 + NGHTTP2_FLAG_PRIORITY = 0x20 } nghttp2_flag; /** @@ -731,93 +727,25 @@ typedef enum { NGHTTP2_HCAT_HEADERS = 3 } nghttp2_headers_category; -/** - * @enum - * - * The type of priority specified in :type:`nghttp2_priority_spec`. - */ -typedef enum { - /** - * No priority is given. The default priority will be used. - */ - NGHTTP2_PRIORITY_TYPE_NONE = 0, - /** - * Priority group ID and its weight are specified. - */ - NGHTTP2_PRIORITY_TYPE_GROUP = 1, - /** - * The stream ID of a stream to depend on and its exclusive flag is - * specified. - */ - NGHTTP2_PRIORITY_TYPE_DEP = 2 -} nghttp2_priority_type; - /** * @struct * - * This structure stores priority group ID and its weight. + * The structure to specify stream dependency. */ typedef struct { /** - * The priority group ID - */ - int32_t pri_group_id; - /** - * The weight of the priority group - */ - int32_t weight; -} nghttp2_priority_group; - -/** - * @struct - * - * This structure stores stream ID of the stream to depend on and its - * dependency is exclusive or not. - */ -typedef struct { - /** - * The stream ID of the stream to depend on. + * The stream ID of the stream to depend on. Specifying 0 makes + * stream not depend any other stream. */ int32_t stream_id; + /** + * The weight of this dependency. + */ + int32_t weight; /** * nonzero means exclusive dependency */ uint8_t exclusive; -} nghttp2_priority_dep; - -/** - * @struct - * - * The structure to specify stream dependency. To specify stream - * dependency, specify |pri_type| and fill the |group| or |dep| member - * according to |pri_type|. - */ -typedef struct { - /** - * Type of priority specification. If |pri_type| is - * :enum:`NGHTTP2_PRIORITY_TYPE_GROUP`, fill |group|. If |pri_type| - * is :enum:`NGHTTP2_PRIORITY_TYPE_DEP`, fill |dep|. If |pri_type| - * is :enum:`NGHTTP2_PRIORITY_TYPE_NONE`, the other data members are - * ignored and it means that default priority group ID (which is - * same as the stream ID) and default weight - * :macro:`NGHTTP2_DEFAULT_WEIGHT` are specified. - */ - nghttp2_priority_type pri_type; - - union { - /** - * Specify priority group ID and its weight. This field is - * interpreted only when |pri_type| member is - * :enum:`NGHTTP2_PRIORITY_TYPE_GROUP`. - */ - nghttp2_priority_group group; - /** - * Specify stream ID of a stream to depend on and exclusive flag. - * This field is interpreted only when |pri_type| member is - * :enum:`NGHTTP2_PRIORITY_TYPE_DEP`. - */ - nghttp2_priority_dep dep; - } spec; } nghttp2_priority_spec; /** @@ -2153,32 +2081,34 @@ const char* nghttp2_strerror(int lib_error_code); /** * @function * - * Initializes |pri_spec| with priority group ID |pri_group_id| and - * its weight |weight|. + * Initializes |pri_spec| with the |stream_id| of the stream to depend + * on with |weight| and its exclusive flag. If |exclusive| is + * nonzero, exclusive flag is set. * * The |weight| must be in [:enum:`NGHTTP2_MIN_WEIGHT`, - * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If |weight| is strictly - * less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes - * :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than - * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`. - * - * To specify weight for the default priority group (which is the same - * as the stream ID of the stream) in `nghttp2_submit_request()` and - * `nghttp2_submit_headers()` and its stream ID is not known in - * advance, specify -1 to |pri_group_id|. + * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. */ -void nghttp2_priority_spec_group_init(nghttp2_priority_spec *pri_spec, - int32_t pri_group_id, int32_t weight); +void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec, + int32_t stream_id, int32_t weight, + int exclusive); /** * @function * - * Initializes |pri_spec| with the |stream_id| of the stream to depend - * on and its exclusive flag. If |exclusive| is nonzero, exclusive - * flag is set. + * Initializes |pri_spec| with the default values. The default values + * are: stream_id = 0, weight = :macro:`NGHTTP2_DEFAULT_WEIGHT` and + * exclusive = 0. */ -void nghttp2_priority_spec_dep_init(nghttp2_priority_spec *pri_spec, - int32_t stream_id, int exclusive); +void nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec); + +/** + * @function + * + * Returns nonzero if the |pri_spec| is filled with default values. + * `pri_spec->exclusive` is ignored since it is irrelevant when + * `pri_spec->stream_id == 0`. + */ +int nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec); /** * @function @@ -2186,12 +2116,17 @@ void nghttp2_priority_spec_dep_init(nghttp2_priority_spec *pri_spec, * Submits HEADERS frame and optionally one or more DATA frames. * * The |pri_spec| is priority specification of this request. ``NULL`` - * means the default priority (priority group ID becomes its stream ID - * and weight is :macro:`NGHTTP2_DEFAULT_WEIGHT`). To specify the - * priority, use either `nghttp2_priority_spec_group_init()` or - * `nghttp2_priority_spec_dep_init()`. If |pri_spec| is not ``NULL``, + * means the default priority (see + * `nghttp2_priority_spec_default_init()`). To specify the priority, + * use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``, * this function will copy its data members. * + * The `pri_spec->weight` must be in [:enum:`NGHTTP2_MIN_WEIGHT`, + * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If `pri_spec->weight` is + * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes + * :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than + * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`. + * * The |nva| is an array of name/value pair :type:`nghttp2_nv` with * |nvlen| elements. The value is opaque sequence of bytes and * therefore can contain NULL byte (0x0). If the application requires @@ -2234,8 +2169,6 @@ void nghttp2_priority_spec_dep_init(nghttp2_priority_spec *pri_spec, * * :enum:`NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` - * The |pri_spec->pri_type| is invalid. */ int nghttp2_submit_request(nghttp2_session *session, const nghttp2_priority_spec *pri_spec, @@ -2306,12 +2239,17 @@ int nghttp2_submit_response(nghttp2_session *session, * response, specify stream ID in |stream_id|. * * The |pri_spec| is priority specification of this request. ``NULL`` - * means the default priority (priority group ID becomes its stream ID - * and weight is :macro:`NGHTTP2_DEFAULT_WEIGHT`). To specify the - * priority, use either `nghttp2_priority_spec_group_init()` or - * `nghttp2_priority_spec_dep_init()`. If |pri_spec| is not ``NULL``, + * means the default priority (see + * `nghttp2_priority_spec_default_init()`). To specify the priority, + * use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``, * this function will copy its data members. * + * The `pri_spec->weight` must be in [:enum:`NGHTTP2_MIN_WEIGHT`, + * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If `pri_spec->weight` is + * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes + * :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than + * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`. + * * The |nva| is an array of name/value pair :type:`nghttp2_nv` with * |nvlen| elements. The value is opaque sequence of bytes and * therefore can contain NULL byte (0x0). If the application requires @@ -2336,8 +2274,6 @@ int nghttp2_submit_response(nghttp2_session *session, * * :enum:`NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` - * The |pri_spec->pri_type| is invalid. */ int nghttp2_submit_headers(nghttp2_session *session, uint8_t flags, int32_t stream_id, @@ -2379,10 +2315,15 @@ int nghttp2_submit_data(nghttp2_session *session, uint8_t flags, * :enum:`NGHTTP2_FLAG_NONE`. * * The |pri_spec| is priority specification of this request. ``NULL`` - * is not allowed for this function. To specify the priority, use - * either `nghttp2_priority_spec_group_init()` or - * `nghttp2_priority_spec_dep_init()`. This function will copy its - * data members. + * is not allowed for this function. To specify the priority, use + * `nghttp2_priority_spec_init()`. This function will copy its data + * members. + * + * The `pri_spec->weight` must be in [:enum:`NGHTTP2_MIN_WEIGHT`, + * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If `pri_spec->weight` is + * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes + * :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than + * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -2390,8 +2331,7 @@ int nghttp2_submit_data(nghttp2_session *session, uint8_t flags, * :enum:`NGHTTP2_ERR_NOMEM` * Out of memory. * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` - * The |pri_spec| is NULL; or the |pri_spec->pri_type| is invalid; - * or trying to depend on itself. + * The |pri_spec| is NULL; or trying to depend on itself. */ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags, int32_t stream_id, diff --git a/lib/nghttp2_frame.c b/lib/nghttp2_frame.c index fb047dd2..0b8f7fb8 100644 --- a/lib/nghttp2_frame.c +++ b/lib/nghttp2_frame.c @@ -74,7 +74,12 @@ void nghttp2_frame_headers_init(nghttp2_headers *frame, frame->nva = nva; frame->nvlen = nvlen; frame->cat = NGHTTP2_HCAT_REQUEST; - frame->pri_spec = *pri_spec; + + if(pri_spec) { + frame->pri_spec = *pri_spec; + } else { + nghttp2_priority_spec_default_init(&frame->pri_spec); + } } void nghttp2_frame_headers_free(nghttp2_headers *frame) @@ -85,22 +90,8 @@ void nghttp2_frame_headers_free(nghttp2_headers *frame) void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id, const nghttp2_priority_spec *pri_spec) { - uint8_t flags; - - switch(pri_spec->pri_type) { - case NGHTTP2_PRIORITY_TYPE_GROUP: - flags = NGHTTP2_FLAG_PRIORITY_GROUP; - - break; - case NGHTTP2_PRIORITY_TYPE_DEP: - flags = NGHTTP2_FLAG_PRIORITY_DEPENDENCY; - - break; - default: - assert(0); - } - - nghttp2_frame_set_hd(&frame->hd, 4, NGHTTP2_PRIORITY, flags, stream_id); + nghttp2_frame_set_hd(&frame->hd, 5, NGHTTP2_PRIORITY, NGHTTP2_FLAG_NONE, + stream_id); frame->pri_spec = *pri_spec; } @@ -261,14 +252,10 @@ void nghttp2_frame_private_data_free(nghttp2_private_data *frame) size_t nghttp2_frame_priority_len(uint8_t flags) { - if(flags & NGHTTP2_FLAG_PRIORITY_GROUP) { + if(flags & NGHTTP2_FLAG_PRIORITY) { return 5; } - if(flags & NGHTTP2_FLAG_PRIORITY_DEPENDENCY) { - return 4; - } - return 0; } @@ -375,7 +362,9 @@ int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, return rv; } - nghttp2_frame_pack_priority_spec(buf->pos, &frame->pri_spec); + if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { + nghttp2_frame_pack_priority_spec(buf->pos, &frame->pri_spec); + } frame->padlen = 0; frame->hd.length = nghttp2_bufs_len(bufs); @@ -386,24 +375,11 @@ int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, void nghttp2_frame_pack_priority_spec(uint8_t *buf, const nghttp2_priority_spec *pri_spec) { - switch(pri_spec->pri_type) { - case NGHTTP2_PRIORITY_TYPE_GROUP: - - nghttp2_put_uint32be(buf, pri_spec->spec.group.pri_group_id); - buf[4] = pri_spec->spec.group.weight - 1; - - return; - case NGHTTP2_PRIORITY_TYPE_DEP: - - nghttp2_put_uint32be(buf, pri_spec->spec.dep.stream_id); - if(pri_spec->spec.dep.exclusive) { - buf[0] |= 0x80; - } - - return; - default: - return; + nghttp2_put_uint32be(buf, pri_spec->stream_id); + if(pri_spec->exclusive) { + buf[0] |= 0x80; } + buf[4] = pri_spec->weight - 1; } void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec, @@ -411,33 +387,28 @@ void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec, const uint8_t *payload, size_t payloadlen) { - if(flags & NGHTTP2_FLAG_PRIORITY_GROUP) { - int32_t pri_group_id; - int32_t weight; + int32_t dep_stream_id; + uint8_t exclusive; + int32_t weight; - pri_group_id = nghttp2_get_uint32(payload) & NGHTTP2_PRI_GROUP_ID_MASK; - weight = payload[4] + 1; + dep_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK; + exclusive = (payload[0] & 0x80) > 0; + weight = payload[4] + 1; - nghttp2_priority_spec_group_init(pri_spec, pri_group_id, weight); - } else if(flags & NGHTTP2_FLAG_PRIORITY_DEPENDENCY) { - int32_t dep_stream_id; - uint8_t exclusive; - - dep_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK; - exclusive = (payload[0] & 0x80) > 0; - - nghttp2_priority_spec_dep_init(pri_spec, dep_stream_id, exclusive); - } else { - pri_spec->pri_type = NGHTTP2_PRIORITY_TYPE_NONE; - } + nghttp2_priority_spec_init(pri_spec, dep_stream_id, weight, exclusive); } int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame, const uint8_t *payload, size_t payloadlen) { - nghttp2_frame_unpack_priority_spec(&frame->pri_spec, frame->hd.flags, - payload, payloadlen); + if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { + nghttp2_frame_unpack_priority_spec(&frame->pri_spec, frame->hd.flags, + payload, payloadlen); + } else { + nghttp2_priority_spec_default_init(&frame->pri_spec); + } + frame->nva = NULL; frame->nvlen = 0; @@ -457,7 +428,7 @@ int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame) nghttp2_frame_pack_priority_spec(buf->last, &frame->pri_spec); - buf->last += nghttp2_frame_priority_len(frame->hd.flags); + buf->last += 5; return 0; } diff --git a/lib/nghttp2_frame.h b/lib/nghttp2_frame.h index 25bfa797..97939d6b 100644 --- a/lib/nghttp2_frame.h +++ b/lib/nghttp2_frame.h @@ -155,7 +155,8 @@ int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, /* * Unpacks HEADERS frame byte sequence into |frame|. This function - * only unapcks bytes that come before name/value header block. + * only unapcks bytes that come before name/value header block and + * after PAD_HIGH and PAD_LOW. * * This function returns 0 if it succeeds or one of the following * negative error codes: diff --git a/lib/nghttp2_priority_spec.c b/lib/nghttp2_priority_spec.c index a3539968..6e6dcb24 100644 --- a/lib/nghttp2_priority_spec.c +++ b/lib/nghttp2_priority_spec.c @@ -24,18 +24,25 @@ */ #include "nghttp2_priority_spec.h" -void nghttp2_priority_spec_group_init(nghttp2_priority_spec *pri_spec, - int32_t pri_group_id, int32_t weight) +void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec, + int32_t stream_id, int32_t weight, + int exclusive) { - pri_spec->pri_type = NGHTTP2_PRIORITY_TYPE_GROUP; - pri_spec->spec.group.pri_group_id = pri_group_id; - pri_spec->spec.group.weight = weight; + pri_spec->stream_id = stream_id; + pri_spec->weight = weight; + pri_spec->exclusive = exclusive != 0; } -void nghttp2_priority_spec_dep_init(nghttp2_priority_spec *pri_spec, - int32_t stream_id, int exclusive) +void nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec) { - pri_spec->pri_type = NGHTTP2_PRIORITY_TYPE_DEP; - pri_spec->spec.dep.stream_id = stream_id; - pri_spec->spec.dep.exclusive = exclusive != 0; + pri_spec->stream_id = 0; + pri_spec->weight = NGHTTP2_DEFAULT_WEIGHT; + pri_spec->exclusive = 0; +} + +int nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec) +{ + /* Ignore exclusive flag */ + return pri_spec->stream_id == 0 && + pri_spec->weight == NGHTTP2_DEFAULT_WEIGHT; } diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 1debddd6..e2323b23 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -147,13 +147,6 @@ nghttp2_stream* nghttp2_session_get_stream_raw(nghttp2_session *session, return (nghttp2_stream*)nghttp2_map_find(&session->streams, stream_id); } -nghttp2_stream_group* nghttp2_session_get_stream_group -(nghttp2_session *session, int32_t pri_group_id) -{ - return (nghttp2_stream_group*)nghttp2_map_find(&session->stream_groups, - pri_group_id); -} - static int nghttp2_outbound_item_compar(const void *lhsx, const void *rhsx) { const nghttp2_outbound_item *lhs, *rhs; @@ -287,11 +280,6 @@ static int nghttp2_session_new(nghttp2_session **session_ptr, goto fail_map; } - rv = nghttp2_map_init(&(*session_ptr)->stream_groups); - if(rv != 0) { - goto fail_group_map; - } - (*session_ptr)->next_seq = 0; (*session_ptr)->remote_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE; @@ -359,8 +347,6 @@ static int nghttp2_session_new(nghttp2_session **session_ptr, return 0; fail_aob_framebuf: - nghttp2_map_free(&(*session_ptr)->stream_groups); - fail_group_map: nghttp2_map_free(&(*session_ptr)->streams); fail_map: nghttp2_hd_inflate_free(&(*session_ptr)->hd_inflater); @@ -432,14 +418,6 @@ static int nghttp2_free_streams(nghttp2_map_entry *entry, void *ptr) return 0; } -static int nghttp2_free_stream_groups(nghttp2_map_entry *entry, void *ptr) -{ - nghttp2_stream_group_free((nghttp2_stream_group*)entry); - free(entry); - - return 0; -} - static void nghttp2_session_ob_pq_free(nghttp2_pq *pq) { while(!nghttp2_pq_empty(pq)) { @@ -463,10 +441,6 @@ void nghttp2_session_del(nghttp2_session *session) nghttp2_map_each_free(&session->streams, nghttp2_free_streams, NULL); nghttp2_map_free(&session->streams); - nghttp2_map_each_free(&session->stream_groups, nghttp2_free_stream_groups, - NULL); - nghttp2_map_free(&session->stream_groups); - nghttp2_session_ob_pq_free(&session->ob_pq); nghttp2_session_ob_pq_free(&session->ob_ss_pq); nghttp2_active_outbound_item_reset(&session->aob); @@ -482,99 +456,63 @@ int nghttp2_session_reprioritize_stream const nghttp2_priority_spec *pri_spec) { int rv; - nghttp2_stream_group *stream_group; - nghttp2_stream_group *old_stream_group; nghttp2_stream *dep_stream; nghttp2_stream *root_stream; - const nghttp2_priority_group *group; - const nghttp2_priority_dep *dep; - switch(pri_spec->pri_type) { - case NGHTTP2_PRIORITY_TYPE_GROUP: - group = &pri_spec->spec.group; - - old_stream_group = stream->stream_group; + if(pri_spec->stream_id == stream->stream_id) { + return nghttp2_session_terminate_session(session, + NGHTTP2_PROTOCOL_ERROR); + } + if(pri_spec->stream_id == 0) { nghttp2_stream_dep_remove_subtree(stream); - stream_group = nghttp2_session_get_stream_group(session, - group->pri_group_id); + /* We have to update weight after removing stream from tree */ + stream->weight = pri_spec->weight; - if(stream_group == NULL) { - stream_group = nghttp2_session_open_stream_group(session, - group->pri_group_id, - group->weight); + rv = nghttp2_stream_dep_make_root(stream, &session->ob_pq); - if(stream_group == NULL) { - return NGHTTP2_ERR_NOMEM; - } - } else { - stream_group->weight = group->weight; - } + return rv; + } - rv = nghttp2_stream_dep_make_root(stream_group, stream, &session->ob_pq); - - if(rv != 0) { - return rv; - } - - nghttp2_session_close_stream_group_if_empty(session, old_stream_group); + dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id); + if(dep_stream == NULL) { return 0; + } - case NGHTTP2_PRIORITY_TYPE_DEP: - dep = &pri_spec->spec.dep; - - if(dep->stream_id == stream->stream_id || dep->stream_id == 0) { - return nghttp2_session_terminate_session(session, - NGHTTP2_PROTOCOL_ERROR); - } - - old_stream_group = stream->stream_group; - - dep_stream = nghttp2_session_get_stream_raw(session, dep->stream_id); - - if(dep_stream == NULL) { - return 0; - } - - /* Ignore priority request if resultant tree has cycle */ - if(nghttp2_stream_dep_subtree_find(stream, dep_stream)) { - DEBUGF(fprintf(stderr, - "stream: future cycle detected, dep_stream(%p)=%d " - "stream(%p)=%d\n", - dep_stream, dep_stream->stream_id, - stream, stream->stream_id)); - return 0; - } - - nghttp2_stream_dep_remove_subtree(stream); - - root_stream = nghttp2_stream_get_dep_root(dep_stream); - - if(root_stream->num_substreams + stream->num_substreams > - NGHTTP2_MAX_DEP_TREE_LENGTH) { - rv = nghttp2_stream_dep_make_root(dep_stream->stream_group, stream, - &session->ob_pq); - } else { - if(dep->exclusive) { - rv = nghttp2_stream_dep_insert_subtree(dep_stream, stream, - &session->ob_pq); - } else { - rv = nghttp2_stream_dep_add_subtree(dep_stream, stream, - &session->ob_pq); - } - } - - if(rv != 0) { - return rv; - } - - nghttp2_session_close_stream_group_if_empty(session, old_stream_group); - + /* Ignore priority request if resultant tree has cycle */ + if(nghttp2_stream_dep_subtree_find(stream, dep_stream)) { + DEBUGF(fprintf(stderr, + "stream: future cycle detected, dep_stream(%p)=%d " + "stream(%p)=%d\n", + dep_stream, dep_stream->stream_id, + stream, stream->stream_id)); return 0; - default: - assert(0); + } + + nghttp2_stream_dep_remove_subtree(stream); + + /* 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) { + rv = nghttp2_stream_dep_make_root(stream, &session->ob_pq); + } else { + if(pri_spec->exclusive) { + rv = nghttp2_stream_dep_insert_subtree(dep_stream, stream, + &session->ob_pq); + } else { + rv = nghttp2_stream_dep_add_subtree(dep_stream, stream, + &session->ob_pq); + } + } + + if(rv != 0) { + return rv; } return 0; @@ -615,24 +553,30 @@ int nghttp2_session_add_frame(nghttp2_session *session, if(frame->hd.stream_id == -1) { /* Initial HEADERS, which will open stream */ - if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY_GROUP) { - item->weight = frame->headers.pri_spec.spec.group.weight; - } else if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY_DEPENDENCY) { - dep_stream = nghttp2_session_get_stream - (session, frame->headers.pri_spec.spec.dep.stream_id); - if(dep_stream) { - item->weight = dep_stream->stream_group->weight; + /* TODO If we always frame.headers.pri_spec filled in, we + don't have to check flags */ + if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { + if(frame->headers.pri_spec.stream_id == 0) { + item->weight = frame->headers.pri_spec.weight; } else { - item->weight = NGHTTP2_DEFAULT_WEIGHT; + dep_stream = nghttp2_session_get_stream + (session, frame->headers.pri_spec.stream_id); + + if(dep_stream) { + item->weight = nghttp2_stream_dep_distributed_effective_weight + (dep_stream, frame->headers.pri_spec.weight); + } else { + item->weight = frame->headers.pri_spec.weight; + } } } else { item->weight = NGHTTP2_DEFAULT_WEIGHT; } } else if(stream) { - /* Otherwise, the frame must have stream ID. We use its - priority value. */ - item->weight = stream->stream_group->weight; + /* Otherwise, the frame must have stream ID. We use its + effective_weight. */ + item->weight = stream->effective_weight; } break; case NGHTTP2_PRIORITY: @@ -656,7 +600,7 @@ int nghttp2_session_add_frame(nghttp2_session *session, case NGHTTP2_PUSH_PROMISE: /* Use priority of associated stream */ if(stream) { - item->weight = stream->stream_group->weight; + item->weight = stream->effective_weight; } break; @@ -699,7 +643,7 @@ int nghttp2_session_add_frame(nghttp2_session *session, if(stream->data_item) { rv = NGHTTP2_ERR_DATA_EXIST; } else { - item->weight = nghttp2_stream_group_shared_wait(stream->stream_group); + item->weight = stream->effective_weight; rv = nghttp2_stream_attach_data(stream, item, &session->ob_pq); } @@ -756,57 +700,18 @@ nghttp2_stream* nghttp2_session_open_stream(nghttp2_session *session, nghttp2_stream *stream; nghttp2_stream *dep_stream; nghttp2_stream *root_stream; - int32_t pri_group_id; - int32_t weight; - nghttp2_stream_group *stream_group; - - dep_stream = NULL; if(session->server && !nghttp2_session_is_my_stream_id(session, stream_id)) { nghttp2_session_adjust_closed_stream(session, 1); } - switch(pri_spec->pri_type) { - case NGHTTP2_PRIORITY_TYPE_GROUP: - pri_group_id = pri_spec->spec.group.pri_group_id; - weight = pri_spec->spec.group.weight; - - break; - case NGHTTP2_PRIORITY_TYPE_DEP: - dep_stream = nghttp2_session_get_stream_raw(session, - pri_spec->spec.dep.stream_id); - - if(dep_stream) { - pri_group_id = dep_stream->stream_group->pri_group_id; - weight = dep_stream->stream_group->weight; - } else { - pri_group_id = stream_id; - weight = NGHTTP2_DEFAULT_WEIGHT; - } - - break; - default: - pri_group_id = stream_id; - weight = NGHTTP2_DEFAULT_WEIGHT; - }; - - stream_group = nghttp2_session_get_stream_group(session, pri_group_id); - - if(stream_group == NULL) { - stream_group = nghttp2_session_open_stream_group(session, pri_group_id, - weight); - - if(stream_group == NULL) { - return NULL; - } - } - stream = malloc(sizeof(nghttp2_stream)); if(stream == NULL) { return NULL; } nghttp2_stream_init(stream, stream_id, flags, initial_state, + pri_spec->weight, session->remote_settings [NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE], session->local_settings @@ -819,8 +724,6 @@ nghttp2_stream* nghttp2_session_open_stream(nghttp2_session *session, return NULL; } - nghttp2_stream_group_add_stream(stream_group, stream); - if(initial_state == NGHTTP2_STREAM_RESERVED) { if(nghttp2_session_is_my_stream_id(session, stream_id)) { /* half closed (remote) */ @@ -839,14 +742,13 @@ nghttp2_stream* nghttp2_session_open_stream(nghttp2_session *session, } } - /* Possibly update weight of priority group */ - stream_group->weight = weight; - /* We don't have to track dependency of received reserved stream */ if(stream->shut_flags & NGHTTP2_SHUT_WR) { return stream; } + dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id); + if(!dep_stream) { return stream; } @@ -858,7 +760,7 @@ nghttp2_stream* nghttp2_session_open_stream(nghttp2_session *session, root_stream = nghttp2_stream_get_dep_root(dep_stream); if(root_stream->num_substreams < NGHTTP2_MAX_DEP_TREE_LENGTH) { - if(pri_spec->spec.dep.exclusive) { + if(pri_spec->exclusive) { nghttp2_stream_dep_insert(dep_stream, stream); } else { nghttp2_stream_dep_add(dep_stream, stream); @@ -944,18 +846,11 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id, void nghttp2_session_destroy_stream(nghttp2_session *session, nghttp2_stream *stream) { - nghttp2_stream_group *stream_group; - DEBUGF(fprintf(stderr, "stream: destroy closed stream(%p)=%d\n", stream, stream->stream_id)); nghttp2_stream_dep_remove(stream); - stream_group = stream->stream_group; - - nghttp2_stream_group_remove_stream(stream_group, stream); - nghttp2_session_close_stream_group_if_empty(session, stream_group); - nghttp2_map_remove(&session->streams, stream->stream_id); nghttp2_stream_free(stream); free(stream); @@ -1537,15 +1432,6 @@ static int nghttp2_session_prep_frame(nghttp2_session *session, frame->hd.stream_id = session->next_stream_id; session->next_stream_id += 2; - if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY_GROUP) { - if(frame->headers.pri_spec.spec.group.pri_group_id == -1) { - /* We now know stream_id. Assign stream_id to - pri_group_id if it is -1. */ - frame->headers.pri_spec.spec.group.pri_group_id = - frame->hd.stream_id; - } - } - } else if(nghttp2_session_predicate_push_response_headers_send (session, frame->hd.stream_id) == 0) { frame->headers.cat = NGHTTP2_HCAT_PUSH_RESPONSE; @@ -1665,7 +1551,8 @@ static int nghttp2_session_prep_frame(nghttp2_session *session, /* TODO It is unclear reserved stream dpeneds on associated stream with or without exclusive flag set */ - nghttp2_priority_spec_dep_init(&pri_spec, stream->stream_id, 0); + nghttp2_priority_spec_init(&pri_spec, stream->stream_id, + NGHTTP2_DEFAULT_WEIGHT, 0); if(!nghttp2_session_open_stream (session, frame->push_promise.promised_stream_id, @@ -2159,8 +2046,7 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session) assert(stream); next_item = nghttp2_session_get_next_ob_item(session); - outbound_item_cycle_weight - (aob->item, nghttp2_stream_group_shared_wait(stream->stream_group)); + outbound_item_cycle_weight(aob->item, stream->effective_weight); /* If priority of this stream is higher or equal to other stream waiting at the top of the queue, we continue to send this @@ -2855,9 +2741,7 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session, (session, frame, NGHTTP2_ENHANCE_YOUR_CALM); } - if(frame->headers.pri_spec.pri_type == NGHTTP2_PRIORITY_TYPE_DEP && - (frame->headers.pri_spec.spec.dep.stream_id == frame->hd.stream_id || - frame->headers.pri_spec.spec.dep.stream_id == 0)) { + if(frame->headers.pri_spec.stream_id == frame->hd.stream_id) { return nghttp2_session_inflate_handle_invalid_connection (session, frame, NGHTTP2_PROTOCOL_ERROR); } @@ -3508,7 +3392,8 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session, /* TODO It is unclear reserved stream dpeneds on associated stream with or without exclusive flag set */ - nghttp2_priority_spec_dep_init(&pri_spec, stream->stream_id, 0); + nghttp2_priority_spec_init(&pri_spec, stream->stream_id, + NGHTTP2_DEFAULT_WEIGHT, 0); promised_stream = nghttp2_session_open_stream (session, @@ -4229,15 +4114,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PAD_LOW | NGHTTP2_FLAG_PAD_HIGH | - NGHTTP2_FLAG_PRIORITY_GROUP | - NGHTTP2_FLAG_PRIORITY_DEPENDENCY); + NGHTTP2_FLAG_PRIORITY); rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); - if(rv < 0 || - (iframe->frame.hd.flags & (NGHTTP2_FLAG_PRIORITY_GROUP | - NGHTTP2_FLAG_PRIORITY_DEPENDENCY)) == - (NGHTTP2_FLAG_PRIORITY_GROUP | NGHTTP2_FLAG_PRIORITY_DEPENDENCY)) { - + if(rv < 0) { busy = 1; iframe->state = NGHTTP2_IB_IGN_PAYLOAD; @@ -4287,34 +4167,11 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, break; case NGHTTP2_PRIORITY: - pri_fieldlen = 0; - DEBUGF(fprintf(stderr, "recv: PRIORITY\n")); - iframe->frame.hd.flags &= (NGHTTP2_FLAG_PRIORITY_GROUP | - NGHTTP2_FLAG_PRIORITY_DEPENDENCY); + iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; - pri_fieldlen = nghttp2_frame_priority_len(iframe->frame.hd.flags); - - if(iframe->frame.hd.flags == (NGHTTP2_FLAG_PRIORITY_GROUP | - NGHTTP2_FLAG_PRIORITY_DEPENDENCY) || - pri_fieldlen == 0) { - - busy = 1; - - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; - - rv = nghttp2_session_terminate_session(session, - NGHTTP2_PROTOCOL_ERROR); - - if(nghttp2_is_fatal(rv)) { - return rv; - } - - break; - } - - if(pri_fieldlen != iframe->payloadleft) { + if(iframe->payloadleft != 5) { busy = 1; iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; @@ -4324,7 +4181,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, iframe->state = NGHTTP2_IB_READ_NBYTE; - inbound_frame_set_mark(iframe, pri_fieldlen); + inbound_frame_set_mark(iframe, 5); break; case NGHTTP2_RST_STREAM: @@ -4535,6 +4392,9 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, iframe->state = NGHTTP2_IB_READ_NBYTE; inbound_frame_set_mark(iframe, pri_fieldlen); break; + } else { + /* Truncate buffers used for padding spec */ + inbound_frame_set_mark(iframe, 0); } } @@ -5653,7 +5513,7 @@ int nghttp2_session_upgrade(nghttp2_session *session, return rv; } - nghttp2_priority_spec_group_init(&pri_spec, 1, NGHTTP2_DEFAULT_WEIGHT); + nghttp2_priority_spec_default_init(&pri_spec); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, &pri_spec, NGHTTP2_STREAM_OPENING, @@ -5672,41 +5532,3 @@ int nghttp2_session_upgrade(nghttp2_session *session, } return 0; } - -nghttp2_stream_group* nghttp2_session_open_stream_group -(nghttp2_session *session, int32_t pri_group_id, int32_t weight) -{ - int rv; - nghttp2_stream_group *stream_group; - - stream_group = malloc(sizeof(nghttp2_stream_group)); - - if(stream_group == NULL) { - return NULL; - } - - nghttp2_stream_group_init(stream_group, pri_group_id, weight); - - rv = nghttp2_map_insert(&session->stream_groups, &stream_group->map_entry); - - if(rv != 0) { - free(stream_group); - - return NULL; - } - - return stream_group; -} - -void nghttp2_session_close_stream_group_if_empty -(nghttp2_session *session, nghttp2_stream_group *stream_group) -{ - if(stream_group->num_streams == 0) { - DEBUGF(fprintf(stderr, "stream: stream_group(%p)=%d closed\n", - stream_group, stream_group->pri_group_id)); - - nghttp2_map_remove(&session->stream_groups, stream_group->pri_group_id); - nghttp2_stream_group_free(stream_group); - free(stream_group); - } -} diff --git a/lib/nghttp2_session.h b/lib/nghttp2_session.h index b398dc3b..21f728e5 100644 --- a/lib/nghttp2_session.h +++ b/lib/nghttp2_session.h @@ -117,7 +117,6 @@ typedef enum { struct nghttp2_session { nghttp2_map /* */ streams; - nghttp2_map /* */ stream_groups; /* Queue for outbound frames other than stream-creating HEADERS */ nghttp2_pq /* */ ob_pq; /* Queue for outbound stream-creating HEADERS frame */ @@ -603,14 +602,6 @@ nghttp2_stream* nghttp2_session_get_stream(nghttp2_session *session, nghttp2_stream* nghttp2_session_get_stream_raw(nghttp2_session *session, int32_t stream_id); -/* - * Returns nghttp2_stream_group* object whose priority group ID is - * |pri_group_id|. It could be NULL if such priority group does not - * exist. - */ -nghttp2_stream_group* nghttp2_session_get_stream_group -(nghttp2_session *session, int32_t pri_group_id); - /* * Packs DATA frame |frame| in wire frame format and stores it in * |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| @@ -698,19 +689,4 @@ int nghttp2_session_reprioritize_stream (nghttp2_session *session, nghttp2_stream *stream, const nghttp2_priority_spec *pri_spec); -/* - * Creates new priority group using given values. - * - * This function returns created priority group if it succeeds, or - * NULL. - */ -nghttp2_stream_group* nghttp2_session_open_stream_group -(nghttp2_session *session, int32_t pri_group_id, int32_t weight); - -/* - * Closes priority group if it does not include any streams. - */ -void nghttp2_session_close_stream_group_if_empty -(nghttp2_session *session, nghttp2_stream_group *stream_group); - #endif /* NGHTTP2_SESSION_H */ diff --git a/lib/nghttp2_stream.c b/lib/nghttp2_stream.c index c559a833..aafa35d4 100644 --- a/lib/nghttp2_stream.c +++ b/lib/nghttp2_stream.c @@ -32,6 +32,7 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, uint8_t flags, nghttp2_stream_state initial_state, + int32_t weight, int32_t remote_initial_window_size, int32_t local_initial_window_size, void *stream_user_data) @@ -55,10 +56,11 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, stream->closed_next = NULL; - stream->stream_group = NULL; stream->dpri = NGHTTP2_STREAM_DPRI_NO_DATA; stream->num_substreams = 1; - stream->num_subtop = 0; + stream->weight = weight; + stream->effective_weight = stream->weight; + stream->sum_dep_weight = 0; } void nghttp2_stream_free(nghttp2_stream *stream) @@ -79,15 +81,12 @@ void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag) static int stream_push_data(nghttp2_stream *stream, nghttp2_pq *pq) { int rv; - ssize_t weight; assert(stream->data_item); assert(stream->data_item->queued == 0); - weight = nghttp2_stream_group_shared_wait(stream->stream_group); - - if(stream->data_item->weight > weight) { - stream->data_item->weight = weight; + if(stream->data_item->weight > stream->effective_weight) { + stream->data_item->weight = stream->effective_weight; } rv = nghttp2_pq_push(pq, stream->data_item); @@ -129,39 +128,39 @@ static nghttp2_stream* stream_update_dep_length(nghttp2_stream *stream, return stream; } -static nghttp2_stream* stream_update_dep_both_length(nghttp2_stream *stream, - ssize_t delta_stream, - ssize_t delta_top) +int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream, + int32_t weight) { - stream->num_substreams += delta_stream; - stream->num_subtop += delta_top; + weight = stream->weight * weight / stream->sum_dep_weight; - stream = stream_first_sib(stream); - - if(stream->dep_prev) { - return stream_update_dep_both_length(stream->dep_prev, delta_stream, - delta_top); - } - - return stream; + return nghttp2_max(1, weight); } -static void stream_update_dep_set_rest_stream_group -(nghttp2_stream *stream, nghttp2_stream_group *stream_group) +int32_t nghttp2_stream_dep_distributed_effective_weight +(nghttp2_stream *stream, int32_t weight) { - if(stream == NULL) { - return; + weight = stream->effective_weight * weight / stream->sum_dep_weight; + + return nghttp2_max(1, weight); +} + +/* Updates effective_weight of descendant streams in subtree of + |stream|. We assume that stream->effective_weight is already set + right. */ +static void stream_update_dep_effective_weight(nghttp2_stream *stream) +{ + nghttp2_stream *si; + + DEBUGF(fprintf(stderr, "stream: update_dep_effective_weight " + "stream(%p)=%d, weight=%d\n", + stream, stream->stream_id, stream->weight)); + + for(si = stream->dep_next; si; si = si->sib_next) { + si->effective_weight = nghttp2_stream_dep_distributed_effective_weight + (stream, si->weight); + + stream_update_dep_effective_weight(si); } - - nghttp2_stream_group_remove_stream(stream->stream_group, stream); - nghttp2_stream_group_add_stream(stream_group, stream); - - if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) { - stream->dpri = NGHTTP2_STREAM_DPRI_REST; - } - - stream_update_dep_set_rest_stream_group(stream->sib_next, stream_group); - stream_update_dep_set_rest_stream_group(stream->dep_next, stream_group); } static void stream_update_dep_set_rest(nghttp2_stream *stream) @@ -174,8 +173,6 @@ static void stream_update_dep_set_rest(nghttp2_stream *stream) return; } - stream->num_subtop = 0; - if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) { stream->dpri = NGHTTP2_STREAM_DPRI_REST; @@ -192,18 +189,15 @@ static void stream_update_dep_set_rest(nghttp2_stream *stream) * Performs dfs starting |stream|, search stream which can become * NGHTTP2_STREAM_DPRI_TOP and queues its data_item. * - * This function returns the number of stream marked as - * NGHTTP2_STREAM_DPRI_TOP (including already marked as such) if it - * succeeds, or one of the following negative error codes: + * This function returns 0 if it succeeds, or one of the following + * negative error codes: * * NGHTTP2_ERR_NOMEM * Out of memory. */ -static ssize_t stream_update_dep_set_top(nghttp2_stream *stream, - nghttp2_pq *pq) +static int stream_update_dep_set_top(nghttp2_stream *stream, nghttp2_pq *pq) { - ssize_t rv; - ssize_t num_top; + int rv; if(stream == NULL) { return 0; @@ -212,13 +206,11 @@ static ssize_t stream_update_dep_set_top(nghttp2_stream *stream, if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) { rv = stream_update_dep_set_top(stream->sib_next, pq); - if(rv < 0) { + if(rv != 0) { return rv; } - stream->num_subtop = 1; - - return stream->num_subtop + rv; + return 0; } if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) { @@ -238,42 +230,35 @@ static ssize_t stream_update_dep_set_top(nghttp2_stream *stream, rv = stream_update_dep_set_top(stream->sib_next, pq); - if(rv < 0) { + if(rv != 0) { return rv; } - stream->num_subtop = 1; - - return stream->num_subtop + rv; + return 0; } assert(stream->dpri == NGHTTP2_STREAM_DPRI_NO_DATA); rv = stream_update_dep_set_top(stream->sib_next, pq); - if(rv < 0) { + if(rv != 0) { return rv; } - num_top = rv; - rv = stream_update_dep_set_top(stream->dep_next, pq); - if(rv < 0) { + if(rv != 0) { return rv; } - stream->num_subtop = rv; - - return stream->num_subtop + num_top; + return 0; } -static ssize_t stream_update_dep_on_attach_data(nghttp2_stream *stream, - nghttp2_pq *pq) +static int stream_update_dep_on_attach_data(nghttp2_stream *stream, + nghttp2_pq *pq) { - ssize_t rv; + int rv; nghttp2_stream *root_stream; - ssize_t old_num_subtop; stream->dpri = NGHTTP2_STREAM_DPRI_REST; @@ -283,26 +268,20 @@ static ssize_t stream_update_dep_on_attach_data(nghttp2_stream *stream, DEBUGF(fprintf(stderr, "root=%p, stream=%p\n", root_stream, stream)); - old_num_subtop = root_stream->num_subtop; - rv = stream_update_dep_set_top(root_stream, pq); - if(rv < 0) { + if(rv != 0) { return rv; } - nghttp2_stream_group_update_num_top - (root_stream->stream_group, root_stream->num_subtop - old_num_subtop); - return 0; } static int stream_update_dep_on_detach_data(nghttp2_stream *stream, nghttp2_pq *pq) { - ssize_t rv; + int rv; nghttp2_stream *root_stream; - ssize_t old_num_subtop; if(stream->dpri != NGHTTP2_STREAM_DPRI_TOP) { stream->dpri = NGHTTP2_STREAM_DPRI_NO_DATA; @@ -314,17 +293,12 @@ static int stream_update_dep_on_detach_data(nghttp2_stream *stream, root_stream = nghttp2_stream_get_dep_root(stream); - old_num_subtop = root_stream->num_subtop; - rv = stream_update_dep_set_top(root_stream, pq); - if(rv < 0) { + if(rv != 0) { return rv; } - nghttp2_stream_group_update_num_top - (root_stream->stream_group, root_stream->num_subtop - old_num_subtop); - return 0; } @@ -483,6 +457,9 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, dep_stream, dep_stream->stream_id, stream, stream->stream_id)); + stream->sum_dep_weight = dep_stream->sum_dep_weight; + dep_stream->sum_dep_weight = stream->weight; + if(dep_stream->dep_next) { for(si = dep_stream->dep_next; si; si = si->sib_next) { stream->num_substreams += si->num_substreams; @@ -496,6 +473,7 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, stream->dep_prev = dep_stream; stream_update_dep_length(dep_stream, 1); + stream_update_dep_effective_weight(dep_stream); } void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, @@ -512,29 +490,45 @@ void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, stream_update_dep_length(dep_stream, 1); + dep_stream->sum_dep_weight += stream->weight; + if(dep_stream->dep_next == NULL) { dep_stream->dep_next = stream; stream->dep_prev = dep_stream; - - return; + } else { + last_sib = stream_last_sib(dep_stream->dep_next); + last_sib->sib_next = stream; + stream->sib_prev = last_sib; } - last_sib = stream_last_sib(dep_stream->dep_next); - last_sib->sib_next = stream; - stream->sib_prev = last_sib; + stream_update_dep_effective_weight(dep_stream); } void nghttp2_stream_dep_remove(nghttp2_stream *stream) { - nghttp2_stream *prev, *next, *dep_next; + nghttp2_stream *prev, *next, *dep_next, *dep_prev, *si; + int32_t sum_dep_weight_delta; DEBUGF(fprintf(stderr, "stream: dep_remove stream(%p)=%d\n", stream, stream->stream_id)); + /* Distribute weight of |stream| to direct descendants */ + sum_dep_weight_delta = -stream->weight; + + for(si = stream->dep_next; si; si = si->sib_next) { + si->weight = nghttp2_stream_dep_distributed_weight(stream, si->weight); + + sum_dep_weight_delta += si->weight; + } + prev = stream_first_sib(stream); - if(prev->dep_prev) { - stream_update_dep_length(prev->dep_prev, -1); + dep_prev = prev->dep_prev; + + if(dep_prev) { + stream_update_dep_length(dep_prev, -1); + + dep_prev->sum_dep_weight += sum_dep_weight_delta; } if(stream->sib_prev) { @@ -574,8 +568,6 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream) dep_next = NULL; } } else { - nghttp2_stream *si; - dep_next = NULL; /* stream is a root of tree. Removing stream makes its @@ -588,6 +580,9 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream) si->sib_prev = NULL; si->sib_next = NULL; + /* We already distributed weight of |stream| to this. */ + si->effective_weight = si->weight; + si = next; } } @@ -600,7 +595,13 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream) next->sib_prev = prev; } + if(dep_prev) { + stream_update_dep_effective_weight(dep_prev); + } + stream->num_substreams = 1; + stream->sum_dep_weight = 0; + stream->dep_prev = NULL; stream->dep_next = NULL; stream->sib_prev = NULL; @@ -614,10 +615,8 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, nghttp2_stream *last_sib; nghttp2_stream *dep_next; nghttp2_stream *root_stream; - nghttp2_stream *si; size_t delta_substreams; - ssize_t old_num_subtop; - ssize_t rv; + int rv; DEBUGF(fprintf(stderr, "stream: dep_insert_subtree dep_stream(%p)=%d " "stream(%p)=%d\n", @@ -626,17 +625,16 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, delta_substreams = stream->num_substreams; - nghttp2_stream_group_update_num_top - (stream->stream_group, -stream->num_subtop); - - stream_update_dep_set_rest_stream_group(stream, dep_stream->stream_group); + stream_update_dep_set_rest(stream); if(dep_stream->dep_next) { - dep_next = dep_stream->dep_next; + /* dep_stream->num_substreams includes dep_stream itself */ + stream->num_substreams += dep_stream->num_substreams - 1; - for(si = dep_stream->dep_next; si; si = si->sib_next) { - stream->num_substreams += si->num_substreams; - } + stream->sum_dep_weight += dep_stream->sum_dep_weight; + dep_stream->sum_dep_weight = stream->weight; + + dep_next = dep_stream->dep_next; stream_update_dep_set_rest(dep_next); @@ -657,21 +655,21 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, } else { dep_stream->dep_next = stream; stream->dep_prev = dep_stream; + + assert(dep_stream->sum_dep_weight == 0); + dep_stream->sum_dep_weight = stream->weight; } + stream_update_dep_effective_weight(dep_stream); + root_stream = stream_update_dep_length(dep_stream, delta_substreams); - old_num_subtop = root_stream->num_subtop; - rv = stream_update_dep_set_top(root_stream, pq); - if(rv < 0) { + if(rv != 0) { return rv; } - nghttp2_stream_group_update_num_top - (root_stream->stream_group, root_stream->num_subtop - old_num_subtop); - return 0; } @@ -681,20 +679,18 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, { nghttp2_stream *last_sib; nghttp2_stream *root_stream; - ssize_t old_num_subtop; - ssize_t rv; + int rv; DEBUGF(fprintf(stderr, "stream: dep_add_subtree dep_stream(%p)=%d " "stream(%p)=%d\n", dep_stream, dep_stream->stream_id, stream, stream->stream_id)); - nghttp2_stream_group_update_num_top - (stream->stream_group, -stream->num_subtop); - - stream_update_dep_set_rest_stream_group(stream, dep_stream->stream_group); + stream_update_dep_set_rest(stream); if(dep_stream->dep_next) { + dep_stream->sum_dep_weight += stream->weight; + last_sib = stream_last_sib(dep_stream->dep_next); last_sib->sib_next = stream; @@ -702,33 +698,31 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, } else { dep_stream->dep_next = stream; stream->dep_prev = dep_stream; + + assert(dep_stream->sum_dep_weight == 0); + dep_stream->sum_dep_weight = stream->weight; } + stream_update_dep_effective_weight(dep_stream); + root_stream = stream_update_dep_length(dep_stream, stream->num_substreams); - old_num_subtop = root_stream->num_subtop; - rv = stream_update_dep_set_top(root_stream, pq); - if(rv < 0) { + if(rv != 0) { return rv; } - nghttp2_stream_group_update_num_top - (root_stream->stream_group, root_stream->num_subtop - old_num_subtop); - return 0; } void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) { - nghttp2_stream *prev, *next; + nghttp2_stream *prev, *next, *dep_prev; DEBUGF(fprintf(stderr, "stream: dep_remove_subtree stream(%p)=%d\n", stream, stream->stream_id)); - /* Removing subtree does not change stream_group->num_top */ - if(stream->sib_prev) { prev = stream->sib_prev; @@ -738,24 +732,31 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) } prev = stream_first_sib(prev); - if(prev->dep_prev) { - stream_update_dep_both_length(prev->dep_prev, -stream->num_substreams, - -stream->num_subtop); - } + + dep_prev = prev->dep_prev; + } else if(stream->dep_prev) { - prev = stream->dep_prev; + dep_prev = stream->dep_prev; next = stream->sib_next; - prev->dep_next = next; + dep_prev->dep_next = next; if(next) { - next->dep_prev = prev; + next->dep_prev = dep_prev; next->sib_prev = NULL; } - stream_update_dep_both_length(prev, -stream->num_substreams, - -stream->num_subtop); + } else { + dep_prev = NULL; + } + + if(dep_prev) { + dep_prev->sum_dep_weight -= stream->weight; + + stream_update_dep_effective_weight(dep_prev); + + stream_update_dep_length(dep_prev, -stream->num_substreams); } stream->sib_prev = NULL; @@ -763,94 +764,24 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) stream->dep_prev = NULL; } -int nghttp2_stream_dep_make_root(nghttp2_stream_group *stream_group, - nghttp2_stream *stream, - nghttp2_pq *pq) +int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq) { - ssize_t rv; + int rv; - DEBUGF(fprintf(stderr, "stream: dep_make_root new_stream_group(%p)=%d, " - "old_stream_group(%p)=%d, stream(%p)=%d\n", - stream_group, stream_group->pri_group_id, - stream->stream_group, stream->stream_group->pri_group_id, + DEBUGF(fprintf(stderr, "stream: dep_make_root stream(%p)=%d\n", stream, stream->stream_id)); - /* First update num_top of old stream_group */ - nghttp2_stream_group_update_num_top - (stream->stream_group, -stream->num_subtop); + stream_update_dep_set_rest(stream); - stream_update_dep_set_rest_stream_group(stream, stream_group); + stream->effective_weight = stream->weight; + + stream_update_dep_effective_weight(stream); rv = stream_update_dep_set_top(stream, pq); - if(rv < 0) { + if(rv != 0) { return rv; } - nghttp2_stream_group_update_num_top(stream_group, stream->num_subtop); - return 0; } - -void nghttp2_stream_group_init(nghttp2_stream_group *stream_group, - int32_t pri_group_id, - int32_t weight) -{ - nghttp2_map_entry_init(&stream_group->map_entry, pri_group_id); - - stream_group->num_streams = 0; - stream_group->num_top = 0; - stream_group->pri_group_id = pri_group_id; - stream_group->weight = weight; -} - -void nghttp2_stream_group_free(nghttp2_stream_group *stream_group) -{} - -void nghttp2_stream_group_add_stream(nghttp2_stream_group *stream_group, - nghttp2_stream *stream) -{ - DEBUGF(fprintf(stderr, "stream_group: stream_group(%p)=%d " - "add stream(%p)=%d\n", - stream_group, stream_group->pri_group_id, - stream, stream->stream_id)); - - stream->stream_group = stream_group; - - ++stream_group->num_streams; -} - -void nghttp2_stream_group_remove_stream(nghttp2_stream_group *stream_group, - nghttp2_stream *stream) -{ - DEBUGF(fprintf(stderr, "stream_group: stream_group(%p)=%d " - "remove stream(%p)=%d\n", - stream_group, stream_group->pri_group_id, - stream, stream->stream_id)); - - stream->stream_group = NULL; - - --stream_group->num_streams; -} - -void nghttp2_stream_group_update_num_top(nghttp2_stream_group *stream_group, - ssize_t delta) -{ - DEBUGF(fprintf(stderr, "stream_group: stream_group(%p)=%d " - "update num_top current=%zd, delta=%zd, after=%zd\n", - stream_group, stream_group->pri_group_id, - stream_group->num_top, delta, stream_group->num_top + delta)); - - stream_group->num_top += delta; - - assert(stream_group->num_top >= 0); -} - -size_t nghttp2_stream_group_shared_wait(nghttp2_stream_group *stream_group) -{ - if(stream_group->num_top == 0) { - return 1; - } - - return nghttp2_max(1, stream_group->weight / stream_group->num_top); -} diff --git a/lib/nghttp2_stream.h b/lib/nghttp2_stream.h index eb30c2fd..05a4f52c 100644 --- a/lib/nghttp2_stream.h +++ b/lib/nghttp2_stream.h @@ -102,10 +102,6 @@ typedef enum { NGHTTP2_STREAM_DPRI_REST = 0x04 } nghttp2_stream_dpri; -struct nghttp2_stream_group; - -typedef struct nghttp2_stream_group nghttp2_stream_group; - struct nghttp2_stream; typedef struct nghttp2_stream nghttp2_stream; @@ -133,16 +129,11 @@ struct nghttp2_stream { nghttp2_outbound_item *data_item; /* stream ID */ int32_t stream_id; - /* priority group this stream belongs to */ - nghttp2_stream_group *stream_group; /* categorized priority of this stream. Only stream bearing NGHTTP2_STREAM_DPRI_TOP can send DATA frame. */ nghttp2_stream_dpri dpri; /* the number of streams in subtree */ size_t num_substreams; - /* the number of streams marked as NGHTTP2_STREAM_DPRI_TOP in - subtree */ - ssize_t num_subtop; /* Current remote window size. This value is computed against the current initial window size of remote endpoint. */ int32_t remote_window_size; @@ -157,6 +148,12 @@ struct nghttp2_stream { NGHTTP2_INITIAL_WINDOW_SIZE and could be increased/decreased by submitting WINDOW_UPDATE. See nghttp2_submit_window_update(). */ int32_t local_window_size; + /* weight of this stream */ + int32_t weight; + /* effective weight of this stream in belonging dependency tree */ + int32_t effective_weight; + /* sum of weight (not effective_weight) of direct descendants */ + int32_t sum_dep_weight; nghttp2_stream_state state; /* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */ uint8_t flags; @@ -167,6 +164,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, int32_t remote_initial_window_size, int32_t local_initial_window_size, void *stream_user_data); @@ -259,12 +257,30 @@ nghttp2_stream* nghttp2_stream_get_dep_root(nghttp2_stream *stream); int nghttp2_stream_dep_subtree_find(nghttp2_stream *stream, nghttp2_stream *target); +/* + * Computes distributed weight of a stream of the |weight| under the + * |stream| if |stream| is removed from a dependency tree. The result + * is computed using stream->weight rather than + * stream->effective_weight. + */ +int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream, + int32_t weight); + +/* + * Computes effective weight of a stream of the |weight| under the + * |stream|. The result is computed using stream->effective_weight + * rather than stream->weight. This function is used to determine + * weight in dependency tree. + */ +int32_t nghttp2_stream_dep_distributed_effective_weight +(nghttp2_stream *stream, int32_t weight); + /* * Makes the |stream| depend on the |dep_stream|. This dependency is * exclusive. All existing direct descendants of |dep_stream| become * the descendants of the |stream|. This function assumes * |stream->data| is NULL and no dpri members are changed in this - * dependency tree. It also does not change stream->stream_group. + * dependency tree. */ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, nghttp2_stream *stream); @@ -272,8 +288,7 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, /* * Makes the |stream| depend on the |dep_stream|. This dependency is * not exclusive. This function assumes |stream->data| is NULL and no - * dpri members are changed in this dependency tree. It also does not - * change stream->stream_group. + * dpri members are changed in this dependency tree. */ void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, nghttp2_stream *stream); @@ -342,8 +357,8 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, /* * Removes subtree whose root stream is |stream|. Removing subtree - * does not change dpri values and removed subtree is still in the - * same stream_group. + * does not change dpri values. The effective_weight of streams in + * removed subtree is not updated. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -354,8 +369,8 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream); /* - * Makes the |stream| as root for |stream_group|. Updates dpri - * members in this dependency tree. + * 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: @@ -363,53 +378,6 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream); * NGHTTP2_ERR_NOMEM * Out of memory */ -int nghttp2_stream_dep_make_root(nghttp2_stream_group *stream_group, - nghttp2_stream *stream, - nghttp2_pq *pq); - -/* - * Priority group of streams. - */ -struct nghttp2_stream_group { - /* Intrusive Map */ - nghttp2_map_entry map_entry; - /* The number of streams this priority group contains */ - size_t num_streams; - /* The number of streams marked as NGHTTP2_STREAM_DPRI_TOP */ - ssize_t num_top; - /* The priority group ID */ - int32_t pri_group_id; - /* The weight of this group */ - int32_t weight; -}; - -void nghttp2_stream_group_init(nghttp2_stream_group *stream_group, - int32_t pri_group_id, - int32_t weight); - -void nghttp2_stream_group_free(nghttp2_stream_group *stream_group); - -/* - * Adds |stream| to |stream_group|. - */ -void nghttp2_stream_group_add_stream(nghttp2_stream_group *stream_group, - nghttp2_stream *stream); - -/* - * Removes |stream| from |stream_group|. - */ -void nghttp2_stream_group_remove_stream(nghttp2_stream_group *stream_group, - nghttp2_stream *stream); - -/* - * Updates |stream_group->num_top| += |delta| - */ -void nghttp2_stream_group_update_num_top(nghttp2_stream_group *stream_group, - ssize_t delta); - -/* - * Returns shared weight among the streams belongs to |stream_group|. - */ -size_t nghttp2_stream_group_shared_wait(nghttp2_stream_group *stream_group); +int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq); #endif /* NGHTTP2_STREAM */ diff --git a/lib/nghttp2_submit.c b/lib/nghttp2_submit.c index 7e69e437..fc6a0c31 100644 --- a/lib/nghttp2_submit.c +++ b/lib/nghttp2_submit.c @@ -77,8 +77,7 @@ static int nghttp2_submit_headers_shared flags_copy = (flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_SEGMENT | - NGHTTP2_FLAG_PRIORITY_GROUP | - NGHTTP2_FLAG_PRIORITY_DEPENDENCY)) | + NGHTTP2_FLAG_PRIORITY)) | NGHTTP2_FLAG_END_HEADERS; nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, pri_spec, @@ -102,14 +101,16 @@ static int nghttp2_submit_headers_shared return rv; } -static void adjust_priority_spec_group_weight(nghttp2_priority_spec *pri_spec) +static void adjust_priority_spec_weight(nghttp2_priority_spec *pri_spec) { - assert(pri_spec->pri_type == NGHTTP2_PRIORITY_TYPE_GROUP); + if(pri_spec->stream_id == 0) { + pri_spec->exclusive = 0; + } - if(pri_spec->spec.group.weight < NGHTTP2_MIN_WEIGHT) { - pri_spec->spec.group.weight = NGHTTP2_MIN_WEIGHT; - } else if(pri_spec->spec.group.weight > NGHTTP2_MAX_WEIGHT) { - pri_spec->spec.group.weight = NGHTTP2_MAX_WEIGHT; + if(pri_spec->weight < NGHTTP2_MIN_WEIGHT) { + pri_spec->weight = NGHTTP2_MIN_WEIGHT; + } else if(pri_spec->weight > NGHTTP2_MAX_WEIGHT) { + pri_spec->weight = NGHTTP2_MAX_WEIGHT; } } @@ -125,25 +126,13 @@ static int nghttp2_submit_headers_shared_nva { ssize_t rv; nghttp2_nv *nva_copy; - nghttp2_priority_spec copy_pri_spec = { - NGHTTP2_PRIORITY_TYPE_NONE - }; + nghttp2_priority_spec copy_pri_spec; if(pri_spec) { - switch(pri_spec->pri_type) { - case NGHTTP2_PRIORITY_TYPE_NONE: - case NGHTTP2_PRIORITY_TYPE_GROUP: - case NGHTTP2_PRIORITY_TYPE_DEP: - break; - default: - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - copy_pri_spec = *pri_spec; - - if(copy_pri_spec.pri_type == NGHTTP2_PRIORITY_TYPE_GROUP) { - adjust_priority_spec_group_weight(©_pri_spec); - } + adjust_priority_spec_weight(©_pri_spec); + } else { + nghttp2_priority_spec_default_init(©_pri_spec); } rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen); @@ -164,20 +153,10 @@ int nghttp2_submit_headers(nghttp2_session *session, uint8_t flags, { flags &= NGHTTP2_FLAG_END_STREAM; - if(pri_spec) { - switch(pri_spec->pri_type) { - case NGHTTP2_PRIORITY_TYPE_GROUP: - flags |= NGHTTP2_FLAG_PRIORITY_GROUP; - break; - case NGHTTP2_PRIORITY_TYPE_DEP: - flags |= NGHTTP2_FLAG_PRIORITY_DEPENDENCY; - break; - default: - /* Default weight */ - pri_spec = NULL; - - break; - } + if(pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) { + flags |= NGHTTP2_FLAG_PRIORITY; + } else { + pri_spec = NULL; } return nghttp2_submit_headers_shared_nva(session, flags, stream_id, pri_spec, @@ -203,23 +182,14 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags, return NGHTTP2_ERR_INVALID_ARGUMENT; } - copy_pri_spec = *pri_spec; - - switch(copy_pri_spec.pri_type) { - case NGHTTP2_PRIORITY_TYPE_GROUP: - adjust_priority_spec_group_weight(©_pri_spec); - - break; - case NGHTTP2_PRIORITY_TYPE_DEP: - if(stream_id == copy_pri_spec.spec.dep.stream_id) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - break; - default: + if(stream_id == pri_spec->stream_id) { return NGHTTP2_ERR_INVALID_ARGUMENT; } + copy_pri_spec = *pri_spec; + + adjust_priority_spec_weight(©_pri_spec); + frame = malloc(sizeof(nghttp2_frame)); if(frame == NULL) { @@ -433,17 +403,7 @@ static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec, } if(pri_spec) { - switch(pri_spec->pri_type) { - case NGHTTP2_PRIORITY_TYPE_GROUP: - flags |= NGHTTP2_FLAG_PRIORITY_GROUP; - break; - case NGHTTP2_PRIORITY_TYPE_DEP: - flags |= NGHTTP2_FLAG_PRIORITY_DEPENDENCY; - break; - default: - /* Default weight */ - break; - } + flags |= NGHTTP2_FLAG_PRIORITY; } return flags; @@ -457,6 +417,10 @@ int nghttp2_submit_request(nghttp2_session *session, { uint8_t flags; + if(pri_spec && nghttp2_priority_spec_check_default(pri_spec)) { + pri_spec = NULL; + } + flags = set_request_flags(pri_spec, data_prd); return nghttp2_submit_headers_shared_nva(session, flags, -1, pri_spec, diff --git a/src/app_helper.cc b/src/app_helper.cc index 999260cf..dc78792e 100644 --- a/src/app_helper.cc +++ b/src/app_helper.cc @@ -261,27 +261,15 @@ void print_flags(const nghttp2_frame_hd& hd) } s += "PAD_HIGH"; } - if(hd.flags & NGHTTP2_FLAG_PRIORITY_GROUP) { + if(hd.flags & NGHTTP2_FLAG_PRIORITY) { if(!s.empty()) { s += " | "; } - s += "PRIORITY_GROUP"; - } - if(hd.flags & NGHTTP2_FLAG_PRIORITY_DEPENDENCY) { - if(!s.empty()) { - s += " | "; - } - s += "PRIORITY_DEPENDENCY"; + s += "PRIORITY"; } break; case NGHTTP2_PRIORITY: - if(hd.flags & NGHTTP2_FLAG_PRIORITY_GROUP) { - s += "PRIORITY_GROUP"; - } else if(hd.flags & NGHTTP2_FLAG_PRIORITY_DEPENDENCY) { - s += "PRIORITY_DEPENDENCY"; - } - break; case NGHTTP2_SETTINGS: if(hd.flags & NGHTTP2_FLAG_ACK) { @@ -368,14 +356,11 @@ void print_frame(print_type ptype, const nghttp2_frame *frame) case NGHTTP2_HEADERS: print_frame_attr_indent(); fprintf(outfile, "(padlen=%zu", frame->headers.padlen); - if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY_GROUP) { - fprintf(outfile, ", pri_group_id=%d, weight=%u", - frame->headers.pri_spec.spec.group.pri_group_id, - frame->headers.pri_spec.spec.group.weight); - } else if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY_DEPENDENCY) { - fprintf(outfile, ", stream_id=%d, exclusive=%d", - frame->headers.pri_spec.spec.dep.stream_id, - frame->headers.pri_spec.spec.dep.exclusive); + if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { + fprintf(outfile, ", stream_id=%d, weight=%u, exclusive=%d", + frame->headers.pri_spec.stream_id, + frame->headers.pri_spec.weight, + frame->headers.pri_spec.exclusive); } fprintf(outfile, ")\n"); switch(frame->headers.cat) { @@ -399,19 +384,10 @@ void print_frame(print_type ptype, const nghttp2_frame *frame) case NGHTTP2_PRIORITY: print_frame_attr_indent(); - fprintf(outfile, "("); - - if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY_GROUP) { - fprintf(outfile, "pri_group_id=%d, weight=%u", - frame->priority.pri_spec.spec.group.pri_group_id, - frame->priority.pri_spec.spec.group.weight); - } else if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY_DEPENDENCY) { - fprintf(outfile, "stream_id=%d, exclusive=%d", - frame->priority.pri_spec.spec.dep.stream_id, - frame->priority.pri_spec.spec.dep.exclusive); - } - - fprintf(outfile, ")\n"); + fprintf(outfile, "(stream_id=%d, weight=%u, exclusive=%d)\n", + frame->priority.pri_spec.stream_id, + frame->priority.pri_spec.weight, + frame->priority.pri_spec.exclusive); break; case NGHTTP2_RST_STREAM: diff --git a/src/nghttp.cc b/src/nghttp.cc index d9afc42b..7dcfdca8 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -263,7 +263,7 @@ struct Request { nghttp2_priority_spec resolve_dep(int32_t pri) { - nghttp2_priority_spec pri_spec = { NGHTTP2_PRIORITY_TYPE_NONE }; + nghttp2_priority_spec pri_spec; int exclusive = 0; int32_t stream_id = -1; @@ -271,6 +271,8 @@ struct Request { return pri_spec; } + nghttp2_priority_spec_default_init(&pri_spec); + auto start = std::min(pri, (int)dep->deps.size() - 1); for(auto i = start; i >= 0; --i) { @@ -293,7 +295,8 @@ struct Request { return pri_spec; } - nghttp2_priority_spec_dep_init(&pri_spec, stream_id, exclusive); + nghttp2_priority_spec_init(&pri_spec, stream_id, NGHTTP2_DEFAULT_WEIGHT, + exclusive); return pri_spec; } @@ -1014,12 +1017,9 @@ void update_html_parser(HttpClient *client, Request *req, nghttp2_priority_spec pri_spec; - // We always specify priority group of parent stream, so that - // even if the parent stream is closed, the dependent stream is - // in the same priority group. We adjust the priority using - // separate PRIORITY frame after stream ID becomes known. - nghttp2_priority_spec_group_init(&pri_spec, req->stream_id, - config.weight); + // We adjust the priority using separate PRIORITY frame after + // stream ID becomes known. + nghttp2_priority_spec_default_init(&pri_spec); if ( client->add_request(uri, nullptr, 0, pri_spec, req->dep, req->level+1) ) { @@ -1108,9 +1108,8 @@ void check_stream_id(nghttp2_session *session, int32_t stream_id, auto pri_spec = req->resolve_dep(req->pri); - if(pri_spec.pri_type == NGHTTP2_PRIORITY_TYPE_DEP) { - nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, stream_id, - &pri_spec); + if(!nghttp2_priority_spec_check_default(&pri_spec)) { + nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, stream_id, &pri_spec); } auto itr = std::begin(req->dep->deps); @@ -1208,7 +1207,9 @@ int on_begin_headers_callback(nghttp2_session *session, http_parser_url u; memset(&u, 0, sizeof(u)); // TODO Set pri and level - nghttp2_priority_spec pri_spec = { NGHTTP2_PRIORITY_TYPE_NONE }; + nghttp2_priority_spec pri_spec; + + nghttp2_priority_spec_default_init(&pri_spec); auto req = util::make_unique("", u, nullptr, 0, pri_spec, nullptr); @@ -1624,10 +1625,12 @@ int communicate(const std::string& scheme, const std::string& host, { HttpClient client{callbacks, evbase, ssl_ctx}; - nghttp2_priority_spec pri_spec = { NGHTTP2_PRIORITY_TYPE_NONE }; + nghttp2_priority_spec pri_spec; if(config.weight != NGHTTP2_DEFAULT_WEIGHT) { - nghttp2_priority_spec_group_init(&pri_spec, -1, config.weight); + nghttp2_priority_spec_init(&pri_spec, 0, config.weight, 0); + } else { + nghttp2_priority_spec_default_init(&pri_spec); } for(auto req : requests) { diff --git a/tests/main.c b/tests/main.c index d0937f0f..0335a713 100644 --- a/tests/main.c +++ b/tests/main.c @@ -226,6 +226,8 @@ int main(int argc, char* argv[]) test_nghttp2_session_stream_attach_data) || !CU_add_test(pSuite, "session_stream_attach_data_subtree", test_nghttp2_session_stream_attach_data_subtree) || + !CU_add_test(pSuite, "session_stream_dep_effective_weight", + test_nghttp2_session_stream_dep_effective_weight) || !CU_add_test(pSuite, "session_stream_keep_closed_stream", test_nghttp2_session_keep_closed_stream) || !CU_add_test(pSuite, "frame_pack_headers", diff --git a/tests/nghttp2_frame_test.c b/tests/nghttp2_frame_test.c index 11d7a2c4..0db0a44a 100644 --- a/tests/nghttp2_frame_test.c +++ b/tests/nghttp2_frame_test.c @@ -92,7 +92,7 @@ void test_nghttp2_frame_pack_headers() nva = headers(); nvlen = HEADERS_LENGTH; - pri_spec.pri_type = NGHTTP2_PRIORITY_TYPE_NONE; + nghttp2_priority_spec_default_init(&pri_spec); nghttp2_frame_headers_init(&frame, NGHTTP2_FLAG_END_STREAM | @@ -110,8 +110,8 @@ void test_nghttp2_frame_pack_headers() NGHTTP2_HEADERS, NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS, 1000000007, &oframe.hd); - /* We include NGHTTP2_PRIORITY_TYPE_NONE */ - CU_ASSERT(NGHTTP2_PRIORITY_TYPE_NONE == oframe.pri_spec.pri_type); + /* We did not include PRIORITY flag */ + CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == oframe.pri_spec.weight); hdblocklen = nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN; CU_ASSERT(hdblocklen == @@ -126,9 +126,9 @@ void test_nghttp2_frame_pack_headers() nghttp2_bufs_reset(&bufs); memset(&oframe, 0, sizeof(oframe)); - /* Next, include NGHTTP2_PRIORITY_TYPE_GROUP */ - nghttp2_priority_spec_group_init(&frame.pri_spec, 1000000009, 12); - frame.hd.flags |= NGHTTP2_FLAG_PRIORITY_GROUP; + /* Next, include NGHTTP2_FLAG_PRIORITY */ + nghttp2_priority_spec_init(&frame.pri_spec, 1000000009, 12, 1); + frame.hd.flags |= NGHTTP2_FLAG_PRIORITY; rv = nghttp2_frame_pack_headers(&bufs, &frame, &deflater); @@ -139,12 +139,12 @@ void test_nghttp2_frame_pack_headers() check_frame_header(nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN, NGHTTP2_HEADERS, NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS | - NGHTTP2_FLAG_PRIORITY_GROUP, + NGHTTP2_FLAG_PRIORITY, 1000000007, &oframe.hd); - CU_ASSERT(NGHTTP2_PRIORITY_TYPE_GROUP == oframe.pri_spec.pri_type); - CU_ASSERT(1000000009 == oframe.pri_spec.spec.group.pri_group_id); - CU_ASSERT(12 == oframe.pri_spec.spec.group.weight); + CU_ASSERT(1000000009 == oframe.pri_spec.stream_id); + CU_ASSERT(12 == oframe.pri_spec.weight); + CU_ASSERT(1 == oframe.pri_spec.exclusive); hdblocklen = nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN - nghttp2_frame_priority_len(oframe.hd.flags); @@ -159,44 +159,7 @@ void test_nghttp2_frame_pack_headers() nva_out_reset(&out); nghttp2_bufs_reset(&bufs); - memset(&oframe, 0, sizeof(oframe)); - - /* Next, include NGHTTP2_PRIORITY_TYPE_DEP */ - nghttp2_priority_spec_dep_init(&frame.pri_spec, 123, 1); - - frame.hd.flags = - NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS | - NGHTTP2_FLAG_PRIORITY_DEPENDENCY; - - rv = nghttp2_frame_pack_headers(&bufs, &frame, &deflater); - - CU_ASSERT(0 == rv); - CU_ASSERT(nghttp2_bufs_len(&bufs) > 0); - CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs)); - - check_frame_header(nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN, - NGHTTP2_HEADERS, - NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS | - NGHTTP2_FLAG_PRIORITY_DEPENDENCY, - 1000000007, &oframe.hd); - - CU_ASSERT(NGHTTP2_PRIORITY_TYPE_DEP == oframe.pri_spec.pri_type); - CU_ASSERT(123 == oframe.pri_spec.spec.dep.stream_id); - CU_ASSERT(1 == oframe.pri_spec.spec.dep.exclusive); - - hdblocklen = nghttp2_bufs_len(&bufs) - NGHTTP2_FRAME_HDLEN - - nghttp2_frame_priority_len(oframe.hd.flags); - CU_ASSERT(hdblocklen == - inflate_hd(&inflater, &out, &bufs, NGHTTP2_FRAME_HDLEN - + nghttp2_frame_priority_len(oframe.hd.flags))); - - nghttp2_nv_array_sort(out.nva, out.nvlen); - CU_ASSERT(nvnameeq("method", &out.nva[0])); - - nghttp2_frame_headers_free(&oframe); - nva_out_reset(&out); nghttp2_bufs_free(&bufs); - nghttp2_frame_headers_free(&frame); nghttp2_hd_inflate_free(&inflater); nghttp2_hd_deflate_free(&deflater); @@ -208,7 +171,6 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void) nghttp2_headers frame; nghttp2_bufs bufs; nghttp2_nv *nva; - nghttp2_priority_spec pri_spec; ssize_t nvlen; size_t big_vallen = NGHTTP2_HD_MAX_VALUE; nghttp2_nv big_hds[16]; @@ -228,13 +190,11 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void) big_hds[i].flags = NGHTTP2_NV_FLAG_NONE; } - pri_spec.pri_type = NGHTTP2_PRIORITY_TYPE_NONE; - nvlen = nghttp2_nv_array_copy(&nva, big_hds, big_hdslen); nghttp2_hd_deflate_init(&deflater); nghttp2_frame_headers_init(&frame, NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS, - 1000000007, &pri_spec, nva, nvlen); + 1000000007, NULL, nva, nvlen); rv = nghttp2_frame_pack_headers(&bufs, &frame, &deflater); CU_ASSERT(NGHTTP2_ERR_HEADER_COMP == rv); @@ -256,7 +216,7 @@ void test_nghttp2_frame_pack_priority(void) frame_pack_bufs_init(&bufs); /* First, pack priority with priority group and weight */ - nghttp2_priority_spec_group_init(&pri_spec, 1000000009, 12); + nghttp2_priority_spec_init(&pri_spec, 1000000009, 12, 1); nghttp2_frame_priority_init(&frame, 1000000007, &pri_spec); rv = nghttp2_frame_pack_priority(&bufs, &frame); @@ -264,34 +224,12 @@ void test_nghttp2_frame_pack_priority(void) CU_ASSERT(0 == rv); CU_ASSERT(13 == nghttp2_bufs_len(&bufs)); CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs)); - check_frame_header(4, NGHTTP2_PRIORITY, NGHTTP2_FLAG_PRIORITY_GROUP, + check_frame_header(5, NGHTTP2_PRIORITY, NGHTTP2_FLAG_NONE, 1000000007, &oframe.hd); - CU_ASSERT(NGHTTP2_PRIORITY_TYPE_GROUP == oframe.pri_spec.pri_type); - CU_ASSERT(1000000009 == oframe.pri_spec.spec.group.pri_group_id); - CU_ASSERT(12 == oframe.pri_spec.spec.group.weight); - - nghttp2_frame_priority_free(&oframe); - nghttp2_bufs_reset(&bufs); - - memset(&oframe, 0, sizeof(oframe)); - - /* Next, pack priority with stream dependency */ - nghttp2_priority_spec_dep_init(&pri_spec, 79, 1); - - nghttp2_frame_priority_init(&frame, 1000000007, &pri_spec); - rv = nghttp2_frame_pack_priority(&bufs, &frame); - - CU_ASSERT(0 == rv); - CU_ASSERT(12 == nghttp2_bufs_len(&bufs)); - - CU_ASSERT(0 == unpack_framebuf((nghttp2_frame*)&oframe, &bufs)); - check_frame_header(4, NGHTTP2_PRIORITY, NGHTTP2_FLAG_PRIORITY_DEPENDENCY, - 1000000007, &oframe.hd); - - CU_ASSERT(NGHTTP2_PRIORITY_TYPE_DEP == oframe.pri_spec.pri_type); - CU_ASSERT(79 == oframe.pri_spec.spec.dep.stream_id); - CU_ASSERT(1 == oframe.pri_spec.spec.dep.exclusive); + CU_ASSERT(1000000009 == oframe.pri_spec.stream_id); + CU_ASSERT(12 == oframe.pri_spec.weight); + CU_ASSERT(1 == oframe.pri_spec.exclusive); nghttp2_frame_priority_free(&oframe); nghttp2_bufs_reset(&bufs); diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 8b11289f..30f5e8f4 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -355,8 +355,8 @@ static nghttp2_settings_entry* dup_iv(const nghttp2_settings_entry *iv, return nghttp2_frame_iv_copy(iv, niv); } -static nghttp2_priority_spec pri_spec_none = { - NGHTTP2_PRIORITY_TYPE_NONE +static nghttp2_priority_spec pri_spec_default = { + 0, NGHTTP2_DEFAULT_WEIGHT, 0 }; void test_nghttp2_session_recv(void) @@ -392,7 +392,7 @@ void test_nghttp2_session_recv(void) nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv)); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, - 1, &pri_spec_none, nva, nvlen); + 1, NULL, nva, nvlen); rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater); CU_ASSERT(0 == rv); @@ -418,7 +418,7 @@ void test_nghttp2_session_recv(void) /* Received HEADERS without header block, which is valid */ nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, - 5, &pri_spec_none, NULL, 0); + 5, NULL, NULL, 0); rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater); CU_ASSERT(0 == rv); @@ -491,7 +491,7 @@ void test_nghttp2_session_recv_invalid_stream_id(void) nghttp2_hd_deflate_init(&deflater); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 2, - &pri_spec_none, NULL, 0); + NULL, NULL, 0); rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater); CU_ASSERT(0 == rv); @@ -537,7 +537,7 @@ void test_nghttp2_session_recv_invalid_frame(void) nghttp2_hd_deflate_init(&deflater); nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv)); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1, - &pri_spec_none, nva, nvlen); + NULL, nva, nvlen); rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater); CU_ASSERT(0 == rv); @@ -625,7 +625,7 @@ void test_nghttp2_session_recv_data(void) /* Create stream 1 with CLOSING state. DATA is ignored. */ stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_CLOSING, NULL); /* Set initial window size 16383 to check stream flow control, isolating it from the conneciton flow control */ @@ -739,7 +739,7 @@ void test_nghttp2_session_recv_continuation(void) /* Make 1 HEADERS and insert CONTINUATION header */ nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_NONE, 1, - &pri_spec_none, nva, nvlen); + NULL, nva, nvlen); rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater); CU_ASSERT(0 == rv); @@ -801,7 +801,7 @@ void test_nghttp2_session_recv_continuation(void) /* HEADERS without END_HEADERS flag */ nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_NONE, 1, - &pri_spec_none, nva, nvlen); + NULL, nva, nvlen); nghttp2_bufs_reset(&bufs); rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater); @@ -818,7 +818,7 @@ void test_nghttp2_session_recv_continuation(void) datalen = nghttp2_buf_len(buf); /* Followed by PRIORITY */ - nghttp2_priority_spec_group_init(&pri_spec, 1, 0); + nghttp2_priority_spec_default_init(&pri_spec); nghttp2_frame_priority_init(&frame.priority, 1, &pri_spec); nghttp2_bufs_reset(&bufs); @@ -873,48 +873,15 @@ void test_nghttp2_session_recv_headers_with_priority(void) nghttp2_hd_deflate_init(&deflater); - /* With NGHTTP2_FLAG_PRIORITY_GROUP */ + open_stream(session, 1); + + /* With NGHTTP2_FLAG_PRIORITY without exclusive flag set */ nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); - nghttp2_priority_spec_group_init(&pri_spec, 0, 99); + nghttp2_priority_spec_init(&pri_spec, 1, 99, 0); nghttp2_frame_headers_init(&frame.headers, - NGHTTP2_FLAG_END_HEADERS | - NGHTTP2_FLAG_PRIORITY_GROUP, - 1, &pri_spec, nva, nvlen); - - rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater); - - CU_ASSERT(0 == rv); - CU_ASSERT(nghttp2_bufs_len(&bufs) > 0); - - nghttp2_frame_headers_free(&frame.headers); - - buf = &bufs.head->buf; - assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf)); - - ud.frame_recv_cb_called = 0; - - rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf)); - - CU_ASSERT(nghttp2_buf_len(buf) == rv); - CU_ASSERT(1 == ud.frame_recv_cb_called); - - stream = nghttp2_session_get_stream(session, 1); - - CU_ASSERT(0 == stream->stream_group->pri_group_id); - CU_ASSERT(99 == stream->stream_group->weight); - - nghttp2_bufs_reset(&bufs); - - /* With NGHTTP2_FLAG_PRIORITY_DEP without exclusive flag set */ - nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); - - nghttp2_priority_spec_dep_init(&pri_spec, 1, 0); - - nghttp2_frame_headers_init(&frame.headers, - NGHTTP2_FLAG_END_HEADERS | - NGHTTP2_FLAG_PRIORITY_DEPENDENCY, + NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY, 3, &pri_spec, nva, nvlen); rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater); @@ -936,21 +903,19 @@ void test_nghttp2_session_recv_headers_with_priority(void) stream = nghttp2_session_get_stream(session, 3); - CU_ASSERT(0 == stream->stream_group->pri_group_id); - CU_ASSERT(99 == stream->stream_group->weight); + CU_ASSERT(99 == stream->weight); CU_ASSERT(1 == stream->dep_prev->stream_id); nghttp2_bufs_reset(&bufs); - /* With NGHTTP2_FLAG_PRIORITY_GROUP, but cut last 1 byte to make it + /* With NGHTTP2_FLAG_PRIORITY, but cut last 1 byte to make it invalid. */ nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); - nghttp2_priority_spec_group_init(&pri_spec, 0, 99); + nghttp2_priority_spec_init(&pri_spec, 0, 99, 0); nghttp2_frame_headers_init(&frame.headers, - NGHTTP2_FLAG_END_HEADERS | - NGHTTP2_FLAG_PRIORITY_GROUP, + NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY, 5, &pri_spec, nva, nvlen); rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater); @@ -993,11 +958,10 @@ void test_nghttp2_session_recv_headers_with_priority(void) nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); - nghttp2_priority_spec_dep_init(&pri_spec, 1, 0); + nghttp2_priority_spec_init(&pri_spec, 1, 0, 0); nghttp2_frame_headers_init(&frame.headers, - NGHTTP2_FLAG_END_HEADERS | - NGHTTP2_FLAG_PRIORITY_DEPENDENCY, + NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY, 1, &pri_spec, nva, nvlen); rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater); @@ -1061,7 +1025,7 @@ void test_nghttp2_session_recv_premature_headers(void) nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1, - &pri_spec_none, nva, nvlen); + NULL, nva, nvlen); rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater); CU_ASSERT(0 == rv); @@ -1225,7 +1189,7 @@ void test_nghttp2_session_continue(void) /* Make 2 HEADERS frames */ nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1, - &pri_spec_none, nva, nvlen); + NULL, nva, nvlen); rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater); CU_ASSERT(0 == rv); @@ -1241,7 +1205,7 @@ void test_nghttp2_session_continue(void) nvlen = nghttp2_nv_array_copy(&nva, nv2, ARRLEN(nv2)); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 3, - &pri_spec_none, nva, nvlen); + NULL, nva, nvlen); nghttp2_bufs_reset(&bufs); rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater); @@ -1390,7 +1354,6 @@ void test_nghttp2_session_add_frame(void) malloc(sizeof(nghttp2_headers_aux_data)); nghttp2_nv *nva; ssize_t nvlen; - nghttp2_priority_spec pri_spec; memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); callbacks.send_callback = accumulator_send_callback; @@ -1404,19 +1367,16 @@ void test_nghttp2_session_add_frame(void) frame = malloc(sizeof(nghttp2_frame)); nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv)); - nghttp2_priority_spec_group_init(&pri_spec, 1, 12); - nghttp2_frame_headers_init(&frame->headers, - NGHTTP2_FLAG_END_HEADERS | - NGHTTP2_FLAG_PRIORITY_GROUP, - -1, &pri_spec, nva, nvlen); + NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY, + -1, NULL, nva, nvlen); CU_ASSERT(0 == nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, aux_data)); CU_ASSERT(0 == nghttp2_pq_empty(&session->ob_ss_pq)); CU_ASSERT(0 == nghttp2_session_send(session)); CU_ASSERT(NGHTTP2_HEADERS == acc.buf[2]); - CU_ASSERT((NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY_GROUP) == + CU_ASSERT((NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY) == acc.buf[3]); /* check stream id */ CU_ASSERT(1 == nghttp2_get_uint32(&acc.buf[4])); @@ -1443,11 +1403,10 @@ void test_nghttp2_session_on_request_headers_received(void) nghttp2_session_server_new(&session, &callbacks, &user_data); - nghttp2_priority_spec_group_init(&pri_spec, 1, 12); + nghttp2_priority_spec_init(&pri_spec, 0, 255, 0); nghttp2_frame_headers_init(&frame.headers, - NGHTTP2_FLAG_END_HEADERS | - NGHTTP2_FLAG_PRIORITY_GROUP, + NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY, stream_id, &pri_spec, NULL, 0); user_data.begin_headers_cb_called = 0; @@ -1457,7 +1416,7 @@ void test_nghttp2_session_on_request_headers_received(void) CU_ASSERT(1 == user_data.begin_headers_cb_called); stream = nghttp2_session_get_stream(session, stream_id); CU_ASSERT(NGHTTP2_STREAM_OPENING == stream->state); - CU_ASSERT(12 == stream->stream_group->weight); + CU_ASSERT(255 == stream->weight); nghttp2_frame_headers_free(&frame.headers); @@ -1465,8 +1424,8 @@ void test_nghttp2_session_on_request_headers_received(void) session->pending_local_max_concurrent_stream = 1; nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS | - NGHTTP2_FLAG_PRIORITY_GROUP, - 3, &pri_spec, NULL, 0); + NGHTTP2_FLAG_PRIORITY, + 3, NULL, NULL, 0); user_data.invalid_frame_recv_cb_called = 0; CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK == nghttp2_session_on_request_headers_received(session, &frame)); @@ -1481,8 +1440,8 @@ void test_nghttp2_session_on_request_headers_received(void) HEADERS leads to connection error */ nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS | - NGHTTP2_FLAG_PRIORITY_GROUP, - 3, &pri_spec, NULL, 0); + NGHTTP2_FLAG_PRIORITY, + 3, NULL, NULL, 0); user_data.invalid_frame_recv_cb_called = 0; CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK == nghttp2_session_on_request_headers_received(session, &frame)); @@ -1498,9 +1457,8 @@ void test_nghttp2_session_on_request_headers_received(void) nvlen = nghttp2_nv_array_copy(&nva, malformed_nva, ARRLEN(malformed_nva)); nghttp2_frame_headers_init(&frame.headers, - NGHTTP2_FLAG_END_HEADERS | - NGHTTP2_FLAG_PRIORITY_GROUP, - 1, &pri_spec, nva, nvlen); + NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY, + 1, NULL, nva, nvlen); user_data.begin_headers_cb_called = 0; user_data.invalid_frame_recv_cb_called = 0; CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session, &frame)); @@ -1526,10 +1484,10 @@ void test_nghttp2_session_on_response_headers_received(void) nghttp2_session_client_new(&session, &callbacks, &user_data); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1, - &pri_spec_none, NULL, 0); + NULL, NULL, 0); user_data.begin_headers_cb_called = 0; user_data.invalid_frame_recv_cb_called = 0; @@ -1557,11 +1515,11 @@ void test_nghttp2_session_on_headers_received(void) nghttp2_session_client_new(&session, &callbacks, &user_data); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENED, NULL); nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1, - &pri_spec_none, NULL, 0); + NULL, NULL, 0); user_data.begin_headers_cb_called = 0; user_data.invalid_frame_recv_cb_called = 0; @@ -1579,7 +1537,7 @@ void test_nghttp2_session_on_headers_received(void) /* Check to see when NGHTTP2_STREAM_CLOSING, incoming HEADERS is discarded. */ stream = nghttp2_session_open_stream(session, 3, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_CLOSING, NULL); frame.hd.stream_id = 3; frame.hd.flags = NGHTTP2_FLAG_END_HEADERS; @@ -1591,7 +1549,7 @@ void test_nghttp2_session_on_headers_received(void) /* Server initiated stream */ stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); /* half closed (remote) */ @@ -1630,10 +1588,10 @@ void test_nghttp2_session_on_push_response_headers_received(void) nghttp2_session_client_new(&session, &callbacks, &user_data); stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_RESERVED, NULL); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 2, - &pri_spec_none, NULL, 0); + NULL, NULL, 0); /* nghttp2_session_on_push_response_headers_received assumes stream's state is NGHTTP2_STREAM_RESERVED and session->server is 0. */ @@ -1651,7 +1609,7 @@ void test_nghttp2_session_on_push_response_headers_received(void) RST_STREAMed */ session->pending_local_max_concurrent_stream = 1; stream = nghttp2_session_open_stream(session, 4, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_RESERVED, NULL); frame.hd.stream_id = 4; CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK == @@ -1670,7 +1628,7 @@ void test_nghttp2_session_on_push_response_headers_received(void) session->local_settings[NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] = 1; stream = nghttp2_session_open_stream(session, 6, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_RESERVED, NULL); frame.hd.stream_id = 6; @@ -1702,50 +1660,48 @@ void test_nghttp2_session_on_priority_received(void) nghttp2_session_server_new(&session, &callbacks, &user_data); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); - nghttp2_priority_spec_group_init(&pri_spec, 999, 2); + nghttp2_priority_spec_init(&pri_spec, 0, 2, 0); nghttp2_frame_priority_init(&frame.priority, 1, &pri_spec); /* non-push and initiated by remote peer */ CU_ASSERT(0 == nghttp2_session_on_priority_received(session, &frame)); - CU_ASSERT(999 == stream->stream_group->pri_group_id); - CU_ASSERT(2 == stream->stream_group->weight); + CU_ASSERT(2 == stream->weight); /* push and initiated by remote peer: no update */ stream->flags = NGHTTP2_STREAM_FLAG_PUSH; - frame.priority.pri_spec.spec.group.weight = 3; + frame.priority.pri_spec.weight = 3; CU_ASSERT(0 == nghttp2_session_on_priority_received(session, &frame)); - CU_ASSERT(2 == stream->stream_group->weight); + CU_ASSERT(2 == stream->weight); stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); dep_stream = nghttp2_session_open_stream(session, 3, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); frame.hd.stream_id = 2; /* non-push and initiated by local peer: no update */ CU_ASSERT(0 == nghttp2_session_on_priority_received(session, &frame)); - CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->stream_group->weight); + CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight); /* push and initiated by local peer */ stream->flags = NGHTTP2_STREAM_FLAG_PUSH; - nghttp2_priority_spec_dep_init(&frame.priority.pri_spec, 3, 0); + nghttp2_priority_spec_init(&frame.priority.pri_spec, 3, 1, 0); CU_ASSERT(0 == nghttp2_session_on_priority_received(session, &frame)); - CU_ASSERT(3 == stream->stream_group->pri_group_id); CU_ASSERT(dep_stream == stream->dep_prev); nghttp2_frame_priority_free(&frame.priority); @@ -1754,10 +1710,10 @@ void test_nghttp2_session_on_priority_received(void) /* Check that receiving PRIORITY in reserved(remote) is error */ nghttp2_session_server_new(&session, &callbacks, &user_data); nghttp2_session_open_stream(session, 3, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_RESERVED, NULL); - nghttp2_frame_priority_init(&frame.priority, 3, &pri_spec); + nghttp2_frame_priority_init(&frame.priority, 3, &pri_spec_default); user_data.frame_recv_cb_called = 0; user_data.invalid_frame_recv_cb_called = 0; @@ -1771,10 +1727,10 @@ void test_nghttp2_session_on_priority_received(void) /* Check dep_stream_id == stream_id case */ nghttp2_session_server_new(&session, &callbacks, &user_data); nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENED, NULL); - nghttp2_priority_spec_dep_init(&pri_spec, 1, 0); + nghttp2_priority_spec_init(&pri_spec, 1, 0, 0); nghttp2_frame_priority_init(&frame.priority, 1, &pri_spec); @@ -1797,7 +1753,7 @@ void test_nghttp2_session_on_rst_stream_received(void) memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); nghttp2_session_server_new(&session, &callbacks, &user_data); nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); nghttp2_frame_rst_stream_init(&frame.rst_stream, 1, NGHTTP2_PROTOCOL_ERROR); @@ -1840,10 +1796,10 @@ void test_nghttp2_session_on_settings_received(void) session->remote_settings[NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE] = 16*1024; stream1 = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); stream2 = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); /* Set window size for each streams and will see how settings updates these values */ @@ -1929,7 +1885,7 @@ void test_nghttp2_session_on_push_promise_received(void) nghttp2_session_client_new(&session, &callbacks, &user_data); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); nghttp2_frame_push_promise_init(&frame.push_promise, NGHTTP2_FLAG_END_HEADERS, 1, 2, @@ -2004,7 +1960,7 @@ void test_nghttp2_session_on_push_promise_received(void) nghttp2_session_client_new(&session, &callbacks, &user_data); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); /* Same ID twice */ @@ -2040,7 +1996,7 @@ void test_nghttp2_session_on_push_promise_received(void) nghttp2_session_client_new(&session, &callbacks, &user_data); stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_RESERVED, NULL); /* Attempt to PUSH_PROMISE against reserved (remote) stream */ nghttp2_frame_push_promise_init(&frame.push_promise, @@ -2062,7 +2018,7 @@ void test_nghttp2_session_on_push_promise_received(void) nghttp2_session_client_new(&session, &callbacks, &user_data); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); session->local_settings[NGHTTP2_SETTINGS_ENABLE_PUSH] = 0; @@ -2086,7 +2042,7 @@ void test_nghttp2_session_on_push_promise_received(void) nghttp2_session_client_new(&session, &callbacks, &user_data); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); nvlen = nghttp2_nv_array_copy(&nva, malformed_nva, ARRLEN(malformed_nva)); nghttp2_frame_push_promise_init(&frame.push_promise, @@ -2184,7 +2140,7 @@ void test_nghttp2_session_on_window_update_received(void) nghttp2_session_client_new(&session, &callbacks, &user_data); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENED, NULL); data_item = malloc(sizeof(nghttp2_outbound_item)); @@ -2215,7 +2171,7 @@ void test_nghttp2_session_on_window_update_received(void) /* WINDOW_UPDATE against reserved stream is a connection error */ stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_RESERVED, NULL); nghttp2_frame_window_update_init(&frame.window_update, NGHTTP2_FLAG_NONE, @@ -2243,7 +2199,7 @@ void test_nghttp2_session_on_data_received(void) nghttp2_session_client_new(&session, &callbacks, &user_data); stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); frame.hd.length = 4096; @@ -2260,7 +2216,7 @@ void test_nghttp2_session_on_data_received(void) /* If NGHTTP2_STREAM_CLOSING state, DATA frame is discarded. */ stream = nghttp2_session_open_stream(session, 4, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_CLOSING, NULL); frame.hd.flags = NGHTTP2_FLAG_NONE; @@ -2299,7 +2255,7 @@ void test_nghttp2_session_send_headers_start_stream(void) nghttp2_session_client_new(&session, &callbacks, NULL); nghttp2_frame_headers_init(&frame->headers, NGHTTP2_FLAG_END_HEADERS, -1, - &pri_spec_none, NULL, 0); + NULL, NULL, 0); nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, aux_data); CU_ASSERT(0 == nghttp2_session_send(session)); stream = nghttp2_session_get_stream(session, 1); @@ -2320,10 +2276,10 @@ void test_nghttp2_session_send_headers_reply(void) CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, NULL)); nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); nghttp2_frame_headers_init(&frame->headers, NGHTTP2_FLAG_END_HEADERS, 2, - &pri_spec_none, NULL, 0); + NULL, NULL, 0); nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, NULL); CU_ASSERT(0 == nghttp2_session_send(session)); stream = nghttp2_session_get_stream(session, 2); @@ -2361,7 +2317,7 @@ void test_nghttp2_session_send_headers_header_comp_error(void) nvlen = nghttp2_nv_array_copy(&nva, nv, nnv); nghttp2_frame_headers_init(&frame->headers, NGHTTP2_FLAG_END_HEADERS, -1, - &pri_spec_none, nva, nvlen); + NULL, nva, nvlen); nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, NULL); CU_ASSERT(0 == nghttp2_session_send(session)); @@ -2387,10 +2343,10 @@ void test_nghttp2_session_send_headers_push_reply(void) CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, NULL)); nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_RESERVED, NULL); nghttp2_frame_headers_init(&frame->headers, NGHTTP2_FLAG_END_HEADERS, 2, - &pri_spec_none, NULL, 0); + NULL, NULL, 0); nghttp2_session_add_frame(session, NGHTTP2_CAT_CTRL, frame, NULL); CU_ASSERT(0 == session->num_outgoing_streams); CU_ASSERT(0 == nghttp2_session_send(session)); @@ -2411,7 +2367,7 @@ void test_nghttp2_session_send_rst_stream(void) callbacks.send_callback = null_send_callback; nghttp2_session_client_new(&session, &callbacks, &user_data); nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); frame = malloc(sizeof(nghttp2_frame)); @@ -2439,7 +2395,7 @@ void test_nghttp2_session_send_push_promise(void) nghttp2_session_server_new(&session, &callbacks, &ud); nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, NGHTTP2_STREAM_OPENING, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); nghttp2_frame_push_promise_init(&frame->push_promise, NGHTTP2_FLAG_END_HEADERS, 1, -1, @@ -2477,7 +2433,7 @@ void test_nghttp2_session_send_push_promise(void) /* PUSH_PROMISE from client is error */ nghttp2_session_client_new(&session, &callbacks, &ud); nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, NGHTTP2_STREAM_OPENING, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); frame = malloc(sizeof(nghttp2_frame)); nghttp2_frame_push_promise_init(&frame->push_promise, @@ -2603,15 +2559,15 @@ void test_nghttp2_session_reprioritize_stream(void) nghttp2_session_server_new(&session, &callbacks, &ud); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); - nghttp2_priority_spec_group_init(&pri_spec, 2, 10); + nghttp2_priority_spec_init(&pri_spec, 0, 10, 0); nghttp2_session_reprioritize_stream(session, stream, &pri_spec); - CU_ASSERT(2 == stream->stream_group->pri_group_id); - CU_ASSERT(10 == stream->stream_group->weight); + CU_ASSERT(10 == stream->weight); + CU_ASSERT(NULL == stream->dep_prev); nghttp2_session_del(session); } @@ -2638,7 +2594,7 @@ void test_nghttp2_submit_data(void) framebufs = &aob->framebufs; nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, NGHTTP2_STREAM_OPENING, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); CU_ASSERT(0 == nghttp2_submit_data(session, NGHTTP2_FLAG_END_STREAM | @@ -2762,7 +2718,7 @@ void test_nghttp2_submit_response_with_data(void) ud.data_source_length = 64*1024 - 1; CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, &ud)); nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_END_STREAM, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); CU_ASSERT(0 == nghttp2_submit_response(session, 1, nva, ARRLEN(nva), &data_prd)); @@ -2801,7 +2757,7 @@ void test_nghttp2_submit_response_without_data(void) nghttp2_hd_inflate_init(&inflater); nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_END_STREAM, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); CU_ASSERT(0 == nghttp2_submit_response(session, 1, nva, ARRLEN(nva), &data_prd)); @@ -2843,8 +2799,7 @@ void test_nghttp2_submit_headers_start_stream(void) CU_ASSERT(nvnameeq(":version", &OB_CTRL(item)->headers.nva[0])); CU_ASSERT((NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_END_STREAM) == OB_CTRL(item)->hd.flags); - CU_ASSERT(NGHTTP2_PRIORITY_TYPE_NONE == - OB_CTRL(item)->headers.pri_spec.pri_type); + CU_ASSERT(0 == (OB_CTRL(item)->hd.flags & NGHTTP2_FLAG_PRIORITY)); nghttp2_session_del(session); } @@ -2882,7 +2837,7 @@ void test_nghttp2_submit_headers_reply(void) CU_ASSERT(0 == ud.frame_send_cb_called); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); CU_ASSERT(0 == nghttp2_submit_headers(session, @@ -2914,7 +2869,7 @@ void test_nghttp2_submit_headers_push_reply(void) CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, &ud)); stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_RESERVED, NULL); CU_ASSERT(0 == nghttp2_submit_headers(session, NGHTTP2_FLAG_NONE, @@ -2935,7 +2890,7 @@ void test_nghttp2_submit_headers_push_reply(void) error */ CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud)); stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_RESERVED, NULL); CU_ASSERT(0 == nghttp2_submit_headers(session, NGHTTP2_FLAG_NONE, @@ -2995,7 +2950,7 @@ void test_nghttp2_submit_headers(void) CU_ASSERT(0 == ud.frame_send_cb_called); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); CU_ASSERT(0 == nghttp2_submit_headers(session, @@ -3059,8 +3014,7 @@ void test_nghttp2_submit_headers_continuation(void) CU_ASSERT(NGHTTP2_HEADERS == OB_CTRL_TYPE(item)); CU_ASSERT((NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS) == OB_CTRL(item)->hd.flags); - CU_ASSERT(NGHTTP2_PRIORITY_TYPE_NONE == - OB_CTRL(item)->headers.pri_spec.pri_type); + CU_ASSERT(0 == (OB_CTRL(item)->hd.flags & NGHTTP2_FLAG_PRIORITY)); ud.frame_send_cb_called = 0; CU_ASSERT(0 == nghttp2_session_send(session)); @@ -3084,48 +3038,43 @@ void test_nghttp2_submit_priority(void) nghttp2_session_client_new(&session, &callbacks, &ud); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); - pri_spec.pri_type = 999999; - - CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == - nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, 1, &pri_spec)); - - nghttp2_priority_spec_group_init(&pri_spec, 1, 3); + nghttp2_priority_spec_init(&pri_spec, 0, 3, 0); /* non-push stream and initiated by local peer */ CU_ASSERT(0 == nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, 1, &pri_spec)); CU_ASSERT(0 == nghttp2_session_send(session)); - CU_ASSERT(3 == stream->stream_group->weight); + CU_ASSERT(3 == stream->weight); /* push stream and initiated by local peer: no update */ stream->flags = NGHTTP2_STREAM_FLAG_PUSH; - nghttp2_priority_spec_group_init(&pri_spec, 1, 2); + nghttp2_priority_spec_init(&pri_spec, 0, 2, 0); CU_ASSERT(0 == nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, 1, &pri_spec)); CU_ASSERT(0 == nghttp2_session_send(session)); - CU_ASSERT(3 == stream->stream_group->weight); + CU_ASSERT(3 == stream->weight); /* non-push stream and initiated by remote peer: no update */ stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); CU_ASSERT(0 == nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, 2, &pri_spec)); CU_ASSERT(0 == nghttp2_session_send(session)); - CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->stream_group->weight); + CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight); /* push stream and initiated by remote peer */ stream->flags = NGHTTP2_STREAM_FLAG_PUSH; CU_ASSERT(0 == nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, 2, &pri_spec)); CU_ASSERT(0 == nghttp2_session_send(session)); - CU_ASSERT(2 == stream->stream_group->weight); + CU_ASSERT(2 == stream->weight); nghttp2_session_del(session); @@ -3133,7 +3082,7 @@ void test_nghttp2_submit_priority(void) error */ nghttp2_session_server_new(&session, &callbacks, &ud); stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_RESERVED, NULL); CU_ASSERT(0 == nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, 2, @@ -3245,13 +3194,13 @@ void test_nghttp2_submit_settings_update_local_window_size(void) nghttp2_session_server_new(&session, &callbacks, NULL); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENED, NULL); stream->local_window_size = NGHTTP2_INITIAL_WINDOW_SIZE + 100; stream->recv_window_size = 32768; stream = nghttp2_session_open_stream(session, 3, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENED, NULL); CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 1)); @@ -3275,7 +3224,7 @@ void test_nghttp2_submit_settings_update_local_window_size(void) iv[0].value = 128*1024; nghttp2_session_server_new(&session, &callbacks, NULL); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENED, NULL); stream->local_window_size = NGHTTP2_MAX_WINDOW_SIZE; @@ -3308,7 +3257,7 @@ void test_nghttp2_submit_push_promise(void) CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, &ud)); nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); CU_ASSERT(0 == nghttp2_submit_push_promise(session, NGHTTP2_FLAG_NONE, 1, nv, ARRLEN(nv), &ud)); @@ -3339,7 +3288,7 @@ void test_nghttp2_submit_window_update(void) nghttp2_session_client_new(&session, &callbacks, &ud); stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENED, NULL); stream->recv_window_size = 4096; @@ -3390,7 +3339,7 @@ void test_nghttp2_submit_window_update_local_window_size(void) nghttp2_session_client_new(&session, &callbacks, NULL); stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENED, NULL); stream->recv_window_size = 4096; @@ -3590,7 +3539,7 @@ void test_nghttp2_session_open_stream(void) memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); nghttp2_session_server_new(&session, &callbacks, NULL); - nghttp2_priority_spec_group_init(&pri_spec, 100, 245); + nghttp2_priority_spec_init(&pri_spec, 0, 245, 0); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, &pri_spec, NGHTTP2_STREAM_OPENED, @@ -3598,41 +3547,41 @@ void test_nghttp2_session_open_stream(void) CU_ASSERT(1 == session->num_incoming_streams); CU_ASSERT(0 == session->num_outgoing_streams); CU_ASSERT(NGHTTP2_STREAM_OPENED == stream->state); - CU_ASSERT(100 == stream->stream_group->pri_group_id); - CU_ASSERT(245 == stream->stream_group->weight); + CU_ASSERT(245 == stream->weight); + CU_ASSERT(NULL == stream->dep_prev); CU_ASSERT(NGHTTP2_SHUT_NONE == stream->shut_flags); stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); CU_ASSERT(1 == session->num_incoming_streams); CU_ASSERT(1 == session->num_outgoing_streams); - CU_ASSERT(2 == stream->stream_group->pri_group_id); - CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->stream_group->weight); + CU_ASSERT(NULL == stream->dep_prev); + CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight); CU_ASSERT(NGHTTP2_SHUT_NONE == stream->shut_flags); stream = nghttp2_session_open_stream(session, 4, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_RESERVED, NULL); CU_ASSERT(1 == session->num_incoming_streams); CU_ASSERT(1 == session->num_outgoing_streams); - CU_ASSERT(4 == stream->stream_group->pri_group_id); - CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->stream_group->weight); + CU_ASSERT(NULL == stream->dep_prev); + CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight); CU_ASSERT(NGHTTP2_SHUT_RD == stream->shut_flags); nghttp2_session_del(session); nghttp2_session_client_new(&session, &callbacks, NULL); stream = nghttp2_session_open_stream(session, 4, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_RESERVED, NULL); CU_ASSERT(0 == session->num_incoming_streams); CU_ASSERT(0 == session->num_outgoing_streams); - CU_ASSERT(4 == stream->stream_group->pri_group_id); - CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->stream_group->weight); + CU_ASSERT(NULL == stream->dep_prev); + CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight); CU_ASSERT(NGHTTP2_SHUT_WR == stream->shut_flags); nghttp2_session_del(session); @@ -3665,10 +3614,10 @@ void test_nghttp2_session_get_next_ob_item(void) /* Incoming stream does not affect the number of outgoing max concurrent streams. */ nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); - nghttp2_priority_spec_group_init(&pri_spec, -1, NGHTTP2_MAX_WEIGHT); + nghttp2_priority_spec_init(&pri_spec, 0, NGHTTP2_MAX_WEIGHT, 0); nghttp2_submit_request(session, &pri_spec, NULL, 0, NULL, NULL); CU_ASSERT(NGHTTP2_HEADERS == @@ -3703,7 +3652,7 @@ void test_nghttp2_session_pop_next_ob_item(void) nghttp2_submit_ping(session, NGHTTP2_FLAG_NONE, NULL); - nghttp2_priority_spec_group_init(&pri_spec, -1, 254); + nghttp2_priority_spec_init(&pri_spec, 0, 254, 0); nghttp2_submit_request(session, &pri_spec, NULL, 0, NULL, NULL); @@ -3722,12 +3671,12 @@ void test_nghttp2_session_pop_next_ob_item(void) /* Incoming stream does not affect the number of outgoing max concurrent streams. */ nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, NGHTTP2_STREAM_OPENING, NULL); + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); /* In-flight outgoing stream */ nghttp2_session_open_stream(session, 4, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, NGHTTP2_STREAM_OPENING, NULL); + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); - nghttp2_priority_spec_group_init(&pri_spec, -1, NGHTTP2_MAX_WEIGHT); + nghttp2_priority_spec_init(&pri_spec, 0, NGHTTP2_MAX_WEIGHT, 0); nghttp2_submit_request(session, &pri_spec, NULL, 0, NULL, NULL); nghttp2_submit_response(session, 1, NULL, 0, NULL); @@ -3753,7 +3702,7 @@ void test_nghttp2_session_pop_next_ob_item(void) nghttp2_session_server_new(&session, &callbacks, NULL); session->remote_settings[NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] = 0; nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, NGHTTP2_STREAM_RESERVED, + &pri_spec_default, NGHTTP2_STREAM_RESERVED, NULL); CU_ASSERT(0 == nghttp2_submit_headers(session, NGHTTP2_FLAG_END_STREAM, 2, NULL, NULL, 0, @@ -3777,7 +3726,7 @@ void test_nghttp2_session_reply_fail(void) ud.data_source_length = 4*1024; CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, &ud)); nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); CU_ASSERT(0 == nghttp2_submit_response(session, 1, NULL, 0, &data_prd)); CU_ASSERT(NGHTTP2_ERR_CALLBACK_FAILURE == nghttp2_session_send(session)); @@ -3796,12 +3745,12 @@ void test_nghttp2_session_max_concurrent_streams(void) nghttp2_session_server_new(&session, &callbacks, NULL); nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENED, NULL); /* Check un-ACKed SETTINGS_MAX_CONCURRENT_STREAMS */ nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 3, - &pri_spec_none, NULL, 0); + NULL, NULL, 0); session->pending_local_max_concurrent_stream = 1; CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK == @@ -3877,7 +3826,7 @@ void test_nghttp2_session_stop_data_with_rst_stream(void) nghttp2_session_server_new(&session, &callbacks, &ud); nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); nghttp2_submit_response(session, 1, NULL, 0, &data_prd); @@ -3923,7 +3872,7 @@ void test_nghttp2_session_defer_data(void) nghttp2_session_server_new(&session, &callbacks, &ud); nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); nghttp2_submit_response(session, 1, NULL, 0, &data_prd); @@ -4103,7 +4052,7 @@ void test_nghttp2_session_flow_control_data_recv(void) nghttp2_session_client_new(&session, &callbacks, NULL); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENED, NULL); session->next_stream_id = 3; @@ -4169,7 +4118,7 @@ void test_nghttp2_session_flow_control_data_with_padding_recv(void) nghttp2_session_client_new(&session, &callbacks, NULL); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENED, NULL); /* Create DATA frame */ @@ -4266,7 +4215,7 @@ void test_nghttp2_session_on_stream_close(void) nghttp2_session_client_new(&session, &callbacks, &user_data); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENED, &user_data); CU_ASSERT(stream != NULL); CU_ASSERT(nghttp2_session_close_stream(session, 1, NGHTTP2_NO_ERROR) == 0); @@ -4290,7 +4239,7 @@ void test_nghttp2_session_on_ctrl_not_send(void) nghttp2_session_server_new(&session, &callbacks, &user_data); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENING, &user_data); /* Check response HEADERS */ @@ -4328,7 +4277,7 @@ void test_nghttp2_session_on_ctrl_not_send(void) CU_ASSERT(NGHTTP2_ERR_STREAM_CLOSED == user_data.not_sent_error); stream = nghttp2_session_open_stream(session, 3, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENED, &user_data); /* Check HEADERS */ @@ -4401,7 +4350,7 @@ void test_nghttp2_session_get_effective_local_window_size(void) CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, NULL)); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, + &pri_spec_default, NGHTTP2_STREAM_OPENED, NULL); CU_ASSERT(NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE == @@ -4503,6 +4452,8 @@ void test_nghttp2_session_set_option(void) session-> remote_settings[NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS]); nghttp2_session_del(session); + + nghttp2_option_del(option); } void test_nghttp2_session_data_backoff_by_high_pri_frame(void) @@ -4564,7 +4515,7 @@ static void check_session_recv_data_with_padding(nghttp2_bufs *bufs, nghttp2_session_server_new(&session, &callbacks, &ud); nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - &pri_spec_none, NGHTTP2_STREAM_OPENING, + &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL); inlen = nghttp2_bufs_remove(bufs, &in); @@ -4652,7 +4603,6 @@ void test_nghttp2_session_pack_headers_with_padding(void) nghttp2_session_callbacks callbacks; nghttp2_nv nva[8172]; size_t i; - nghttp2_priority_spec pri_spec; for(i = 0; i < ARRLEN(nva); ++i) { nva[i].name = (uint8_t*)":path"; @@ -4678,10 +4628,8 @@ void test_nghttp2_session_pack_headers_with_padding(void) ud.padding_boundary = 16385; - nghttp2_priority_spec_group_init(&pri_spec, 1, 255); - CU_ASSERT(0 == - nghttp2_submit_request(session, &pri_spec, + nghttp2_submit_request(session, NULL, nva, ARRLEN(nva), NULL, NULL)); CU_ASSERT(0 == nghttp2_session_send(session)); @@ -4915,6 +4863,11 @@ void test_nghttp2_session_stream_dep_add(void) 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(b, a, NULL, NULL, c); check_stream_dep_sib(c, NULL, d, b, NULL); @@ -4937,6 +4890,12 @@ void test_nghttp2_session_stream_dep_add(void) 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(e, a, b, NULL, NULL); check_stream_dep_sib(b, e, NULL, NULL, c); @@ -4982,6 +4941,11 @@ void test_nghttp2_session_stream_dep_remove(void) 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); @@ -5019,6 +4983,11 @@ void test_nghttp2_session_stream_dep_remove(void) 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(b, NULL, NULL, NULL, NULL); check_stream_dep_sib(c, a, d, NULL, NULL); @@ -5054,6 +5023,11 @@ void test_nghttp2_session_stream_dep_remove(void) CU_ASSERT(1 == 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(0 == d->sum_dep_weight); + CU_ASSERT(0 == c->sum_dep_weight); + check_stream_dep_sib(a, NULL, b, NULL, NULL); check_stream_dep_sib(b, a, NULL, NULL, d); check_stream_dep_sib(c, NULL, NULL, NULL, NULL); @@ -5085,6 +5059,13 @@ void test_nghttp2_session_stream_dep_remove(void) 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); + CU_ASSERT(0 == d->sum_dep_weight); + CU_ASSERT(0 == e->sum_dep_weight); + CU_ASSERT(0 == f->sum_dep_weight); + nghttp2_stream_dep_remove(c); /* becomes: @@ -5100,6 +5081,15 @@ void test_nghttp2_session_stream_dep_remove(void) 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); + CU_ASSERT(0 == b->sum_dep_weight); + CU_ASSERT(0 == c->sum_dep_weight); + CU_ASSERT(0 == d->sum_dep_weight); + CU_ASSERT(0 == e->sum_dep_weight); + CU_ASSERT(0 == f->sum_dep_weight); + check_stream_dep_sib(a, NULL, b, NULL, NULL); check_stream_dep_sib(b, a, NULL, NULL, e); check_stream_dep_sib(c, NULL, NULL, NULL, NULL); @@ -5153,6 +5143,13 @@ void test_nghttp2_session_stream_dep_add_subtree(void) 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); + CU_ASSERT(0 == d->sum_dep_weight); + CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == e->sum_dep_weight); + CU_ASSERT(0 == f->sum_dep_weight); + check_stream_dep_sib(a, NULL, b, NULL, NULL); check_stream_dep_sib(b, a, NULL, NULL, c); check_stream_dep_sib(c, NULL, d, b, e); @@ -5160,9 +5157,6 @@ void test_nghttp2_session_stream_dep_add_subtree(void) check_stream_dep_sib(e, NULL, f, c, NULL); check_stream_dep_sib(f, e, NULL, NULL, NULL); - CU_ASSERT(a->stream_group == e->stream_group); - CU_ASSERT(a->stream_group == f->stream_group); - nghttp2_session_del(session); /* dep_stream has dep_next and now we insert subtree */ @@ -5202,6 +5196,13 @@ void test_nghttp2_session_stream_dep_add_subtree(void) 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); + CU_ASSERT(0 == d->sum_dep_weight); + 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(e, a, f, NULL, NULL); check_stream_dep_sib(f, e, NULL, NULL, b); @@ -5209,9 +5210,6 @@ void test_nghttp2_session_stream_dep_add_subtree(void) check_stream_dep_sib(c, NULL, d, b, NULL); check_stream_dep_sib(d, c, NULL, NULL, NULL); - CU_ASSERT(a->stream_group == e->stream_group); - CU_ASSERT(a->stream_group == f->stream_group); - nghttp2_session_del(session); } @@ -5251,6 +5249,11 @@ void test_nghttp2_session_stream_dep_remove_subtree(void) 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(b, a, NULL, NULL, NULL); check_stream_dep_sib(c, NULL, d, NULL, NULL); @@ -5288,6 +5291,11 @@ void test_nghttp2_session_stream_dep_remove_subtree(void) 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(c, a, d, NULL, NULL); check_stream_dep_sib(d, c, NULL, NULL, NULL); @@ -5325,6 +5333,12 @@ void test_nghttp2_session_stream_dep_remove_subtree(void) 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(b, a, NULL, NULL, e); check_stream_dep_sib(e, NULL, NULL, b, NULL); @@ -5379,12 +5393,6 @@ void test_nghttp2_session_stream_attach_data(void) CU_ASSERT(1 == db->queued); - CU_ASSERT(1 == a->stream_group->num_top); - CU_ASSERT(1 == a->num_subtop); - CU_ASSERT(1 == b->num_subtop); - CU_ASSERT(0 == c->num_subtop); - CU_ASSERT(0 == d->num_subtop); - dc = create_data_ob_item(); nghttp2_stream_attach_data(c, dc, &session->ob_pq); @@ -5396,12 +5404,6 @@ void test_nghttp2_session_stream_attach_data(void) CU_ASSERT(1 == dc->queued); - CU_ASSERT(2 == a->stream_group->num_top); - CU_ASSERT(2 == a->num_subtop); - CU_ASSERT(1 == b->num_subtop); - CU_ASSERT(1 == c->num_subtop); - CU_ASSERT(0 == d->num_subtop); - da = create_data_ob_item(); nghttp2_stream_attach_data(a, da, &session->ob_pq); @@ -5413,12 +5415,6 @@ void test_nghttp2_session_stream_attach_data(void) CU_ASSERT(1 == da->queued); - CU_ASSERT(1 == a->stream_group->num_top); - CU_ASSERT(1 == a->num_subtop); - CU_ASSERT(0 == b->num_subtop); - CU_ASSERT(0 == c->num_subtop); - CU_ASSERT(0 == d->num_subtop); - nghttp2_stream_detach_data(a, &session->ob_pq); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); @@ -5426,12 +5422,6 @@ void test_nghttp2_session_stream_attach_data(void) CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == d->dpri); - CU_ASSERT(2 == a->stream_group->num_top); - CU_ASSERT(2 == a->num_subtop); - CU_ASSERT(1 == b->num_subtop); - CU_ASSERT(1 == c->num_subtop); - CU_ASSERT(0 == d->num_subtop); - dd = create_data_ob_item(); nghttp2_stream_attach_data(d, dd, &session->ob_pq); @@ -5443,12 +5433,6 @@ void test_nghttp2_session_stream_attach_data(void) CU_ASSERT(0 == dd->queued); - CU_ASSERT(2 == a->stream_group->num_top); - CU_ASSERT(2 == a->num_subtop); - CU_ASSERT(1 == b->num_subtop); - CU_ASSERT(1 == c->num_subtop); - CU_ASSERT(0 == d->num_subtop); - nghttp2_stream_detach_data(c, &session->ob_pq); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); @@ -5458,12 +5442,6 @@ void test_nghttp2_session_stream_attach_data(void) CU_ASSERT(1 == dd->queued); - CU_ASSERT(2 == a->stream_group->num_top); - CU_ASSERT(2 == a->num_subtop); - CU_ASSERT(1 == b->num_subtop); - CU_ASSERT(1 == c->num_subtop); - CU_ASSERT(1 == d->num_subtop); - nghttp2_session_del(session); } @@ -5471,11 +5449,9 @@ void test_nghttp2_session_stream_attach_data_subtree(void) { nghttp2_session *session; nghttp2_session_callbacks callbacks; - nghttp2_stream *a, *b, *c, *d, *e, *f, *g, *h; + nghttp2_stream *a, *b, *c, *d, *e, *f; nghttp2_outbound_item *db, *dd, *de; - (void)d; - memset(&callbacks, 0, sizeof(callbacks)); nghttp2_session_server_new(&session, &callbacks, NULL); @@ -5487,8 +5463,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void) e = open_stream(session, 9); f = open_stream_with_dep(session, 11, e); - /* gr.1 gr.9 - * + /* * a e * | | * b--c f @@ -5504,15 +5479,18 @@ void test_nghttp2_session_stream_attach_data_subtree(void) nghttp2_stream_attach_data(b, db, &session->ob_pq); - CU_ASSERT(1 == a->stream_group->num_top); - CU_ASSERT(1 == e->stream_group->num_top); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == c->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == d->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == f->dpri); /* Insert subtree e under a */ nghttp2_stream_dep_insert_subtree(a, e, &session->ob_pq); - /* gr.1 - * + /* * a * | * e @@ -5522,26 +5500,20 @@ void test_nghttp2_session_stream_attach_data_subtree(void) * d */ + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == b->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == c->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == d->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == f->dpri); - CU_ASSERT(1 == a->stream_group->num_top); - CU_ASSERT(1 == a->num_subtop); - CU_ASSERT(1 == e->num_subtop); - CU_ASSERT(0 == f->num_subtop); - CU_ASSERT(0 == b->num_subtop); - CU_ASSERT(0 == c->num_subtop); - CU_ASSERT(0 == d->num_subtop); - /* Remove subtree b */ nghttp2_stream_dep_remove_subtree(b); - nghttp2_stream_dep_make_root(b->stream_group, b, &session->ob_pq); + nghttp2_stream_dep_make_root(b, &session->ob_pq); - /* gr.1 gr.1 - * + /* * a b * | * e @@ -5551,42 +5523,33 @@ void test_nghttp2_session_stream_attach_data_subtree(void) * d */ + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); - - /* a and b are still same group */ - CU_ASSERT(b->stream_group == a->stream_group); - - CU_ASSERT(2 == b->stream_group->num_top); - CU_ASSERT(1 == b->num_subtop); - - CU_ASSERT(2 == a->stream_group->num_top); - CU_ASSERT(1 == a->num_subtop); - CU_ASSERT(1 == e->num_subtop); - CU_ASSERT(0 == f->num_subtop); - CU_ASSERT(0 == c->num_subtop); - CU_ASSERT(0 == d->num_subtop); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == c->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == d->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == f->dpri); /* Remove subtree a */ nghttp2_stream_dep_remove_subtree(a); - nghttp2_stream_dep_make_root(a->stream_group, a, &session->ob_pq); + nghttp2_stream_dep_make_root(a, &session->ob_pq); - CU_ASSERT(2 == a->stream_group->num_top); - CU_ASSERT(1 == a->num_subtop); - CU_ASSERT(1 == e->num_subtop); - CU_ASSERT(0 == f->num_subtop); - CU_ASSERT(0 == c->num_subtop); - CU_ASSERT(0 == d->num_subtop); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == c->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == d->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == f->dpri); /* Remove subtree c */ nghttp2_stream_dep_remove_subtree(c); - nghttp2_stream_dep_make_root(c->stream_group, c, &session->ob_pq); + nghttp2_stream_dep_make_root(c, &session->ob_pq); - /* gr.1 gr.1 gr.1 - * + /* * a b c * | | * e d @@ -5594,28 +5557,22 @@ void test_nghttp2_session_stream_attach_data_subtree(void) * f */ - CU_ASSERT(2 == a->stream_group->num_top); - CU_ASSERT(1 == a->num_subtop); - CU_ASSERT(1 == e->num_subtop); - CU_ASSERT(0 == f->num_subtop); - - CU_ASSERT(0 == c->num_subtop); - CU_ASSERT(0 == d->num_subtop); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == c->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == d->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == f->dpri); dd = create_data_ob_item(); nghttp2_stream_attach_data(d, dd, &session->ob_pq); - CU_ASSERT(3 == a->stream_group->num_top); - CU_ASSERT(1 == c->num_subtop); - CU_ASSERT(1 == d->num_subtop); - /* Add subtree c to a */ nghttp2_stream_dep_add_subtree(a, c, &session->ob_pq); - /* gr.1 gr.1 - * + /* * a b * | * e--c @@ -5623,19 +5580,18 @@ void test_nghttp2_session_stream_attach_data_subtree(void) * f d */ - CU_ASSERT(3 == a->stream_group->num_top); - CU_ASSERT(2 == a->num_subtop); - CU_ASSERT(1 == e->num_subtop); - CU_ASSERT(0 == f->num_subtop); - CU_ASSERT(1 == c->num_subtop); - CU_ASSERT(1 == d->num_subtop); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == c->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == f->dpri); /* Insert b under a */ nghttp2_stream_dep_insert_subtree(a, b, &session->ob_pq); - /* gr.1 - * + /* * a * | * b @@ -5645,24 +5601,17 @@ void test_nghttp2_session_stream_attach_data_subtree(void) * f d */ - CU_ASSERT(1 == a->stream_group->num_top); - CU_ASSERT(1 == a->num_subtop); - CU_ASSERT(1 == b->num_subtop); - CU_ASSERT(0 == e->num_subtop); - CU_ASSERT(0 == f->num_subtop); - CU_ASSERT(0 == c->num_subtop); - CU_ASSERT(0 == d->num_subtop); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == c->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == d->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == e->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == f->dpri); - g = open_stream(session, 13); - h = open_stream(session, 15); + nghttp2_stream_dep_make_root(a, &session->ob_pq); - nghttp2_stream_dep_make_root(a->stream_group, h, &session->ob_pq); - - nghttp2_stream_dep_make_root(g->stream_group, a, &session->ob_pq); - - /* gr.13 gr.13 gr.1 - * - * a g h + /* + * a * | * b * | @@ -5671,39 +5620,254 @@ void test_nghttp2_session_stream_attach_data_subtree(void) * f d */ - CU_ASSERT(g->stream_group == a->stream_group); - - CU_ASSERT(0 == h->stream_group->num_top); - - CU_ASSERT(1 == a->stream_group->num_top); - CU_ASSERT(1 == a->num_subtop); - CU_ASSERT(1 == b->num_subtop); - CU_ASSERT(0 == e->num_subtop); - CU_ASSERT(0 == f->num_subtop); - CU_ASSERT(0 == c->num_subtop); - CU_ASSERT(0 == d->num_subtop); - /* Remove subtree b */ nghttp2_stream_dep_remove_subtree(b); - /* gr.13 gr.13 gr.13 gr.1 - * - * b a g h + /* + * b a * | * e--c * | | * f d */ - CU_ASSERT(1 == b->stream_group->num_top); - CU_ASSERT(1 == b->num_subtop); - CU_ASSERT(0 == e->num_subtop); - CU_ASSERT(0 == f->num_subtop); - CU_ASSERT(0 == c->num_subtop); - CU_ASSERT(0 == d->num_subtop); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == a->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == c->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == d->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == e->dpri); + CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == f->dpri); - CU_ASSERT(0 == a->num_subtop); + nghttp2_session_del(session); +} + +void test_nghttp2_session_stream_dep_effective_weight(void) +{ + nghttp2_session *session; + nghttp2_session_callbacks callbacks; + nghttp2_stream *a, *b, *c, *d, *e, *f, *g; + + memset(&callbacks, 0, sizeof(callbacks)); + + nghttp2_session_server_new(&session, &callbacks, NULL); + + a = open_stream(session, 1); + b = open_stream_with_dep_weight(session, 3, 8, a); + c = open_stream_with_dep_weight(session, 5, 4, a); + d = open_stream_with_dep_weight(session, 7, 1, c); + e = open_stream_with_dep_weight(session, 9, 2, c); + + /* a + * | + * b--c + * | + * d--e + */ + + CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->effective_weight); + CU_ASSERT(16 * 8 / 12 == b->effective_weight); + CU_ASSERT(16 * 4 / 12 == c->effective_weight); + CU_ASSERT((16 * 4 / 12) * 1 / 3 == d->effective_weight); + CU_ASSERT((16 * 4 / 12) * 2 / 3 == e->effective_weight); + + /* Remove a */ + + nghttp2_stream_dep_remove(a); + + /* + * b c + * | + * d--e + */ + + CU_ASSERT(16 * 8 / 12 == b->effective_weight); + CU_ASSERT(16 * 4 / 12 == c->effective_weight); + CU_ASSERT((16 * 4 / 12) * 1 / 3 == d->effective_weight); + CU_ASSERT((16 * 4 / 12) * 2 / 3 == e->effective_weight); + + /* weight is updated for b and c */ + CU_ASSERT(16 * 8 / 12 == b->weight); + CU_ASSERT(16 * 4 / 12 == c->weight); + /* weight remains same for d and e */ + CU_ASSERT(1 == d->weight); + CU_ASSERT(2 == e->weight); + + /* Remove d */ + + nghttp2_stream_dep_remove(d); + + /* + * c d + * | + * e + */ + + CU_ASSERT(16 * 4 / 12 == c->effective_weight); + CU_ASSERT(16 * 4 / 12 == e->effective_weight); + + nghttp2_session_del(session); + + nghttp2_session_server_new(&session, &callbacks, NULL); + + a = open_stream(session, 1); + b = open_stream_with_dep_weight(session, 3, 8, a); + c = open_stream_with_dep_weight(session, 5, 4, a); + d = open_stream_with_dep_weight(session, 7, 1, c); + e = open_stream_with_dep_weight(session, 9, 2, c); + + /* a + * | + * b--c + * | + * d--e + */ + + /* Remove c */ + + nghttp2_stream_dep_remove(c); + + /* a + * | + * b--d--e + */ + + /* weight for d and e is updated */ + CU_ASSERT(1/*4 * 1 / 3*/ == d->weight); + CU_ASSERT(4 * 2 / 3 == e->weight); + + CU_ASSERT(16 * 8 / 11 == b->effective_weight); + CU_ASSERT(16 * 1 / 11 == d->effective_weight); + CU_ASSERT(16 * 2 / 11 == e->effective_weight); + + nghttp2_session_del(session); + + nghttp2_session_server_new(&session, &callbacks, NULL); + + a = open_stream(session, 1); + b = open_stream_with_dep_weight(session, 3, 8, a); + c = open_stream_with_dep_weight(session, 5, 4, a); + d = open_stream_with_dep_weight(session, 7, 1, c); + e = open_stream_with_dep_weight(session, 9, 2, c); + + /* a + * | + * b--c + * | + * d--e + */ + + /* Insert f under a */ + f = open_stream_with_dep_excl(session, 11, a); + + /* a + * | + * f + * | + * b--c + * | + * d--e + */ + + CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->effective_weight); + CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == f->effective_weight); + CU_ASSERT(16 * 8 / 12 == b->effective_weight); + CU_ASSERT(16 * 4 / 12 == c->effective_weight); + CU_ASSERT((16 * 4 / 12) * 1 / 3 == d->effective_weight); + CU_ASSERT((16 * 4 / 12) * 2 / 3 == e->effective_weight); + + /* Add g under f */ + g = open_stream_with_dep_weight(session, 13, 2, f); + + /* a + * | + * f + * | + * b--c--g + * | + * d--e + */ + + CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->effective_weight); + CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == f->effective_weight); + CU_ASSERT(16 * 8 / 14 == b->effective_weight); + CU_ASSERT(16 * 4 / 14 == c->effective_weight); + CU_ASSERT(16 * 2 / 14 == g->effective_weight); + CU_ASSERT((16 * 4 / 14) * 1 / 3 == d->effective_weight); + CU_ASSERT((16 * 4 / 14) * 2 / 3 == e->effective_weight); + + nghttp2_session_del(session); + + nghttp2_session_server_new(&session, &callbacks, NULL); + + a = open_stream(session, 1); + b = open_stream_with_dep_weight(session, 3, 8, a); + c = open_stream_with_dep_weight(session, 5, 4, a); + d = open_stream_with_dep_weight(session, 7, 1, c); + + e = open_stream(session, 9); + f = open_stream_with_dep_weight(session, 11, 12, e); + + /* a e + * | | + * b--c f + * | + * d + */ + + /* Insert e under a */ + nghttp2_stream_dep_insert_subtree(a, e, &session->ob_pq); + + /* a + * | + * e + * | + * b--c--f + * | + * d + */ + + CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == e->effective_weight); + CU_ASSERT(16 * 8 / 24 == b->effective_weight); + CU_ASSERT(16 * 4 / 24 == c->effective_weight); + CU_ASSERT(16 * 12 / 24 == f->effective_weight); + CU_ASSERT(16 * 4 / 24 == d->effective_weight); + + /* Remove subtree c */ + nghttp2_stream_dep_remove_subtree(c); + nghttp2_stream_dep_make_root(c, &session->ob_pq); + + /* a c + * | | + * e d + * | + * b--f + */ + + CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == e->effective_weight); + CU_ASSERT(16 * 8 / 20 == b->effective_weight); + CU_ASSERT(16 * 12 / 20 == f->effective_weight); + + CU_ASSERT(4 == c->effective_weight); + CU_ASSERT(4 == d->effective_weight); + + /* Add subtree c under a */ + nghttp2_stream_dep_add_subtree(a, c, &session->ob_pq); + + /* a + * | + * e-----c + * | | + * b--f d + */ + + CU_ASSERT(16 * 16 / 20 == e->effective_weight); + CU_ASSERT(16 * 4 / 20 == c->effective_weight); + + CU_ASSERT((16 * 16 / 20) * 8 / 20 == b->effective_weight); + CU_ASSERT((16 * 16 / 20) * 12 / 20 == f->effective_weight); + + CU_ASSERT(16 * 4 / 20 == d->effective_weight); nghttp2_session_del(session); } diff --git a/tests/nghttp2_session_test.h b/tests/nghttp2_session_test.h index 0ed4a1f9..f65e6b36 100644 --- a/tests/nghttp2_session_test.h +++ b/tests/nghttp2_session_test.h @@ -105,6 +105,7 @@ void test_nghttp2_session_stream_dep_add_subtree(void); void test_nghttp2_session_stream_dep_remove_subtree(void); void test_nghttp2_session_stream_attach_data(void); void test_nghttp2_session_stream_attach_data_subtree(void); +void test_nghttp2_session_stream_dep_effective_weight(void); void test_nghttp2_session_keep_closed_stream(void); #endif /* NGHTTP2_SESSION_TEST_H */ diff --git a/tests/nghttp2_test_helper.c b/tests/nghttp2_test_helper.c index faea0a56..fc00f401 100644 --- a/tests/nghttp2_test_helper.c +++ b/tests/nghttp2_test_helper.c @@ -236,8 +236,7 @@ nghttp2_stream* open_stream(nghttp2_session *session, int32_t stream_id) { nghttp2_priority_spec pri_spec; - nghttp2_priority_spec_group_init(&pri_spec, stream_id, - NGHTTP2_DEFAULT_WEIGHT); + nghttp2_priority_spec_default_init(&pri_spec); return nghttp2_session_open_stream(session, stream_id, NGHTTP2_STREAM_FLAG_NONE, @@ -249,10 +248,19 @@ nghttp2_stream* open_stream(nghttp2_session *session, int32_t stream_id) nghttp2_stream* open_stream_with_dep(nghttp2_session *session, int32_t stream_id, nghttp2_stream *dep_stream) +{ + return open_stream_with_dep_weight(session, stream_id, + NGHTTP2_DEFAULT_WEIGHT, dep_stream); +} + +nghttp2_stream* open_stream_with_dep_weight(nghttp2_session *session, + int32_t stream_id, + int32_t weight, + nghttp2_stream *dep_stream) { nghttp2_priority_spec pri_spec; - nghttp2_priority_spec_dep_init(&pri_spec, dep_stream->stream_id, 0); + nghttp2_priority_spec_init(&pri_spec, dep_stream->stream_id, weight, 0); return nghttp2_session_open_stream(session, stream_id, NGHTTP2_STREAM_FLAG_NONE, @@ -267,7 +275,8 @@ nghttp2_stream* open_stream_with_dep_excl(nghttp2_session *session, { nghttp2_priority_spec pri_spec; - nghttp2_priority_spec_dep_init(&pri_spec, dep_stream->stream_id, 1); + nghttp2_priority_spec_init(&pri_spec, dep_stream->stream_id, + NGHTTP2_DEFAULT_WEIGHT, 1); return nghttp2_session_open_stream(session, stream_id, NGHTTP2_STREAM_FLAG_NONE, diff --git a/tests/nghttp2_test_helper.h b/tests/nghttp2_test_helper.h index 956a0cd9..27b2c801 100644 --- a/tests/nghttp2_test_helper.h +++ b/tests/nghttp2_test_helper.h @@ -89,6 +89,11 @@ nghttp2_stream* open_stream_with_dep(nghttp2_session *session, int32_t stream_id, nghttp2_stream *dep_stream); +nghttp2_stream* open_stream_with_dep_weight(nghttp2_session *session, + int32_t stream_id, + int32_t weight, + nghttp2_stream *dep_stream); + nghttp2_stream* open_stream_with_dep_excl(nghttp2_session *session, int32_t stream_id, nghttp2_stream *dep_stream); From aa4d43f31e9f4cc235aa18b1d1c0b83c1ba972a1 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Thu, 17 Apr 2014 21:15:14 +0900 Subject: [PATCH 2/5] Allow exclusive dependency to stream 0 --- lib/includes/nghttp2/nghttp2.h | 2 - lib/nghttp2_priority_spec.c | 4 +- lib/nghttp2_session.c | 43 ++++++- lib/nghttp2_session.h | 1 + lib/nghttp2_stream.c | 157 ++++++++++++++++++++++++ lib/nghttp2_stream.h | 47 ++++++++ lib/nghttp2_submit.c | 4 - tests/main.c | 2 + tests/nghttp2_session_test.c | 210 +++++++++++++++++++++++++++++++-- tests/nghttp2_session_test.h | 1 + 10 files changed, 446 insertions(+), 25 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 6cae2f78..038030aa 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -2105,8 +2105,6 @@ void nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec); * @function * * Returns nonzero if the |pri_spec| is filled with default values. - * `pri_spec->exclusive` is ignored since it is irrelevant when - * `pri_spec->stream_id == 0`. */ int nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec); diff --git a/lib/nghttp2_priority_spec.c b/lib/nghttp2_priority_spec.c index 6e6dcb24..778088fc 100644 --- a/lib/nghttp2_priority_spec.c +++ b/lib/nghttp2_priority_spec.c @@ -42,7 +42,7 @@ void nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec) int nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec) { - /* Ignore exclusive flag */ return pri_spec->stream_id == 0 && - pri_spec->weight == NGHTTP2_DEFAULT_WEIGHT; + pri_spec->weight == NGHTTP2_DEFAULT_WEIGHT && + pri_spec->exclusive == 0; } diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index e2323b23..ea50843d 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -280,6 +280,8 @@ static int nghttp2_session_new(nghttp2_session **session_ptr, goto fail_map; } + nghttp2_stream_roots_init(&(*session_ptr)->roots); + (*session_ptr)->next_seq = 0; (*session_ptr)->remote_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE; @@ -436,6 +438,8 @@ void nghttp2_session_del(nghttp2_session *session) } free(session->inflight_iv); + nghttp2_stream_roots_free(&session->roots); + /* Have to free streams first, so that we can check stream->data_item->queued */ nghttp2_map_each_free(&session->streams, nghttp2_free_streams, NULL); @@ -470,14 +474,21 @@ int nghttp2_session_reprioritize_stream /* We have to update weight after removing stream from tree */ stream->weight = pri_spec->weight; - rv = nghttp2_stream_dep_make_root(stream, &session->ob_pq); + 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->ob_pq); + } else { + rv = nghttp2_stream_dep_make_root(stream, &session->ob_pq); + } return rv; } dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id); - if(dep_stream == NULL) { + if(!dep_stream || !nghttp2_stream_in_dep_tree(dep_stream)) { return 0; } @@ -711,7 +722,7 @@ nghttp2_stream* nghttp2_session_open_stream(nghttp2_session *session, } nghttp2_stream_init(stream, stream_id, flags, initial_state, - pri_spec->weight, + pri_spec->weight, &session->roots, session->remote_settings [NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE], session->local_settings @@ -747,9 +758,29 @@ 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->ob_pq); + + /* 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; + } + dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id); - if(!dep_stream) { + /* If dep_stream is not part of dependency tree, we don't use it. */ + if(!dep_stream || !nghttp2_stream_in_dep_tree(dep_stream)) { return stream; } @@ -831,7 +862,9 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id, /* Closes both directions just in case they are not closed yet */ stream->flags |= NGHTTP2_STREAM_FLAG_CLOSED; - if(session->server && !nghttp2_session_is_my_stream_id(session, stream_id)) { + if(session->server && + nghttp2_stream_in_dep_tree(stream) && + !nghttp2_session_is_my_stream_id(session, stream_id)) { /* On server side, retain incoming stream object at most MAX_CONCURRENT_STREAMS combined with the current active streams to make dependency tree work better. */ diff --git a/lib/nghttp2_session.h b/lib/nghttp2_session.h index 21f728e5..bcdb0467 100644 --- a/lib/nghttp2_session.h +++ b/lib/nghttp2_session.h @@ -117,6 +117,7 @@ typedef enum { struct nghttp2_session { nghttp2_map /* */ streams; + nghttp2_stream_roots roots; /* Queue for outbound frames other than stream-creating HEADERS */ nghttp2_pq /* */ ob_pq; /* Queue for outbound stream-creating HEADERS frame */ diff --git a/lib/nghttp2_stream.c b/lib/nghttp2_stream.c index aafa35d4..fdda4e82 100644 --- a/lib/nghttp2_stream.c +++ b/lib/nghttp2_stream.c @@ -33,6 +33,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 local_initial_window_size, void *stream_user_data) @@ -61,6 +62,10 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, stream->weight = weight; stream->effective_weight = stream->weight; stream->sum_dep_weight = 0; + + stream->roots = roots; + stream->root_prev = NULL; + stream->root_next = NULL; } void nghttp2_stream_free(nghttp2_stream *stream) @@ -474,6 +479,8 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, stream_update_dep_length(dep_stream, 1); stream_update_dep_effective_weight(dep_stream); + + ++stream->roots->num_streams; } void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, @@ -502,6 +509,8 @@ void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, } stream_update_dep_effective_weight(dep_stream); + + ++stream->roots->num_streams; } void nghttp2_stream_dep_remove(nghttp2_stream *stream) @@ -568,6 +577,8 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream) dep_next = NULL; } } else { + nghttp2_stream_roots_remove(stream->roots, stream); + dep_next = NULL; /* stream is a root of tree. Removing stream makes its @@ -583,6 +594,8 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream) /* We already distributed weight of |stream| to this. */ si->effective_weight = si->weight; + nghttp2_stream_roots_add(si->roots, si); + si = next; } } @@ -606,6 +619,8 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream) stream->dep_next = NULL; stream->sib_prev = NULL; stream->sib_next = NULL; + + --stream->roots->num_streams; } int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, @@ -748,6 +763,8 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) } } else { + nghttp2_stream_roots_remove(stream->roots, stream); + dep_prev = NULL; } @@ -771,6 +788,8 @@ int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq) DEBUGF(fprintf(stderr, "stream: dep_make_root stream(%p)=%d\n", stream, stream->stream_id)); + nghttp2_stream_roots_add(stream->roots, stream); + stream_update_dep_set_rest(stream); stream->effective_weight = stream->weight; @@ -785,3 +804,141 @@ int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq) return 0; } + +int nghttp2_stream_dep_all_your_stream_are_belong_to_us +(nghttp2_stream *stream, nghttp2_pq *pq) +{ + 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; + + 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)); + + fprintf(stderr, "w=%d, sum=%d\n", + si->weight, stream->sum_dep_weight); + stream->sum_dep_weight += si->weight; + stream->num_substreams += si->num_substreams; + + si->sib_prev = prev; + prev->sib_next = si; + + prev = si; + } + + if(stream->dep_next) { + nghttp2_stream *last_sib; + + last_sib = stream_last_sib(stream->dep_next); + + last_sib->sib_next = first; + first->sib_prev = last_sib; + } else { + stream->dep_next = first; + first->dep_prev = stream; + } + } + + nghttp2_stream_roots_remove_all(stream->roots); + + return nghttp2_stream_dep_make_root(stream, pq); +} + +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) +{} + +void nghttp2_stream_roots_add(nghttp2_stream_roots *roots, + nghttp2_stream *stream) +{ + if(roots->head) { + nghttp2_stream *si; + for(si = roots->head; si; si = si->root_next) { + if(si == stream) { + assert(0); + } + } + + 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; +} diff --git a/lib/nghttp2_stream.h b/lib/nghttp2_stream.h index 05a4f52c..5c2fbced 100644 --- a/lib/nghttp2_stream.h +++ b/lib/nghttp2_stream.h @@ -102,6 +102,10 @@ typedef enum { NGHTTP2_STREAM_DPRI_REST = 0x04 } nghttp2_stream_dpri; +struct nghttp2_stream_roots; + +typedef struct nghttp2_stream_roots nghttp2_stream_roots; + struct nghttp2_stream; typedef struct nghttp2_stream nghttp2_stream; @@ -118,11 +122,17 @@ 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 single 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_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; /* DATA frame item */ @@ -165,6 +175,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 local_initial_window_size, void *stream_user_data); @@ -380,4 +391,40 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream); */ int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq); +/* + * 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_pq *pq); + +/* + * 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/lib/nghttp2_submit.c b/lib/nghttp2_submit.c index fc6a0c31..23b8de1a 100644 --- a/lib/nghttp2_submit.c +++ b/lib/nghttp2_submit.c @@ -103,10 +103,6 @@ static int nghttp2_submit_headers_shared static void adjust_priority_spec_weight(nghttp2_priority_spec *pri_spec) { - if(pri_spec->stream_id == 0) { - pri_spec->exclusive = 0; - } - if(pri_spec->weight < NGHTTP2_MIN_WEIGHT) { pri_spec->weight = NGHTTP2_MIN_WEIGHT; } else if(pri_spec->weight > NGHTTP2_MAX_WEIGHT) { diff --git a/tests/main.c b/tests/main.c index 0335a713..3cca7ac6 100644 --- a/tests/main.c +++ b/tests/main.c @@ -222,6 +222,8 @@ int main(int argc, char* argv[]) test_nghttp2_session_stream_dep_add_subtree) || !CU_add_test(pSuite, "session_stream_dep_remove_subtree", test_nghttp2_session_stream_dep_remove_subtree) || + !CU_add_test(pSuite, "session_stream_dep_all_your_stream_are_belong_to_us", + test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us) || !CU_add_test(pSuite, "session_stream_attach_data", test_nghttp2_session_stream_attach_data) || !CU_add_test(pSuite, "session_stream_attach_data_subtree", diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 30f5e8f4..647864a2 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -4873,6 +4873,10 @@ void test_nghttp2_session_stream_dep_add(void) check_stream_dep_sib(c, NULL, 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); + e = open_stream_with_dep_excl(session, 9, a); /* a @@ -4902,6 +4906,10 @@ void test_nghttp2_session_stream_dep_add(void) check_stream_dep_sib(c, NULL, 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); + nghttp2_session_del(session); } @@ -4951,6 +4959,11 @@ void test_nghttp2_session_stream_dep_remove(void) check_stream_dep_sib(c, NULL, d, NULL, NULL); check_stream_dep_sib(d, c, NULL, NULL, NULL); + CU_ASSERT(3 == session->roots.num_streams); + CU_ASSERT(c == session->roots.head); + CU_ASSERT(b == c->root_next); + CU_ASSERT(NULL == b->root_next); + nghttp2_session_del(session); /* Remove left most stream */ @@ -4993,6 +5006,10 @@ void test_nghttp2_session_stream_dep_remove(void) 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); + nghttp2_session_del(session); /* Remove right most stream */ @@ -5348,6 +5365,131 @@ void test_nghttp2_session_stream_dep_remove_subtree(void) nghttp2_session_del(session); } +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; + + memset(&callbacks, 0, sizeof(callbacks)); + + nghttp2_session_server_new(&session, &callbacks, NULL); + + a = open_stream(session, 1); + b = open_stream_with_dep(session, 3, a); + + c = open_stream(session, 5); + + /* a c + * | + * b + */ + + nghttp2_stream_dep_remove_subtree(c); + CU_ASSERT(0 == nghttp2_stream_dep_all_your_stream_are_belong_to_us + (c, &session->ob_pq)); + + /* + * c + * | + * a + * | + * 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); + + check_stream_dep_sib(c, NULL, a, NULL, NULL); + check_stream_dep_sib(a, c, b, NULL, NULL); + check_stream_dep_sib(b, a, NULL, NULL, NULL); + + nghttp2_session_del(session); + + nghttp2_session_server_new(&session, &callbacks, NULL); + + a = open_stream(session, 1); + + b = open_stream(session, 3); + + c = open_stream(session, 5); + + /* + * a b c + */ + + nghttp2_stream_dep_remove_subtree(c); + CU_ASSERT(0 == nghttp2_stream_dep_all_your_stream_are_belong_to_us + (c, &session->ob_pq)); + + /* + * c + * | + * 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); + + check_stream_dep_sib(c, NULL, b, NULL, NULL); + check_stream_dep_sib(b, c, NULL, NULL, a); + check_stream_dep_sib(a, NULL, NULL, b, NULL); + + nghttp2_session_del(session); + + nghttp2_session_server_new(&session, &callbacks, NULL); + + a = open_stream(session, 1); + b = open_stream_with_dep(session, 3, a); + + c = open_stream(session, 5); + d = open_stream_with_dep(session, 7, c); + + /* a c + * | | + * b d + */ + + nghttp2_stream_dep_remove_subtree(c); + CU_ASSERT(0 == nghttp2_stream_dep_all_your_stream_are_belong_to_us + (c, &session->ob_pq)); + + /* + * c + * | + * 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); + CU_ASSERT(0 == b->sum_dep_weight); + + check_stream_dep_sib(c, NULL, d, NULL, NULL); + check_stream_dep_sib(d, c, NULL, NULL, a); + check_stream_dep_sib(a, NULL, b, d, NULL); + check_stream_dep_sib(b, a, NULL, NULL, NULL); + + nghttp2_session_del(session); +} + static nghttp2_outbound_item* create_data_ob_item(void) { nghttp2_outbound_item *item; @@ -5488,6 +5630,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void) /* Insert subtree e under a */ + nghttp2_stream_dep_remove_subtree(e); nghttp2_stream_dep_insert_subtree(a, e, &session->ob_pq); /* @@ -5570,6 +5713,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void) /* Add subtree c to a */ + nghttp2_stream_dep_remove_subtree(c); nghttp2_stream_dep_add_subtree(a, c, &session->ob_pq); /* @@ -5589,6 +5733,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void) /* Insert b under a */ + nghttp2_stream_dep_remove_subtree(b); nghttp2_stream_dep_insert_subtree(a, b, &session->ob_pq); /* @@ -5608,21 +5753,10 @@ void test_nghttp2_session_stream_attach_data_subtree(void) CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == f->dpri); - nghttp2_stream_dep_make_root(a, &session->ob_pq); - - /* - * a - * | - * b - * | - * e--c - * | | - * f d - */ - /* Remove subtree b */ nghttp2_stream_dep_remove_subtree(b); + nghttp2_stream_dep_make_root(b, &session->ob_pq); /* * b a @@ -5870,6 +6004,58 @@ void test_nghttp2_session_stream_dep_effective_weight(void) CU_ASSERT(16 * 4 / 20 == d->effective_weight); nghttp2_session_del(session); + + nghttp2_session_server_new(&session, &callbacks, NULL); + + a = open_stream(session, 1); + b = open_stream_with_dep_weight(session, 3, 8, a); + c = open_stream_with_dep_weight(session, 5, 4, a); + d = open_stream_with_dep_weight(session, 7, 1, c); + + e = open_stream(session, 9); + f = open_stream_with_dep_weight(session, 11, 12, e); + + /* a e + * | | + * b--c f + * | + * d + */ + + CU_ASSERT(e->roots->head == e); + CU_ASSERT(a == e->root_next); + + /* Insert e under stream 0 */ + nghttp2_stream_dep_remove_subtree(e); + + CU_ASSERT(a == e->roots->head); + + CU_ASSERT(0 == nghttp2_stream_dep_all_your_stream_are_belong_to_us + (e, &session->ob_pq)); + + /* e + * | + * f--a + * | + * b--c + * | + * d + */ + + CU_ASSERT(6 == e->num_substreams); + CU_ASSERT(28 == e->sum_dep_weight); + + CU_ASSERT(16 == e->effective_weight); + + CU_ASSERT(16 * 16 / 28 == a->effective_weight); + CU_ASSERT(16 * 12 / 28 == f->effective_weight); + + CU_ASSERT((16 * 16 / 28) * 8 / 12 == b->effective_weight); + CU_ASSERT((16 * 16 / 28) * 4 / 12 == c->effective_weight); + + CU_ASSERT((16 * 16 / 28) * 4 / 12 == d->effective_weight); + + nghttp2_session_del(session); } void test_nghttp2_session_keep_closed_stream(void) diff --git a/tests/nghttp2_session_test.h b/tests/nghttp2_session_test.h index f65e6b36..e6bac7bf 100644 --- a/tests/nghttp2_session_test.h +++ b/tests/nghttp2_session_test.h @@ -103,6 +103,7 @@ void test_nghttp2_session_stream_dep_add(void); void test_nghttp2_session_stream_dep_remove(void); void test_nghttp2_session_stream_dep_add_subtree(void); void test_nghttp2_session_stream_dep_remove_subtree(void); +void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void); void test_nghttp2_session_stream_attach_data(void); void test_nghttp2_session_stream_attach_data_subtree(void); void test_nghttp2_session_stream_dep_effective_weight(void); From 1c1843297ce8b134cb8ec78c1c5a0f479a9c9d76 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Thu, 17 Apr 2014 21:27:56 +0900 Subject: [PATCH 3/5] priority: Add tests --- tests/nghttp2_session_test.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 647864a2..99114231 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -2551,6 +2551,7 @@ void test_nghttp2_session_reprioritize_stream(void) nghttp2_session_callbacks callbacks; my_user_data ud; nghttp2_stream *stream; + nghttp2_stream *dep_stream; nghttp2_priority_spec pri_spec; memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); @@ -2569,6 +2570,30 @@ void test_nghttp2_session_reprioritize_stream(void) CU_ASSERT(10 == stream->weight); CU_ASSERT(NULL == stream->dep_prev); + /* dep_stream does not exist */ + + nghttp2_priority_spec_init(&pri_spec, 3, 99, 0); + + nghttp2_session_reprioritize_stream(session, stream, &pri_spec); + + CU_ASSERT(10 == stream->weight); + CU_ASSERT(NULL == stream->dep_prev); + + dep_stream = open_stream(session, 3); + + nghttp2_session_reprioritize_stream(session, stream, &pri_spec); + + CU_ASSERT(99 == stream->weight); + CU_ASSERT(dep_stream == stream->dep_prev); + + /* Test circular dependency; must be ignored */ + nghttp2_priority_spec_init(&pri_spec, 1, 1, 0); + + nghttp2_session_reprioritize_stream(session, dep_stream, &pri_spec); + + CU_ASSERT(16 == dep_stream->weight); + CU_ASSERT(NULL == dep_stream->dep_prev); + nghttp2_session_del(session); } @@ -3571,6 +3596,14 @@ void test_nghttp2_session_open_stream(void) CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight); CU_ASSERT(NGHTTP2_SHUT_RD == stream->shut_flags); + nghttp2_priority_spec_init(&pri_spec, 1, 17, 1); + + stream = nghttp2_session_open_stream(session, 3, NGHTTP2_STREAM_FLAG_NONE, + &pri_spec, NGHTTP2_STREAM_OPENED, + NULL); + CU_ASSERT(17 == stream->weight); + CU_ASSERT(1 == stream->dep_prev->stream_id); + nghttp2_session_del(session); nghttp2_session_client_new(&session, &callbacks, NULL); From 853c9888d9676939db538be805a81bff8143bca4 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Thu, 24 Apr 2014 23:37:40 +0900 Subject: [PATCH 4/5] Distribute effective weight among only streams with marked as top If stream with dpri value of no_data, we check any its descendant has stream with dpri value of top. If so, we have to distribute of its portion of weight to its descendants. --- lib/nghttp2_stream.c | 151 ++++++++++------ lib/nghttp2_stream.h | 4 + tests/main.c | 2 - tests/nghttp2_session_test.c | 334 +++++------------------------------ tests/nghttp2_session_test.h | 1 - tests/nghttp2_test_helper.c | 60 ++++--- tests/nghttp2_test_helper.h | 2 + 7 files changed, 180 insertions(+), 374 deletions(-) diff --git a/lib/nghttp2_stream.c b/lib/nghttp2_stream.c index fdda4e82..0e771710 100644 --- a/lib/nghttp2_stream.c +++ b/lib/nghttp2_stream.c @@ -62,6 +62,7 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, stream->weight = weight; stream->effective_weight = stream->weight; stream->sum_dep_weight = 0; + stream->sum_norest_weight = 0; stream->roots = roots; stream->root_prev = NULL; @@ -144,7 +145,7 @@ int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream, int32_t nghttp2_stream_dep_distributed_effective_weight (nghttp2_stream *stream, int32_t weight) { - weight = stream->effective_weight * weight / stream->sum_dep_weight; + weight = stream->effective_weight * weight / stream->sum_norest_weight; return nghttp2_max(1, weight); } @@ -157,12 +158,22 @@ static void stream_update_dep_effective_weight(nghttp2_stream *stream) nghttp2_stream *si; DEBUGF(fprintf(stderr, "stream: update_dep_effective_weight " - "stream(%p)=%d, weight=%d\n", - stream, stream->stream_id, stream->weight)); + "stream(%p)=%d, weight=%d, sum_norest_weight=%d\n", + stream, stream->stream_id, stream->weight, + stream->sum_norest_weight)); + + /* stream->sum_norest_weight == 0 means there is no + NGHTTP2_STREAM_DPRI_TOP under stream */ + if(stream->dpri != NGHTTP2_STREAM_DPRI_NO_DATA || + stream->sum_norest_weight == 0) { + return; + } for(si = stream->dep_next; si; si = si->sib_next) { - si->effective_weight = nghttp2_stream_dep_distributed_effective_weight - (stream, si->weight); + if(si->dpri != NGHTTP2_STREAM_DPRI_REST) { + si->effective_weight = nghttp2_stream_dep_distributed_effective_weight + (stream, si->weight); + } stream_update_dep_effective_weight(si); } @@ -203,23 +214,13 @@ static void stream_update_dep_set_rest(nghttp2_stream *stream) static int stream_update_dep_set_top(nghttp2_stream *stream, nghttp2_pq *pq) { int rv; - - if(stream == NULL) { - return 0; - } + nghttp2_stream *si; if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) { - rv = stream_update_dep_set_top(stream->sib_next, pq); - - if(rv != 0) { - return rv; - } - return 0; } if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) { - DEBUGF(fprintf(stderr, "stream: stream=%d data is top\n", stream->stream_id)); @@ -233,32 +234,58 @@ static int stream_update_dep_set_top(nghttp2_stream *stream, nghttp2_pq *pq) stream->dpri = NGHTTP2_STREAM_DPRI_TOP; - rv = stream_update_dep_set_top(stream->sib_next, pq); + return 0; + } + + for(si = stream->dep_next; si; si = si->sib_next) { + rv = stream_update_dep_set_top(si, pq); if(rv != 0) { return rv; } - - return 0; - } - - assert(stream->dpri == NGHTTP2_STREAM_DPRI_NO_DATA); - - rv = stream_update_dep_set_top(stream->sib_next, pq); - - if(rv != 0) { - return rv; - } - - rv = stream_update_dep_set_top(stream->dep_next, pq); - - if(rv != 0) { - return rv; } return 0; } +/* + * Updates stream->sum_norest_weight recursively. We have to gather + * effective sum of weight of descendants. If stream->dpri == + * NGHTTP2_STREAM_DPRI_NO_DATA, we have to go deeper and check that + * any of its descendants has dpri value of NGHTTP2_STREAM_DPRI_TOP. + * If so, we have to add weight of its direct descendants to + * stream->sum_norest_weight. To make this work, this function + * returns 1 if any of its descendants has dpri value of + * NGHTTP2_STREAM_DPRI_TOP, otherwise 0. + */ +static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream) +{ + nghttp2_stream *si; + int rv; + + stream->sum_norest_weight = 0; + + if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) { + return 1; + } + + if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) { + return 0; + } + + rv = 0; + + for(si = stream->dep_next; si; si = si->sib_next) { + + if(stream_update_dep_sum_norest_weight(si)) { + rv = 1; + stream->sum_norest_weight += si->weight; + } + } + + return rv; +} + static int stream_update_dep_on_attach_data(nghttp2_stream *stream, nghttp2_pq *pq) { @@ -279,6 +306,9 @@ static int stream_update_dep_on_attach_data(nghttp2_stream *stream, return rv; } + stream_update_dep_sum_norest_weight(root_stream); + stream_update_dep_effective_weight(root_stream); + return 0; } @@ -288,12 +318,6 @@ static int stream_update_dep_on_detach_data(nghttp2_stream *stream, int rv; nghttp2_stream *root_stream; - if(stream->dpri != NGHTTP2_STREAM_DPRI_TOP) { - stream->dpri = NGHTTP2_STREAM_DPRI_NO_DATA; - - return 0; - } - stream->dpri = NGHTTP2_STREAM_DPRI_NO_DATA; root_stream = nghttp2_stream_get_dep_root(stream); @@ -304,6 +328,9 @@ static int stream_update_dep_on_detach_data(nghttp2_stream *stream, return rv; } + stream_update_dep_sum_norest_weight(root_stream); + stream_update_dep_effective_weight(root_stream); + return 0; } @@ -454,6 +481,7 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, nghttp2_stream *stream) { nghttp2_stream *si; + nghttp2_stream *root_stream; assert(stream->data_item == NULL); @@ -477,8 +505,10 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, dep_stream->dep_next = stream; stream->dep_prev = dep_stream; - stream_update_dep_length(dep_stream, 1); - stream_update_dep_effective_weight(dep_stream); + root_stream = stream_update_dep_length(dep_stream, 1); + + stream_update_dep_sum_norest_weight(root_stream); + stream_update_dep_effective_weight(root_stream); ++stream->roots->num_streams; } @@ -487,6 +517,7 @@ void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, nghttp2_stream *stream) { nghttp2_stream *last_sib; + nghttp2_stream *root_stream; assert(stream->data_item == NULL); @@ -495,7 +526,7 @@ void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, dep_stream, dep_stream->stream_id, stream, stream->stream_id)); - stream_update_dep_length(dep_stream, 1); + root_stream = stream_update_dep_length(dep_stream, 1); dep_stream->sum_dep_weight += stream->weight; @@ -508,16 +539,19 @@ void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, stream->sib_prev = last_sib; } - stream_update_dep_effective_weight(dep_stream); + stream_update_dep_sum_norest_weight(root_stream); + stream_update_dep_effective_weight(root_stream); ++stream->roots->num_streams; } void nghttp2_stream_dep_remove(nghttp2_stream *stream) { - nghttp2_stream *prev, *next, *dep_next, *dep_prev, *si; + nghttp2_stream *prev, *next, *dep_next, *dep_prev, *si, *root_stream; int32_t sum_dep_weight_delta; + root_stream = NULL; + DEBUGF(fprintf(stderr, "stream: dep_remove stream(%p)=%d\n", stream, stream->stream_id)); @@ -535,7 +569,7 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream) dep_prev = prev->dep_prev; if(dep_prev) { - stream_update_dep_length(dep_prev, -1); + root_stream = stream_update_dep_length(dep_prev, -1); dep_prev->sum_dep_weight += sum_dep_weight_delta; } @@ -608,8 +642,9 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream) next->sib_prev = prev; } - if(dep_prev) { - stream_update_dep_effective_weight(dep_prev); + if(root_stream) { + stream_update_dep_sum_norest_weight(root_stream); + stream_update_dep_effective_weight(root_stream); } stream->num_substreams = 1; @@ -675,8 +710,6 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, dep_stream->sum_dep_weight = stream->weight; } - stream_update_dep_effective_weight(dep_stream); - root_stream = stream_update_dep_length(dep_stream, delta_substreams); rv = stream_update_dep_set_top(root_stream, pq); @@ -685,6 +718,9 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, return rv; } + stream_update_dep_sum_norest_weight(root_stream); + stream_update_dep_effective_weight(root_stream); + return 0; } @@ -718,8 +754,6 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, dep_stream->sum_dep_weight = stream->weight; } - stream_update_dep_effective_weight(dep_stream); - root_stream = stream_update_dep_length(dep_stream, stream->num_substreams); rv = stream_update_dep_set_top(root_stream, pq); @@ -728,12 +762,15 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, return rv; } + stream_update_dep_sum_norest_weight(root_stream); + stream_update_dep_effective_weight(root_stream); + return 0; } void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) { - nghttp2_stream *prev, *next, *dep_prev; + nghttp2_stream *prev, *next, *dep_prev, *root_stream; DEBUGF(fprintf(stderr, "stream: dep_remove_subtree stream(%p)=%d\n", stream, stream->stream_id)); @@ -771,9 +808,10 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) if(dep_prev) { dep_prev->sum_dep_weight -= stream->weight; - stream_update_dep_effective_weight(dep_prev); + root_stream = stream_update_dep_length(dep_prev, -stream->num_substreams); - stream_update_dep_length(dep_prev, -stream->num_substreams); + stream_update_dep_sum_norest_weight(root_stream); + stream_update_dep_effective_weight(root_stream); } stream->sib_prev = NULL; @@ -794,14 +832,15 @@ int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq) stream->effective_weight = stream->weight; - stream_update_dep_effective_weight(stream); - rv = stream_update_dep_set_top(stream, pq); if(rv != 0) { return rv; } + stream_update_dep_sum_norest_weight(stream); + stream_update_dep_effective_weight(stream); + return 0; } diff --git a/lib/nghttp2_stream.h b/lib/nghttp2_stream.h index 5c2fbced..e47d7498 100644 --- a/lib/nghttp2_stream.h +++ b/lib/nghttp2_stream.h @@ -164,6 +164,10 @@ struct nghttp2_stream { int32_t effective_weight; /* sum of weight (not effective_weight) of direct descendants */ int32_t sum_dep_weight; + /* sum of weight of direct descendants which have at least one + descendant with dpri == NGHTTP2_STREAM_DPRI_TOP. We use this + value to calculate effective weight. */ + int32_t sum_norest_weight; nghttp2_stream_state state; /* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */ uint8_t flags; diff --git a/tests/main.c b/tests/main.c index 3cca7ac6..723dd333 100644 --- a/tests/main.c +++ b/tests/main.c @@ -228,8 +228,6 @@ int main(int argc, char* argv[]) test_nghttp2_session_stream_attach_data) || !CU_add_test(pSuite, "session_stream_attach_data_subtree", test_nghttp2_session_stream_attach_data_subtree) || - !CU_add_test(pSuite, "session_stream_dep_effective_weight", - test_nghttp2_session_stream_dep_effective_weight) || !CU_add_test(pSuite, "session_stream_keep_closed_stream", test_nghttp2_session_keep_closed_stream) || !CU_add_test(pSuite, "frame_pack_headers", diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 99114231..c16ade27 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -5523,17 +5523,6 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) nghttp2_session_del(session); } -static nghttp2_outbound_item* create_data_ob_item(void) -{ - nghttp2_outbound_item *item; - - item = malloc(sizeof(nghttp2_outbound_item)); - memset(item, 0, sizeof(nghttp2_outbound_item)); - item->frame_cat = NGHTTP2_CAT_DATA; - - return item; -} - void test_nghttp2_session_stream_attach_data(void) { nghttp2_session *session; @@ -5566,6 +5555,10 @@ void test_nghttp2_session_stream_attach_data(void) CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == d->dpri); + CU_ASSERT(16 == b->effective_weight); + + CU_ASSERT(16 == a->sum_norest_weight); + CU_ASSERT(1 == db->queued); dc = create_data_ob_item(); @@ -5577,6 +5570,11 @@ void test_nghttp2_session_stream_attach_data(void) CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == d->dpri); + CU_ASSERT(16 * 16 / 32 == b->effective_weight); + CU_ASSERT(16 * 16 / 32 == c->effective_weight); + + CU_ASSERT(32 == a->sum_norest_weight); + CU_ASSERT(1 == dc->queued); da = create_data_ob_item(); @@ -5588,6 +5586,8 @@ void test_nghttp2_session_stream_attach_data(void) CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == d->dpri); + CU_ASSERT(16 == a->effective_weight); + CU_ASSERT(1 == da->queued); nghttp2_stream_detach_data(a, &session->ob_pq); @@ -5597,6 +5597,9 @@ void test_nghttp2_session_stream_attach_data(void) CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == d->dpri); + CU_ASSERT(16 * 16 / 32 == b->effective_weight); + CU_ASSERT(16 * 16 / 32 == c->effective_weight); + dd = create_data_ob_item(); nghttp2_stream_attach_data(d, dd, &session->ob_pq); @@ -5606,6 +5609,9 @@ void test_nghttp2_session_stream_attach_data(void) CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == d->dpri); + CU_ASSERT(16 * 16 / 32 == b->effective_weight); + CU_ASSERT(16 * 16 / 32 == c->effective_weight); + CU_ASSERT(0 == dd->queued); nghttp2_stream_detach_data(c, &session->ob_pq); @@ -5615,6 +5621,9 @@ void test_nghttp2_session_stream_attach_data(void) CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri); + CU_ASSERT(16 * 16 / 32 == b->effective_weight); + CU_ASSERT(16 * 16 / 32 == d->effective_weight); + CU_ASSERT(1 == dd->queued); nghttp2_session_del(session); @@ -5661,6 +5670,9 @@ void test_nghttp2_session_stream_attach_data_subtree(void) CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == f->dpri); + CU_ASSERT(16 == b->effective_weight); + CU_ASSERT(16 == e->effective_weight); + /* Insert subtree e under a */ nghttp2_stream_dep_remove_subtree(e); @@ -5683,6 +5695,8 @@ void test_nghttp2_session_stream_attach_data_subtree(void) CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == f->dpri); + CU_ASSERT(16 == e->effective_weight); + /* Remove subtree b */ nghttp2_stream_dep_remove_subtree(b); @@ -5706,6 +5720,9 @@ void test_nghttp2_session_stream_attach_data_subtree(void) CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == f->dpri); + CU_ASSERT(16 == b->effective_weight); + CU_ASSERT(16 == e->effective_weight); + /* Remove subtree a */ nghttp2_stream_dep_remove_subtree(a); @@ -5764,6 +5781,13 @@ void test_nghttp2_session_stream_attach_data_subtree(void) CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == f->dpri); + CU_ASSERT(16 == b->effective_weight); + CU_ASSERT(16 * 16 / 32 == e->effective_weight); + CU_ASSERT(16 * 16 / 32 == d->effective_weight); + + CU_ASSERT(32 == a->sum_norest_weight); + CU_ASSERT(16 == c->sum_norest_weight); + /* Insert b under a */ nghttp2_stream_dep_remove_subtree(b); @@ -5786,6 +5810,11 @@ void test_nghttp2_session_stream_attach_data_subtree(void) CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == f->dpri); + CU_ASSERT(16 == b->effective_weight); + + CU_ASSERT(16 == a->sum_norest_weight); + CU_ASSERT(0 == b->sum_norest_weight); + /* Remove subtree b */ nghttp2_stream_dep_remove_subtree(b); @@ -5806,287 +5835,8 @@ void test_nghttp2_session_stream_attach_data_subtree(void) CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == f->dpri); - nghttp2_session_del(session); -} - -void test_nghttp2_session_stream_dep_effective_weight(void) -{ - nghttp2_session *session; - nghttp2_session_callbacks callbacks; - nghttp2_stream *a, *b, *c, *d, *e, *f, *g; - - memset(&callbacks, 0, sizeof(callbacks)); - - nghttp2_session_server_new(&session, &callbacks, NULL); - - a = open_stream(session, 1); - b = open_stream_with_dep_weight(session, 3, 8, a); - c = open_stream_with_dep_weight(session, 5, 4, a); - d = open_stream_with_dep_weight(session, 7, 1, c); - e = open_stream_with_dep_weight(session, 9, 2, c); - - /* a - * | - * b--c - * | - * d--e - */ - - CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->effective_weight); - CU_ASSERT(16 * 8 / 12 == b->effective_weight); - CU_ASSERT(16 * 4 / 12 == c->effective_weight); - CU_ASSERT((16 * 4 / 12) * 1 / 3 == d->effective_weight); - CU_ASSERT((16 * 4 / 12) * 2 / 3 == e->effective_weight); - - /* Remove a */ - - nghttp2_stream_dep_remove(a); - - /* - * b c - * | - * d--e - */ - - CU_ASSERT(16 * 8 / 12 == b->effective_weight); - CU_ASSERT(16 * 4 / 12 == c->effective_weight); - CU_ASSERT((16 * 4 / 12) * 1 / 3 == d->effective_weight); - CU_ASSERT((16 * 4 / 12) * 2 / 3 == e->effective_weight); - - /* weight is updated for b and c */ - CU_ASSERT(16 * 8 / 12 == b->weight); - CU_ASSERT(16 * 4 / 12 == c->weight); - /* weight remains same for d and e */ - CU_ASSERT(1 == d->weight); - CU_ASSERT(2 == e->weight); - - /* Remove d */ - - nghttp2_stream_dep_remove(d); - - /* - * c d - * | - * e - */ - - CU_ASSERT(16 * 4 / 12 == c->effective_weight); - CU_ASSERT(16 * 4 / 12 == e->effective_weight); - - nghttp2_session_del(session); - - nghttp2_session_server_new(&session, &callbacks, NULL); - - a = open_stream(session, 1); - b = open_stream_with_dep_weight(session, 3, 8, a); - c = open_stream_with_dep_weight(session, 5, 4, a); - d = open_stream_with_dep_weight(session, 7, 1, c); - e = open_stream_with_dep_weight(session, 9, 2, c); - - /* a - * | - * b--c - * | - * d--e - */ - - /* Remove c */ - - nghttp2_stream_dep_remove(c); - - /* a - * | - * b--d--e - */ - - /* weight for d and e is updated */ - CU_ASSERT(1/*4 * 1 / 3*/ == d->weight); - CU_ASSERT(4 * 2 / 3 == e->weight); - - CU_ASSERT(16 * 8 / 11 == b->effective_weight); - CU_ASSERT(16 * 1 / 11 == d->effective_weight); - CU_ASSERT(16 * 2 / 11 == e->effective_weight); - - nghttp2_session_del(session); - - nghttp2_session_server_new(&session, &callbacks, NULL); - - a = open_stream(session, 1); - b = open_stream_with_dep_weight(session, 3, 8, a); - c = open_stream_with_dep_weight(session, 5, 4, a); - d = open_stream_with_dep_weight(session, 7, 1, c); - e = open_stream_with_dep_weight(session, 9, 2, c); - - /* a - * | - * b--c - * | - * d--e - */ - - /* Insert f under a */ - f = open_stream_with_dep_excl(session, 11, a); - - /* a - * | - * f - * | - * b--c - * | - * d--e - */ - - CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->effective_weight); - CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == f->effective_weight); - CU_ASSERT(16 * 8 / 12 == b->effective_weight); - CU_ASSERT(16 * 4 / 12 == c->effective_weight); - CU_ASSERT((16 * 4 / 12) * 1 / 3 == d->effective_weight); - CU_ASSERT((16 * 4 / 12) * 2 / 3 == e->effective_weight); - - /* Add g under f */ - g = open_stream_with_dep_weight(session, 13, 2, f); - - /* a - * | - * f - * | - * b--c--g - * | - * d--e - */ - - CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->effective_weight); - CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == f->effective_weight); - CU_ASSERT(16 * 8 / 14 == b->effective_weight); - CU_ASSERT(16 * 4 / 14 == c->effective_weight); - CU_ASSERT(16 * 2 / 14 == g->effective_weight); - CU_ASSERT((16 * 4 / 14) * 1 / 3 == d->effective_weight); - CU_ASSERT((16 * 4 / 14) * 2 / 3 == e->effective_weight); - - nghttp2_session_del(session); - - nghttp2_session_server_new(&session, &callbacks, NULL); - - a = open_stream(session, 1); - b = open_stream_with_dep_weight(session, 3, 8, a); - c = open_stream_with_dep_weight(session, 5, 4, a); - d = open_stream_with_dep_weight(session, 7, 1, c); - - e = open_stream(session, 9); - f = open_stream_with_dep_weight(session, 11, 12, e); - - /* a e - * | | - * b--c f - * | - * d - */ - - /* Insert e under a */ - nghttp2_stream_dep_insert_subtree(a, e, &session->ob_pq); - - /* a - * | - * e - * | - * b--c--f - * | - * d - */ - - CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == e->effective_weight); - CU_ASSERT(16 * 8 / 24 == b->effective_weight); - CU_ASSERT(16 * 4 / 24 == c->effective_weight); - CU_ASSERT(16 * 12 / 24 == f->effective_weight); - CU_ASSERT(16 * 4 / 24 == d->effective_weight); - - /* Remove subtree c */ - nghttp2_stream_dep_remove_subtree(c); - nghttp2_stream_dep_make_root(c, &session->ob_pq); - - /* a c - * | | - * e d - * | - * b--f - */ - - CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == e->effective_weight); - CU_ASSERT(16 * 8 / 20 == b->effective_weight); - CU_ASSERT(16 * 12 / 20 == f->effective_weight); - - CU_ASSERT(4 == c->effective_weight); - CU_ASSERT(4 == d->effective_weight); - - /* Add subtree c under a */ - nghttp2_stream_dep_add_subtree(a, c, &session->ob_pq); - - /* a - * | - * e-----c - * | | - * b--f d - */ - - CU_ASSERT(16 * 16 / 20 == e->effective_weight); - CU_ASSERT(16 * 4 / 20 == c->effective_weight); - - CU_ASSERT((16 * 16 / 20) * 8 / 20 == b->effective_weight); - CU_ASSERT((16 * 16 / 20) * 12 / 20 == f->effective_weight); - - CU_ASSERT(16 * 4 / 20 == d->effective_weight); - - nghttp2_session_del(session); - - nghttp2_session_server_new(&session, &callbacks, NULL); - - a = open_stream(session, 1); - b = open_stream_with_dep_weight(session, 3, 8, a); - c = open_stream_with_dep_weight(session, 5, 4, a); - d = open_stream_with_dep_weight(session, 7, 1, c); - - e = open_stream(session, 9); - f = open_stream_with_dep_weight(session, 11, 12, e); - - /* a e - * | | - * b--c f - * | - * d - */ - - CU_ASSERT(e->roots->head == e); - CU_ASSERT(a == e->root_next); - - /* Insert e under stream 0 */ - nghttp2_stream_dep_remove_subtree(e); - - CU_ASSERT(a == e->roots->head); - - CU_ASSERT(0 == nghttp2_stream_dep_all_your_stream_are_belong_to_us - (e, &session->ob_pq)); - - /* e - * | - * f--a - * | - * b--c - * | - * d - */ - - CU_ASSERT(6 == e->num_substreams); - CU_ASSERT(28 == e->sum_dep_weight); - - CU_ASSERT(16 == e->effective_weight); - - CU_ASSERT(16 * 16 / 28 == a->effective_weight); - CU_ASSERT(16 * 12 / 28 == f->effective_weight); - - CU_ASSERT((16 * 16 / 28) * 8 / 12 == b->effective_weight); - CU_ASSERT((16 * 16 / 28) * 4 / 12 == c->effective_weight); - - CU_ASSERT((16 * 16 / 28) * 4 / 12 == d->effective_weight); + CU_ASSERT(0 == a->sum_norest_weight); + CU_ASSERT(0 == b->sum_norest_weight); nghttp2_session_del(session); } diff --git a/tests/nghttp2_session_test.h b/tests/nghttp2_session_test.h index e6bac7bf..8ef093cf 100644 --- a/tests/nghttp2_session_test.h +++ b/tests/nghttp2_session_test.h @@ -106,7 +106,6 @@ void test_nghttp2_session_stream_dep_remove_subtree(void); void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void); void test_nghttp2_session_stream_attach_data(void); void test_nghttp2_session_stream_attach_data_subtree(void); -void test_nghttp2_session_stream_dep_effective_weight(void); void test_nghttp2_session_keep_closed_stream(void); #endif /* NGHTTP2_SESSION_TEST_H */ diff --git a/tests/nghttp2_test_helper.c b/tests/nghttp2_test_helper.c index fc00f401..dbc979c8 100644 --- a/tests/nghttp2_test_helper.c +++ b/tests/nghttp2_test_helper.c @@ -232,11 +232,22 @@ void bufs_large_init(nghttp2_bufs *bufs, size_t chunk_size) nghttp2_bufs_init2(bufs, chunk_size, 16, NGHTTP2_FRAME_HDLEN + 2); } -nghttp2_stream* open_stream(nghttp2_session *session, int32_t stream_id) +static nghttp2_stream* open_stream_with_all(nghttp2_session *session, + int32_t stream_id, + int32_t weight, + uint8_t exclusive, + nghttp2_stream *dep_stream) { nghttp2_priority_spec pri_spec; + int32_t dep_stream_id; - nghttp2_priority_spec_default_init(&pri_spec); + if(dep_stream) { + dep_stream_id = dep_stream->stream_id; + } else { + dep_stream_id = 0; + } + + nghttp2_priority_spec_init(&pri_spec, dep_stream_id, weight, exclusive); return nghttp2_session_open_stream(session, stream_id, NGHTTP2_STREAM_FLAG_NONE, @@ -245,12 +256,19 @@ nghttp2_stream* open_stream(nghttp2_session *session, int32_t stream_id) NULL); } + +nghttp2_stream* open_stream(nghttp2_session *session, int32_t stream_id) +{ + return open_stream_with_all(session, stream_id, NGHTTP2_DEFAULT_WEIGHT, 0, + NULL); +} + nghttp2_stream* open_stream_with_dep(nghttp2_session *session, int32_t stream_id, nghttp2_stream *dep_stream) { - return open_stream_with_dep_weight(session, stream_id, - NGHTTP2_DEFAULT_WEIGHT, dep_stream); + return open_stream_with_all(session, stream_id, NGHTTP2_DEFAULT_WEIGHT, 0, + dep_stream); } nghttp2_stream* open_stream_with_dep_weight(nghttp2_session *session, @@ -258,29 +276,25 @@ nghttp2_stream* open_stream_with_dep_weight(nghttp2_session *session, int32_t weight, nghttp2_stream *dep_stream) { - nghttp2_priority_spec pri_spec; - - nghttp2_priority_spec_init(&pri_spec, dep_stream->stream_id, weight, 0); - - return nghttp2_session_open_stream(session, stream_id, - NGHTTP2_STREAM_FLAG_NONE, - &pri_spec, - NGHTTP2_STREAM_OPENED, - NULL); + return open_stream_with_all(session, stream_id, weight, 0, dep_stream); } nghttp2_stream* open_stream_with_dep_excl(nghttp2_session *session, int32_t stream_id, nghttp2_stream *dep_stream) { - nghttp2_priority_spec pri_spec; - - nghttp2_priority_spec_init(&pri_spec, dep_stream->stream_id, - NGHTTP2_DEFAULT_WEIGHT, 1); - - return nghttp2_session_open_stream(session, stream_id, - NGHTTP2_STREAM_FLAG_NONE, - &pri_spec, - NGHTTP2_STREAM_OPENED, - NULL); + return open_stream_with_all(session, stream_id, NGHTTP2_DEFAULT_WEIGHT, 1, + dep_stream); } + +nghttp2_outbound_item* create_data_ob_item(void) +{ + nghttp2_outbound_item *item; + + item = malloc(sizeof(nghttp2_outbound_item)); + memset(item, 0, sizeof(nghttp2_outbound_item)); + item->frame_cat = NGHTTP2_CAT_DATA; + + return item; +} + diff --git a/tests/nghttp2_test_helper.h b/tests/nghttp2_test_helper.h index 27b2c801..780dfaf1 100644 --- a/tests/nghttp2_test_helper.h +++ b/tests/nghttp2_test_helper.h @@ -98,4 +98,6 @@ nghttp2_stream* open_stream_with_dep_excl(nghttp2_session *session, int32_t stream_id, nghttp2_stream *dep_stream); +nghttp2_outbound_item* create_data_ob_item(void); + #endif /* NGHTTP2_TEST_HELPER_H */ From ee26469cd909aac26fcf733fd5d5c09cfe032a82 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Thu, 24 Apr 2014 23:44:34 +0900 Subject: [PATCH 5/5] Handle circular dependency Handle the situation if a stream is told to depend on its descendant. This is what http://tools.ietf.org/html/draft-ietf-httpbis-http2-12#section-5.3.3 says. --- lib/nghttp2_session.c | 7 ++++--- tests/nghttp2_session_test.c | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index ea50843d..8e820a8b 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -492,14 +492,15 @@ int nghttp2_session_reprioritize_stream return 0; } - /* Ignore priority request if resultant tree has cycle */ if(nghttp2_stream_dep_subtree_find(stream, dep_stream)) { DEBUGF(fprintf(stderr, - "stream: future cycle detected, dep_stream(%p)=%d " + "stream: cycle detected, dep_stream(%p)=%d " "stream(%p)=%d\n", dep_stream, dep_stream->stream_id, stream, stream->stream_id)); - return 0; + + nghttp2_stream_dep_remove_subtree(dep_stream); + nghttp2_stream_dep_make_root(dep_stream, &session->ob_pq); } nghttp2_stream_dep_remove_subtree(stream); diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index c16ade27..e1e5fdb8 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -2586,13 +2586,14 @@ void test_nghttp2_session_reprioritize_stream(void) CU_ASSERT(99 == stream->weight); CU_ASSERT(dep_stream == stream->dep_prev); - /* Test circular dependency; must be ignored */ + /* Test circular dependency; stream 1 is first removed and becomes + root. Then stream 3 depends on it. */ nghttp2_priority_spec_init(&pri_spec, 1, 1, 0); nghttp2_session_reprioritize_stream(session, dep_stream, &pri_spec); - CU_ASSERT(16 == dep_stream->weight); - CU_ASSERT(NULL == dep_stream->dep_prev); + CU_ASSERT(1 == dep_stream->weight); + CU_ASSERT(stream == dep_stream->dep_prev); nghttp2_session_del(session); }