Skip to content

Commit 0e7b612

Browse files
committed
src: refactor WriteWrap and ShutdownWraps
Encapsulate stream requests more: - `WriteWrap` and `ShutdownWrap` classes are now tailored to the streams on which they are used. In particular, for most streams these are now plain `AsyncWrap`s and do not carry the overhead of unused libuv request data. - Provide generic `Write()` and `Shutdown()` methods that wrap around the actual implementations, and make *usage* of streams easier, rather than implementing; for example, wrap objects don’t need to be provided by callers anymore. - Use `EmitAfterWrite()` and `EmitAfterShutdown()` handlers to call the corresponding JS handlers, rather than always trying to call them. This makes usage of streams by other C++ code easier and leaner. Also fix up some tests that were previously not actually testing asynchronicity when the comments indicated that they would. PR-URL: #18676 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Anatoli Papirovski <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 0ed9ea8 commit 0e7b612

20 files changed

+556
-427
lines changed

benchmark/net/tcp-raw-c2s.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ function client(type, len) {
118118
fail(err, 'write');
119119
}
120120

121-
function afterWrite(err, handle, req) {
121+
function afterWrite(err, handle) {
122122
if (err)
123123
fail(err, 'write');
124124

benchmark/net/tcp-raw-pipe.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ function main({ dur, len, type }) {
5151
if (err)
5252
fail(err, 'write');
5353

54-
writeReq.oncomplete = function(status, handle, req, err) {
54+
writeReq.oncomplete = function(status, handle, err) {
5555
if (err)
5656
fail(err, 'write');
5757
};
@@ -130,7 +130,7 @@ function main({ dur, len, type }) {
130130
fail(err, 'write');
131131
}
132132

133-
function afterWrite(err, handle, req) {
133+
function afterWrite(err, handle) {
134134
if (err)
135135
fail(err, 'write');
136136

benchmark/net/tcp-raw-s2c.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,14 @@ function main({ dur, len, type }) {
7474
fail(err, 'write');
7575
} else if (!writeReq.async) {
7676
process.nextTick(function() {
77-
afterWrite(null, clientHandle, writeReq);
77+
afterWrite(0, clientHandle);
7878
});
7979
}
8080
}
8181

82-
function afterWrite(status, handle, req, err) {
83-
if (err)
84-
fail(err, 'write');
82+
function afterWrite(status, handle) {
83+
if (status)
84+
fail(status, 'write');
8585

8686
while (clientHandle.writeQueueSize === 0)
8787
write();

lib/internal/http2/core.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,20 +1399,19 @@ function trackWriteState(stream, bytes) {
13991399
session[kHandle].chunksSentSinceLastWrite = 0;
14001400
}
14011401

1402-
function afterDoStreamWrite(status, handle, req) {
1402+
function afterDoStreamWrite(status, handle) {
14031403
const stream = handle[kOwner];
14041404
const session = stream[kSession];
14051405

14061406
stream[kUpdateTimer]();
14071407

1408-
const { bytes } = req;
1408+
const { bytes } = this;
14091409
stream[kState].writeQueueSize -= bytes;
14101410

14111411
if (session !== undefined)
14121412
session[kState].writeQueueSize -= bytes;
1413-
if (typeof req.callback === 'function')
1414-
req.callback(null);
1415-
req.handle = undefined;
1413+
if (typeof this.callback === 'function')
1414+
this.callback(null);
14161415
}
14171416

14181417
function streamOnResume() {

lib/internal/wrap_js_stream.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,9 @@ class JSStreamWrap extends Socket {
115115

116116
const handle = this._handle;
117117

118-
this.stream.end(() => {
119-
// Ensure that write was dispatched
120-
setImmediate(() => {
118+
setImmediate(() => {
119+
// Ensure that write is dispatched asynchronously.
120+
this.stream.end(() => {
121121
this.finishShutdown(handle, 0);
122122
});
123123
});

lib/net.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ function onSocketFinish() {
335335
}
336336

337337

338-
function afterShutdown(status, handle, req) {
338+
function afterShutdown(status, handle) {
339339
var self = handle.owner;
340340

341341
debug('afterShutdown destroyed=%j', self.destroyed,
@@ -869,12 +869,12 @@ protoGetter('bytesWritten', function bytesWritten() {
869869
});
870870

871871

872-
function afterWrite(status, handle, req, err) {
872+
function afterWrite(status, handle, err) {
873873
var self = handle.owner;
874874
if (self !== process.stderr && self !== process.stdout)
875875
debug('afterWrite', status);
876876

877-
if (req.async)
877+
if (this.async)
878878
self[kLastWriteQueueSize] = 0;
879879

880880
// callback may come after call to destroy.
@@ -884,9 +884,9 @@ function afterWrite(status, handle, req, err) {
884884
}
885885

886886
if (status < 0) {
887-
var ex = errnoException(status, 'write', req.error);
887+
var ex = errnoException(status, 'write', this.error);
888888
debug('write failure', ex);
889-
self.destroy(ex, req.cb);
889+
self.destroy(ex, this.cb);
890890
return;
891891
}
892892

@@ -895,8 +895,8 @@ function afterWrite(status, handle, req, err) {
895895
if (self !== process.stderr && self !== process.stdout)
896896
debug('afterWrite call cb');
897897

898-
if (req.cb)
899-
req.cb.call(undefined);
898+
if (this.cb)
899+
this.cb.call(undefined);
900900
}
901901

902902

src/env.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ class ModuleWrap;
306306
V(script_context_constructor_template, v8::FunctionTemplate) \
307307
V(script_data_constructor_function, v8::Function) \
308308
V(secure_context_constructor_template, v8::FunctionTemplate) \
309+
V(shutdown_wrap_constructor_function, v8::Function) \
309310
V(tcp_constructor_template, v8::FunctionTemplate) \
310311
V(tick_callback_function, v8::Function) \
311312
V(timers_callback_function, v8::Function) \

src/js_stream.cc

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,6 @@ int JSStream::DoShutdown(ShutdownWrap* req_wrap) {
9191
req_wrap->object()
9292
};
9393

94-
req_wrap->Dispatched();
95-
9694
TryCatch try_catch(env()->isolate());
9795
Local<Value> value;
9896
int value_int = UV_EPROTO;
@@ -127,8 +125,6 @@ int JSStream::DoWrite(WriteWrap* w,
127125
bufs_arr
128126
};
129127

130-
w->Dispatched();
131-
132128
TryCatch try_catch(env()->isolate());
133129
Local<Value> value;
134130
int value_int = UV_EPROTO;
@@ -154,9 +150,8 @@ void JSStream::New(const FunctionCallbackInfo<Value>& args) {
154150

155151
template <class Wrap>
156152
void JSStream::Finish(const FunctionCallbackInfo<Value>& args) {
157-
Wrap* w;
158153
CHECK(args[0]->IsObject());
159-
ASSIGN_OR_RETURN_UNWRAP(&w, args[0].As<Object>());
154+
Wrap* w = static_cast<Wrap*>(StreamReq::FromObject(args[0].As<Object>()));
160155

161156
w->Done(args[1]->Int32Value());
162157
}

src/node_http2.cc

Lines changed: 10 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1552,18 +1552,9 @@ void Http2Session::SendPendingData() {
15521552

15531553
chunks_sent_since_last_write_++;
15541554

1555-
// DoTryWrite may modify both the buffer list start itself and the
1556-
// base pointers/length of the individual buffers.
1557-
uv_buf_t* writebufs = *bufs;
1558-
if (stream_->DoTryWrite(&writebufs, &count) != 0 || count == 0) {
1559-
// All writes finished synchronously, nothing more to do here.
1560-
ClearOutgoing(0);
1561-
return;
1562-
}
1563-
1564-
WriteWrap* req = AllocateSend();
1565-
if (stream_->DoWrite(req, writebufs, count, nullptr) != 0) {
1566-
req->Dispose();
1555+
StreamWriteResult res = underlying_stream()->Write(*bufs, count);
1556+
if (!res.async) {
1557+
ClearOutgoing(res.err);
15671558
}
15681559

15691560
DEBUG_HTTP2SESSION2(this, "wants data in return? %d",
@@ -1649,15 +1640,6 @@ inline void Http2Session::SetChunksSinceLastWrite(size_t n) {
16491640
chunks_sent_since_last_write_ = n;
16501641
}
16511642

1652-
// Allocates the data buffer used to pass outbound data to the i/o stream.
1653-
WriteWrap* Http2Session::AllocateSend() {
1654-
HandleScope scope(env()->isolate());
1655-
Local<Object> obj =
1656-
env()->write_wrap_constructor_function()
1657-
->NewInstance(env()->context()).ToLocalChecked();
1658-
return WriteWrap::New(env(), obj, static_cast<StreamBase*>(stream_));
1659-
}
1660-
16611643
// Callback used to receive inbound data from the i/o stream
16621644
void Http2Session::OnStreamRead(ssize_t nread, const uv_buf_t& buf) {
16631645
Http2Scope h2scope(this);
@@ -1833,20 +1815,15 @@ inline void Http2Stream::Close(int32_t code) {
18331815
DEBUG_HTTP2STREAM2(this, "closed with code %d", code);
18341816
}
18351817

1836-
1837-
inline void Http2Stream::Shutdown() {
1838-
CHECK(!this->IsDestroyed());
1839-
Http2Scope h2scope(this);
1840-
flags_ |= NGHTTP2_STREAM_FLAG_SHUT;
1841-
CHECK_NE(nghttp2_session_resume_data(session_->session(), id_),
1842-
NGHTTP2_ERR_NOMEM);
1843-
DEBUG_HTTP2STREAM(this, "writable side shutdown");
1844-
}
1845-
18461818
int Http2Stream::DoShutdown(ShutdownWrap* req_wrap) {
18471819
CHECK(!this->IsDestroyed());
1848-
req_wrap->Dispatched();
1849-
Shutdown();
1820+
{
1821+
Http2Scope h2scope(this);
1822+
flags_ |= NGHTTP2_STREAM_FLAG_SHUT;
1823+
CHECK_NE(nghttp2_session_resume_data(session_->session(), id_),
1824+
NGHTTP2_ERR_NOMEM);
1825+
DEBUG_HTTP2STREAM(this, "writable side shutdown");
1826+
}
18501827
req_wrap->Done(0);
18511828
return 0;
18521829
}
@@ -2038,7 +2015,6 @@ inline int Http2Stream::DoWrite(WriteWrap* req_wrap,
20382015
CHECK_EQ(send_handle, nullptr);
20392016
Http2Scope h2scope(this);
20402017
session_->SetChunksSinceLastWrite();
2041-
req_wrap->Dispatched();
20422018
if (!IsWritable()) {
20432019
req_wrap->Done(UV_EOF);
20442020
return 0;

src/node_http2.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -601,9 +601,6 @@ class Http2Stream : public AsyncWrap,
601601

602602
inline void Close(int32_t code);
603603

604-
// Shutdown the writable side of the stream
605-
inline void Shutdown();
606-
607604
// Destroy this stream instance and free all held memory.
608605
inline void Destroy();
609606

@@ -818,6 +815,10 @@ class Http2Session : public AsyncWrap, public StreamListener {
818815

819816
inline void EmitStatistics();
820817

818+
inline StreamBase* underlying_stream() {
819+
return static_cast<StreamBase*>(stream_);
820+
}
821+
821822
void Start();
822823
void Stop();
823824
void Close(uint32_t code = NGHTTP2_NO_ERROR,
@@ -907,8 +908,6 @@ class Http2Session : public AsyncWrap, public StreamListener {
907908
template <get_setting fn>
908909
static void GetSettings(const FunctionCallbackInfo<Value>& args);
909910

910-
WriteWrap* AllocateSend();
911-
912911
uv_loop_t* event_loop() const {
913912
return env()->event_loop();
914913
}

0 commit comments

Comments
 (0)