Skip to content

Commit 1b57c37

Browse files
addaleaxMylesBorins
authored andcommitted
http2: minor refactor of passing headers to JS
- Make `ExternalString::New` return a `MaybeLocal`. Failing is left up to the caller. - Allow creating internalized strings for short header names to reduce memory consumption and increase performance. - Use persistent storage for statically allocated header names. PR-URL: #14808 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Timothy Gu <[email protected]>
1 parent 56bb199 commit 1b57c37

File tree

4 files changed

+54
-14
lines changed

4 files changed

+54
-14
lines changed

benchmark/http2/headers.js

+11-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const PORT = common.PORT;
55

66
var bench = common.createBenchmark(main, {
77
n: [1e3],
8-
nheaders: [100, 1000],
8+
nheaders: [0, 10, 100, 1000],
99
}, { flags: ['--expose-http2', '--no-warnings'] });
1010

1111
function main(conf) {
@@ -14,7 +14,16 @@ function main(conf) {
1414
const http2 = require('http2');
1515
const server = http2.createServer();
1616

17-
const headersObject = { ':path': '/' };
17+
const headersObject = {
18+
':path': '/',
19+
':scheme': 'http',
20+
'accept-encoding': 'gzip, deflate',
21+
'accept-language': 'en',
22+
'content-type': 'text/plain',
23+
'referer': 'https://example.org/',
24+
'user-agent': 'SuperBenchmarker 3000'
25+
};
26+
1827
for (var i = 0; i < nheaders; i++) {
1928
headersObject[`foo${i}`] = `some header value ${i}`;
2029
}

src/env.h

+5
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
#include <stdint.h>
4040
#include <vector>
4141
#include <stack>
42+
#include <unordered_map>
43+
44+
struct nghttp2_rcbuf;
4245

4346
namespace node {
4447

@@ -341,6 +344,8 @@ class IsolateData {
341344
#undef VS
342345
#undef VP
343346

347+
std::unordered_map<nghttp2_rcbuf*, v8::Eternal<v8::String>> http2_static_strs;
348+
344349
private:
345350
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
346351
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)

src/node_http2.cc

+4-2
Original file line numberDiff line numberDiff line change
@@ -901,8 +901,10 @@ void Http2Session::OnHeaders(Nghttp2Stream* stream,
901901
while (headers != nullptr && j < arraysize(argv) / 2) {
902902
nghttp2_header_list* item = headers;
903903
// The header name and value are passed as external one-byte strings
904-
name_str = ExternalHeader::New(isolate, item->name);
905-
value_str = ExternalHeader::New(isolate, item->value);
904+
name_str =
905+
ExternalHeader::New<true>(env(), item->name).ToLocalChecked();
906+
value_str =
907+
ExternalHeader::New<false>(env(), item->value).ToLocalChecked();
906908
argv[j * 2] = name_str;
907909
argv[j * 2 + 1] = value_str;
908910
headers = item->next;

src/node_http2.h

+34-10
Original file line numberDiff line numberDiff line change
@@ -472,24 +472,48 @@ class ExternalHeader :
472472
return vec_.len;
473473
}
474474

475-
static Local<String> New(Isolate* isolate, nghttp2_rcbuf* buf) {
476-
EscapableHandleScope scope(isolate);
475+
static inline
476+
MaybeLocal<String> GetInternalizedString(Environment* env,
477+
const nghttp2_vec& vec) {
478+
return String::NewFromOneByte(env->isolate(),
479+
vec.base,
480+
v8::NewStringType::kInternalized,
481+
vec.len);
482+
}
483+
484+
template<bool may_internalize>
485+
static MaybeLocal<String> New(Environment* env, nghttp2_rcbuf* buf) {
486+
if (nghttp2_rcbuf_is_static(buf)) {
487+
auto& static_str_map = env->isolate_data()->http2_static_strs;
488+
v8::Eternal<v8::String>& eternal = static_str_map[buf];
489+
if (eternal.IsEmpty()) {
490+
Local<String> str =
491+
GetInternalizedString(env, nghttp2_rcbuf_get_buf(buf))
492+
.ToLocalChecked();
493+
eternal.Set(env->isolate(), str);
494+
return str;
495+
}
496+
return eternal.Get(env->isolate());
497+
}
498+
477499
nghttp2_vec vec = nghttp2_rcbuf_get_buf(buf);
478500
if (vec.len == 0) {
479501
nghttp2_rcbuf_decref(buf);
480-
return scope.Escape(String::Empty(isolate));
502+
return String::Empty(env->isolate());
481503
}
482504

483-
ExternalHeader* h_str = new ExternalHeader(buf);
484-
MaybeLocal<String> str = String::NewExternalOneByte(isolate, h_str);
485-
isolate->AdjustAmountOfExternalAllocatedMemory(vec.len);
505+
if (may_internalize && vec.len < 64) {
506+
// This is a short header name, so there is a good chance V8 already has
507+
// it internalized.
508+
return GetInternalizedString(env, vec);
509+
}
486510

487-
if (str.IsEmpty()) {
511+
ExternalHeader* h_str = new ExternalHeader(buf);
512+
MaybeLocal<String> str = String::NewExternalOneByte(env->isolate(), h_str);
513+
if (str.IsEmpty())
488514
delete h_str;
489-
return scope.Escape(String::Empty(isolate));
490-
}
491515

492-
return scope.Escape(str.ToLocalChecked());
516+
return str;
493517
}
494518

495519
private:

0 commit comments

Comments
 (0)