nghttp: Use same priority anchor nodes as Firefox does

This commit is contained in:
Tatsuhiro Tsujikawa 2015-04-16 23:42:36 +09:00
parent e6ad2eb14f
commit e23225689f
3 changed files with 60 additions and 48 deletions

View File

@ -75,22 +75,23 @@ void start_element_func(void *user_data, const xmlChar *name,
return; return;
} }
if (util::strieq(rel_attr, "shortcut icon")) { if (util::strieq(rel_attr, "shortcut icon")) {
add_link(parser_data, href_attr, REQ_PRI_LOWEST); add_link(parser_data, href_attr, REQ_OTHERS);
} else if (util::strieq(rel_attr, "stylesheet")) { } else if (util::strieq(rel_attr, "stylesheet")) {
add_link(parser_data, href_attr, REQ_PRI_MEDIUM); add_link(parser_data, href_attr, REQ_CSS);
} }
} else if (util::strieq(reinterpret_cast<const char *>(name), "img")) { } else if (util::strieq(reinterpret_cast<const char *>(name), "img")) {
auto src_attr = get_attr(attrs, "src"); auto src_attr = get_attr(attrs, "src");
if (!src_attr) { if (!src_attr) {
return; return;
} }
add_link(parser_data, src_attr, REQ_PRI_LOWEST); add_link(parser_data, src_attr, REQ_IMG);
} else if (util::strieq(reinterpret_cast<const char *>(name), "script")) { } else if (util::strieq(reinterpret_cast<const char *>(name), "script")) {
auto src_attr = get_attr(attrs, "src"); auto src_attr = get_attr(attrs, "src");
if (!src_attr) { if (!src_attr) {
return; return;
} }
add_link(parser_data, src_attr, REQ_PRI_LOW); // TODO if script is inside in head, this should be REQ_LEADERS.
add_link(parser_data, src_attr, REQ_UNBLOCK_JS);
} }
} }
} // namespace } // namespace

View File

@ -38,11 +38,12 @@
namespace nghttp2 { namespace nghttp2 {
// Lower value has higher priority
enum RequestPriority { enum RequestPriority {
REQ_PRI_HIGH = 0, REQ_CSS = 1,
REQ_PRI_MEDIUM = 1, REQ_UNBLOCK_JS,
REQ_PRI_LOW = 2, REQ_IMG,
REQ_PRI_LOWEST = 3 REQ_OTHERS,
}; };
struct ParserData { struct ParserData {

View File

@ -61,17 +61,33 @@
namespace nghttp2 { namespace nghttp2 {
// stream ID of anchor stream node when --dep-idle is enabled. These // The anchor stream nodes when --dep-idle is enabled. The stream ID
// * portion of ANCHOR_ID_* matches RequestPriority in HtmlParser.h. // = 1 is excluded since it is used as first stream in upgrade case.
// The stream ID = 1 is excluded since it is used as first stream in // We follows the same dependency anchor nodes as Firefox does.
// upgrade case. struct Anchor {
enum { int32_t stream_id;
ANCHOR_ID_HIGH = 3, // stream ID this anchor depends on
ANCHOR_ID_MEDIUM = 5, int32_t dep_stream_id;
ANCHOR_ID_LOW = 7, // .. with this weight.
ANCHOR_ID_LOWEST = 9, int32_t weight;
}; };
// This is index into anchors. Firefox uses ANCHOR_FOLLOWERS for html
// file.
enum {
ANCHOR_LEADERS,
ANCHOR_UNBLOCKED,
ANCHOR_BACKGROUND,
ANCHOR_SPECULATIVE,
ANCHOR_FOLLOWERS,
};
namespace {
auto anchors = std::array<Anchor, 5>{{
{3, 0, 201}, {5, 0, 101}, {7, 0, 1}, {9, 7, 1}, {11, 3, 1},
}};
} // namespace
Config::Config() Config::Config()
: output_upper_thres(1024 * 1024), padding(0), : output_upper_thres(1024 * 1024), padding(0),
peer_max_concurrent_streams(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS), peer_max_concurrent_streams(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS),
@ -176,22 +192,27 @@ nghttp2_priority_spec Request::resolve_dep(int32_t pri) {
} }
if (config.dep_idle) { if (config.dep_idle) {
int32_t anchor_id = 0; int32_t anchor_id;
int32_t weight;
switch (pri) { switch (pri) {
case REQ_PRI_HIGH: case REQ_CSS:
anchor_id = ANCHOR_ID_HIGH; anchor_id = anchors[ANCHOR_LEADERS].stream_id;
weight = 2;
break; break;
case REQ_PRI_MEDIUM: case REQ_UNBLOCK_JS:
anchor_id = ANCHOR_ID_MEDIUM; anchor_id = anchors[ANCHOR_UNBLOCKED].stream_id;
weight = 2;
break; break;
case REQ_PRI_LOW: case REQ_IMG:
anchor_id = ANCHOR_ID_LOW; anchor_id = anchors[ANCHOR_FOLLOWERS].stream_id;
break; weight = 12;
case REQ_PRI_LOWEST:
anchor_id = ANCHOR_ID_LOWEST;
break; break;
default:
anchor_id = anchors[ANCHOR_FOLLOWERS].stream_id;
weight = 2;
} }
nghttp2_priority_spec_init(&pri_spec, anchor_id, NGHTTP2_DEFAULT_WEIGHT, 0);
nghttp2_priority_spec_init(&pri_spec, anchor_id, weight, 0);
return pri_spec; return pri_spec;
} }
@ -980,23 +1001,19 @@ int HttpClient::connection_made() {
if (!config.no_dep && config.dep_idle) { if (!config.no_dep && config.dep_idle) {
// Create anchor stream nodes // Create anchor stream nodes
nghttp2_priority_spec pri_spec; nghttp2_priority_spec pri_spec;
int32_t dep_stream_id = 0;
for (auto stream_id : for (auto &anchor : anchors) {
{ANCHOR_ID_HIGH, ANCHOR_ID_MEDIUM, ANCHOR_ID_LOW, ANCHOR_ID_LOWEST}) { nghttp2_priority_spec_init(&pri_spec, anchor.dep_stream_id, anchor.weight,
0);
nghttp2_priority_spec_init(&pri_spec, dep_stream_id, rv = nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, anchor.stream_id,
NGHTTP2_DEFAULT_WEIGHT, 0);
rv = nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, stream_id,
&pri_spec); &pri_spec);
if (rv != 0) { if (rv != 0) {
return -1; return -1;
} }
dep_stream_id = stream_id;
} }
rv = nghttp2_session_set_next_stream_id(session, ANCHOR_ID_LOWEST + 2); rv = nghttp2_session_set_next_stream_id(
session, anchors[ANCHOR_FOLLOWERS].stream_id + 2);
if (rv != 0) { if (rv != 0) {
return -1; return -1;
} }
@ -1004,7 +1021,8 @@ int HttpClient::connection_made() {
if (need_upgrade()) { if (need_upgrade()) {
// Amend the priority because we cannot send priority in // Amend the priority because we cannot send priority in
// HTTP/1.1 Upgrade. // HTTP/1.1 Upgrade.
nghttp2_priority_spec_init(&pri_spec, ANCHOR_ID_HIGH, config.weight, 0); auto &anchor = anchors[ANCHOR_FOLLOWERS];
nghttp2_priority_spec_init(&pri_spec, anchor.stream_id, config.weight, 0);
rv = nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, 1, &pri_spec); rv = nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, 1, &pri_spec);
if (rv != 0) { if (rv != 0) {
@ -1272,14 +1290,6 @@ void HttpClient::record_connect_end_time() {
} }
void HttpClient::request_done(Request *req) { void HttpClient::request_done(Request *req) {
if (req->pri == 0 && req->dep) {
assert(req->dep->deps.empty());
req->dep->deps.push_back(std::vector<Request *>{req});
return;
}
if (req->stream_id % 2 == 0) { if (req->stream_id % 2 == 0) {
return; return;
} }
@ -2059,7 +2069,7 @@ int communicate(
int32_t dep_stream_id = 0; int32_t dep_stream_id = 0;
if (!config.no_dep && config.dep_idle) { if (!config.no_dep && config.dep_idle) {
dep_stream_id = ANCHOR_ID_HIGH; dep_stream_id = anchors[ANCHOR_FOLLOWERS].stream_id;
} }
nghttp2_priority_spec_init(&pri_spec, dep_stream_id, config.weight, 0); nghttp2_priority_spec_init(&pri_spec, dep_stream_id, config.weight, 0);