Allow exclusive dependency to stream 0
This commit is contained in:
parent
ac86b51e37
commit
aa4d43f31e
|
@ -2105,8 +2105,6 @@ void nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec);
|
||||||
* @function
|
* @function
|
||||||
*
|
*
|
||||||
* Returns nonzero if the |pri_spec| is filled with default values.
|
* 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);
|
int nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec);
|
||||||
|
|
||||||
|
|
|
@ -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)
|
int nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec)
|
||||||
{
|
{
|
||||||
/* Ignore exclusive flag */
|
|
||||||
return pri_spec->stream_id == 0 &&
|
return pri_spec->stream_id == 0 &&
|
||||||
pri_spec->weight == NGHTTP2_DEFAULT_WEIGHT;
|
pri_spec->weight == NGHTTP2_DEFAULT_WEIGHT &&
|
||||||
|
pri_spec->exclusive == 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -280,6 +280,8 @@ static int nghttp2_session_new(nghttp2_session **session_ptr,
|
||||||
goto fail_map;
|
goto fail_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nghttp2_stream_roots_init(&(*session_ptr)->roots);
|
||||||
|
|
||||||
(*session_ptr)->next_seq = 0;
|
(*session_ptr)->next_seq = 0;
|
||||||
|
|
||||||
(*session_ptr)->remote_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE;
|
(*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);
|
free(session->inflight_iv);
|
||||||
|
|
||||||
|
nghttp2_stream_roots_free(&session->roots);
|
||||||
|
|
||||||
/* Have to free streams first, so that we can check
|
/* Have to free streams first, so that we can check
|
||||||
stream->data_item->queued */
|
stream->data_item->queued */
|
||||||
nghttp2_map_each_free(&session->streams, nghttp2_free_streams, NULL);
|
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 */
|
/* We have to update weight after removing stream from tree */
|
||||||
stream->weight = pri_spec->weight;
|
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;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -711,7 +722,7 @@ nghttp2_stream* nghttp2_session_open_stream(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
|
|
||||||
nghttp2_stream_init(stream, stream_id, flags, initial_state,
|
nghttp2_stream_init(stream, stream_id, flags, initial_state,
|
||||||
pri_spec->weight,
|
pri_spec->weight, &session->roots,
|
||||||
session->remote_settings
|
session->remote_settings
|
||||||
[NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
|
[NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE],
|
||||||
session->local_settings
|
session->local_settings
|
||||||
|
@ -747,9 +758,29 @@ nghttp2_stream* nghttp2_session_open_stream(nghttp2_session *session,
|
||||||
return stream;
|
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);
|
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;
|
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 */
|
/* Closes both directions just in case they are not closed yet */
|
||||||
stream->flags |= NGHTTP2_STREAM_FLAG_CLOSED;
|
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
|
/* On server side, retain incoming stream object at most
|
||||||
MAX_CONCURRENT_STREAMS combined with the current active streams
|
MAX_CONCURRENT_STREAMS combined with the current active streams
|
||||||
to make dependency tree work better. */
|
to make dependency tree work better. */
|
||||||
|
|
|
@ -117,6 +117,7 @@ typedef enum {
|
||||||
|
|
||||||
struct nghttp2_session {
|
struct nghttp2_session {
|
||||||
nghttp2_map /* <nghttp2_stream*> */ streams;
|
nghttp2_map /* <nghttp2_stream*> */ streams;
|
||||||
|
nghttp2_stream_roots roots;
|
||||||
/* Queue for outbound frames other than stream-creating HEADERS */
|
/* Queue for outbound frames other than stream-creating HEADERS */
|
||||||
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_pq;
|
nghttp2_pq /* <nghttp2_outbound_item*> */ ob_pq;
|
||||||
/* Queue for outbound stream-creating HEADERS frame */
|
/* Queue for outbound stream-creating HEADERS frame */
|
||||||
|
|
|
@ -33,6 +33,7 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||||
uint8_t flags,
|
uint8_t flags,
|
||||||
nghttp2_stream_state initial_state,
|
nghttp2_stream_state initial_state,
|
||||||
int32_t weight,
|
int32_t weight,
|
||||||
|
nghttp2_stream_roots *roots,
|
||||||
int32_t remote_initial_window_size,
|
int32_t remote_initial_window_size,
|
||||||
int32_t local_initial_window_size,
|
int32_t local_initial_window_size,
|
||||||
void *stream_user_data)
|
void *stream_user_data)
|
||||||
|
@ -61,6 +62,10 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||||
stream->weight = weight;
|
stream->weight = weight;
|
||||||
stream->effective_weight = stream->weight;
|
stream->effective_weight = stream->weight;
|
||||||
stream->sum_dep_weight = 0;
|
stream->sum_dep_weight = 0;
|
||||||
|
|
||||||
|
stream->roots = roots;
|
||||||
|
stream->root_prev = NULL;
|
||||||
|
stream->root_next = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_stream_free(nghttp2_stream *stream)
|
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_length(dep_stream, 1);
|
||||||
stream_update_dep_effective_weight(dep_stream);
|
stream_update_dep_effective_weight(dep_stream);
|
||||||
|
|
||||||
|
++stream->roots->num_streams;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
|
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_update_dep_effective_weight(dep_stream);
|
||||||
|
|
||||||
|
++stream->roots->num_streams;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_stream_dep_remove(nghttp2_stream *stream)
|
void nghttp2_stream_dep_remove(nghttp2_stream *stream)
|
||||||
|
@ -568,6 +577,8 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream)
|
||||||
dep_next = NULL;
|
dep_next = NULL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
nghttp2_stream_roots_remove(stream->roots, stream);
|
||||||
|
|
||||||
dep_next = NULL;
|
dep_next = NULL;
|
||||||
|
|
||||||
/* stream is a root of tree. Removing stream makes its
|
/* 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. */
|
/* We already distributed weight of |stream| to this. */
|
||||||
si->effective_weight = si->weight;
|
si->effective_weight = si->weight;
|
||||||
|
|
||||||
|
nghttp2_stream_roots_add(si->roots, si);
|
||||||
|
|
||||||
si = next;
|
si = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -606,6 +619,8 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream)
|
||||||
stream->dep_next = NULL;
|
stream->dep_next = NULL;
|
||||||
stream->sib_prev = NULL;
|
stream->sib_prev = NULL;
|
||||||
stream->sib_next = NULL;
|
stream->sib_next = NULL;
|
||||||
|
|
||||||
|
--stream->roots->num_streams;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
|
int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
|
||||||
|
@ -748,6 +763,8 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
nghttp2_stream_roots_remove(stream->roots, stream);
|
||||||
|
|
||||||
dep_prev = NULL;
|
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",
|
DEBUGF(fprintf(stderr, "stream: dep_make_root stream(%p)=%d\n",
|
||||||
stream, stream->stream_id));
|
stream, stream->stream_id));
|
||||||
|
|
||||||
|
nghttp2_stream_roots_add(stream->roots, stream);
|
||||||
|
|
||||||
stream_update_dep_set_rest(stream);
|
stream_update_dep_set_rest(stream);
|
||||||
|
|
||||||
stream->effective_weight = stream->weight;
|
stream->effective_weight = stream->weight;
|
||||||
|
@ -785,3 +804,141 @@ int nghttp2_stream_dep_make_root(nghttp2_stream *stream, nghttp2_pq *pq)
|
||||||
|
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -102,6 +102,10 @@ typedef enum {
|
||||||
NGHTTP2_STREAM_DPRI_REST = 0x04
|
NGHTTP2_STREAM_DPRI_REST = 0x04
|
||||||
} nghttp2_stream_dpri;
|
} nghttp2_stream_dpri;
|
||||||
|
|
||||||
|
struct nghttp2_stream_roots;
|
||||||
|
|
||||||
|
typedef struct nghttp2_stream_roots nghttp2_stream_roots;
|
||||||
|
|
||||||
struct nghttp2_stream;
|
struct nghttp2_stream;
|
||||||
|
|
||||||
typedef struct nghttp2_stream nghttp2_stream;
|
typedef struct nghttp2_stream nghttp2_stream;
|
||||||
|
@ -118,11 +122,17 @@ struct nghttp2_stream {
|
||||||
dep_prev and sib_prev are NULL. */
|
dep_prev and sib_prev are NULL. */
|
||||||
nghttp2_stream *dep_prev, *dep_next;
|
nghttp2_stream *dep_prev, *dep_next;
|
||||||
nghttp2_stream *sib_prev, *sib_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
|
/* When stream is kept after closure, it may be kept in single
|
||||||
linked list pointed by nghttp2_session closed_stream_head.
|
linked list pointed by nghttp2_session closed_stream_head.
|
||||||
closed_next points to the next stream object if it is the element
|
closed_next points to the next stream object if it is the element
|
||||||
of the list. */
|
of the list. */
|
||||||
nghttp2_stream *closed_next;
|
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. */
|
/* The arbitrary data provided by user for this stream. */
|
||||||
void *stream_user_data;
|
void *stream_user_data;
|
||||||
/* DATA frame item */
|
/* DATA frame item */
|
||||||
|
@ -165,6 +175,7 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||||
uint8_t flags,
|
uint8_t flags,
|
||||||
nghttp2_stream_state initial_state,
|
nghttp2_stream_state initial_state,
|
||||||
int32_t weight,
|
int32_t weight,
|
||||||
|
nghttp2_stream_roots *roots,
|
||||||
int32_t remote_initial_window_size,
|
int32_t remote_initial_window_size,
|
||||||
int32_t local_initial_window_size,
|
int32_t local_initial_window_size,
|
||||||
void *stream_user_data);
|
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);
|
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 */
|
#endif /* NGHTTP2_STREAM */
|
||||||
|
|
|
@ -103,10 +103,6 @@ static int nghttp2_submit_headers_shared
|
||||||
|
|
||||||
static void adjust_priority_spec_weight(nghttp2_priority_spec *pri_spec)
|
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) {
|
if(pri_spec->weight < NGHTTP2_MIN_WEIGHT) {
|
||||||
pri_spec->weight = NGHTTP2_MIN_WEIGHT;
|
pri_spec->weight = NGHTTP2_MIN_WEIGHT;
|
||||||
} else if(pri_spec->weight > NGHTTP2_MAX_WEIGHT) {
|
} else if(pri_spec->weight > NGHTTP2_MAX_WEIGHT) {
|
||||||
|
|
|
@ -222,6 +222,8 @@ int main(int argc, char* argv[])
|
||||||
test_nghttp2_session_stream_dep_add_subtree) ||
|
test_nghttp2_session_stream_dep_add_subtree) ||
|
||||||
!CU_add_test(pSuite, "session_stream_dep_remove_subtree",
|
!CU_add_test(pSuite, "session_stream_dep_remove_subtree",
|
||||||
test_nghttp2_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",
|
!CU_add_test(pSuite, "session_stream_attach_data",
|
||||||
test_nghttp2_session_stream_attach_data) ||
|
test_nghttp2_session_stream_attach_data) ||
|
||||||
!CU_add_test(pSuite, "session_stream_attach_data_subtree",
|
!CU_add_test(pSuite, "session_stream_attach_data_subtree",
|
||||||
|
|
|
@ -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(c, NULL, d, b, NULL);
|
||||||
check_stream_dep_sib(d, c, NULL, NULL, NULL);
|
check_stream_dep_sib(d, c, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
CU_ASSERT(4 == session->roots.num_streams);
|
||||||
|
CU_ASSERT(a == session->roots.head);
|
||||||
|
CU_ASSERT(NULL == a->root_next);
|
||||||
|
|
||||||
e = open_stream_with_dep_excl(session, 9, a);
|
e = open_stream_with_dep_excl(session, 9, a);
|
||||||
|
|
||||||
/* 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(c, NULL, d, b, NULL);
|
||||||
check_stream_dep_sib(d, c, NULL, NULL, NULL);
|
check_stream_dep_sib(d, c, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
CU_ASSERT(5 == session->roots.num_streams);
|
||||||
|
CU_ASSERT(a == session->roots.head);
|
||||||
|
CU_ASSERT(NULL == a->root_next);
|
||||||
|
|
||||||
nghttp2_session_del(session);
|
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(c, NULL, d, NULL, NULL);
|
||||||
check_stream_dep_sib(d, c, NULL, 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);
|
nghttp2_session_del(session);
|
||||||
|
|
||||||
/* Remove left most stream */
|
/* 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(c, a, d, NULL, NULL);
|
||||||
check_stream_dep_sib(d, c, NULL, 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);
|
nghttp2_session_del(session);
|
||||||
|
|
||||||
/* Remove right most stream */
|
/* Remove right most stream */
|
||||||
|
@ -5348,6 +5365,131 @@ void test_nghttp2_session_stream_dep_remove_subtree(void)
|
||||||
nghttp2_session_del(session);
|
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)
|
static nghttp2_outbound_item* create_data_ob_item(void)
|
||||||
{
|
{
|
||||||
nghttp2_outbound_item *item;
|
nghttp2_outbound_item *item;
|
||||||
|
@ -5488,6 +5630,7 @@ void test_nghttp2_session_stream_attach_data_subtree(void)
|
||||||
|
|
||||||
/* Insert subtree e under a */
|
/* Insert subtree e under a */
|
||||||
|
|
||||||
|
nghttp2_stream_dep_remove_subtree(e);
|
||||||
nghttp2_stream_dep_insert_subtree(a, e, &session->ob_pq);
|
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 */
|
/* Add subtree c to a */
|
||||||
|
|
||||||
|
nghttp2_stream_dep_remove_subtree(c);
|
||||||
nghttp2_stream_dep_add_subtree(a, c, &session->ob_pq);
|
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 */
|
/* Insert b under a */
|
||||||
|
|
||||||
|
nghttp2_stream_dep_remove_subtree(b);
|
||||||
nghttp2_stream_dep_insert_subtree(a, b, &session->ob_pq);
|
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_REST == e->dpri);
|
||||||
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_DATA == f->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 */
|
/* Remove subtree b */
|
||||||
|
|
||||||
nghttp2_stream_dep_remove_subtree(b);
|
nghttp2_stream_dep_remove_subtree(b);
|
||||||
|
nghttp2_stream_dep_make_root(b, &session->ob_pq);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* b a
|
* b a
|
||||||
|
@ -5870,6 +6004,58 @@ void test_nghttp2_session_stream_dep_effective_weight(void)
|
||||||
CU_ASSERT(16 * 4 / 20 == d->effective_weight);
|
CU_ASSERT(16 * 4 / 20 == d->effective_weight);
|
||||||
|
|
||||||
nghttp2_session_del(session);
|
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)
|
void test_nghttp2_session_keep_closed_stream(void)
|
||||||
|
|
|
@ -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_remove(void);
|
||||||
void test_nghttp2_session_stream_dep_add_subtree(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_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(void);
|
||||||
void test_nghttp2_session_stream_attach_data_subtree(void);
|
void test_nghttp2_session_stream_attach_data_subtree(void);
|
||||||
void test_nghttp2_session_stream_dep_effective_weight(void);
|
void test_nghttp2_session_stream_dep_effective_weight(void);
|
||||||
|
|
Loading…
Reference in New Issue