Implement simplified dependency based priority

This commit is contained in:
Tatsuhiro Tsujikawa 2014-04-14 23:53:54 +09:00
parent 27a91fc30e
commit ac86b51e37
17 changed files with 954 additions and 1276 deletions

View File

@ -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,

View File

@ -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;
}

View File

@ -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:

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -117,7 +117,6 @@ typedef enum {
struct nghttp2_session {
nghttp2_map /* <nghttp2_stream*> */ streams;
nghttp2_map /* <nghttp2_stream_group*> */ stream_groups;
/* Queue for outbound frames other than stream-creating HEADERS */
nghttp2_pq /* <nghttp2_outbound_item*> */ 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 */

View File

@ -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);
}

View File

@ -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 */

View File

@ -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(&copy_pri_spec);
}
adjust_priority_spec_weight(&copy_pri_spec);
} else {
nghttp2_priority_spec_default_init(&copy_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(&copy_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(&copy_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,

View File

@ -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:

View File

@ -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<Request>("", 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) {

View File

@ -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",

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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,

View File

@ -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);