-
Notifications
You must be signed in to change notification settings - Fork 29.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
lib: refactor stream_wrap #16158
lib: refactor stream_wrap #16158
Conversation
@@ -248,7 +248,7 @@ function Socket(options) { | |||
this._handle.reading = false; | |||
this._handle.readStop(); | |||
this._readableState.flowing = false; | |||
} else { | |||
} else if (!options.manualStart) { | |||
this.read(0); | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add an else { error...}
case here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Never mind, this is not an exhaustive if else.
const errors = require('internal/errors'); | ||
|
||
/* This class serves as a wrapper for when the C++ side of Node wants access | ||
* to a standard JS stream. For example, TLS or HTTP do not operate on network |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
on a network resource or on network resources.
lib/internal/wrap_js_stream.js
Outdated
* For the common case, i.e. a TLS socket wrapping around a net.Socket, we | ||
* can skip going through the JS layer and let TLS access the raw C++ handle | ||
* of a net.Socket. The flipside of this is that, to maintain composability, | ||
* a way to create "fake" net.Socket instances that call back into a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: change to active voice:
The flipside of this is that, to maintain composability, we need a way to create ....
lib/internal/wrap_js_stream.js
Outdated
* a way to create "fake" net.Socket instances that call back into a | ||
* "real" JavaScript stream is needed. JSStreamWrap is exactly this. | ||
*/ | ||
class JSStreamWrap extends Socket { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to be certain that the change to the ES6 class is not going to break the planet, here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we are, there is no constructor without new in the original one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Also, this class exposes only limited functionality – you effectively can’t use it for any other purpose than what Node core does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. I can't come up with anything specific that would break so I'm ++
debug('close'); | ||
this.doClose(cb); | ||
}; | ||
handle.isAlive = () => this.isAlive(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do these really need to be closures?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They were before. Can we defer optimizing to later work?
lib/internal/wrap_js_stream.js
Outdated
const ondata = (chunk) => { | ||
if (typeof chunk === 'string' || | ||
stream._readableState.objectMode === true) { | ||
// Make sure that no further `data` events will happen |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super-Nit: period at the end of the comment.
Marking semver-major defensively. This is a change to an |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very good work! I think we can take the refactoring a bit further and avoid some closure allocations.
cb(); | ||
}); | ||
}; | ||
module.exports = require('internal/wrap_js_stream'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would deprecate this file, people should not be requiring this in any form.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we go with semver-major, yes.
lib/internal/wrap_js_stream.js
Outdated
* a way to create "fake" net.Socket instances that call back into a | ||
* "real" JavaScript stream is needed. JSStreamWrap is exactly this. | ||
*/ | ||
class JSStreamWrap extends Socket { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we are, there is no constructor without new in the original one.
handle.onreadstart = () => this.readStart(); | ||
handle.onreadstop = () => this.readStop(); | ||
handle.onshutdown = (req) => this.doShutdown(req); | ||
handle.onwrite = (req, bufs) => this.doWrite(req, bufs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some of those would be better of to be bind()
. Now it's faster than allocating a closure.
debug('data', chunk.length); | ||
if (this._handle) | ||
this._handle.readBuffer(chunk); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer if we could optimize this function so that it's not a closure anymore, but a top level function.
handle.doAfterWrite(req); | ||
handle.finishWrite(req, errCode); | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we avoid allocating two closures for every write? I know it would make the code uglier, but it's probably the right moment to do.
The innermost can be replaced by a top-level function with handle, item, req and errCode as parameters. The top-level one can be allocated in the constructor, and we can store pending
as an object property (maybe behind a symbol).
assert.strictEqual(this._handle, null); | ||
cb(); | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function should really be top-level. The while loop can really get cpu-intensive.
I would be extremely surprised if something comes up. Are you marking this semver-major out of principle or because you can actually imagine a use case somebody is having? (If somebody uses this, it’s probably @indutny because there’s basically nobody else around who knows what it does…) |
@mcollina We can talk about optimizations, but this isn’t creating any new closures – can we avoid nitpicking for an actual PR that does those optimizations? Also, to reiterate what the comment states: This is the slow path. Optimizing this doesn’t actually have much real-world impact. |
Marking it semver-major out of principle and an abundance of caution. I'm good with it landing as a patch, but we should do a small amount of due diligence first. |
Yeah, we can wait for an npm search for it. :) |
Currently git is not marking these files as moved, but rather as new files. If this is marked semver-major, this makes sense, and we can as well refactor and improve them. I think we should land this as semver-major, and spend a little more time improving this. I propose you keep the first commit in this PR. Once that is landed, we do another PR with the ES6 refactoring and we deprecate the old file. |
Definitely agree with @mcollina about wanting to avoid the closures if possible (looking them over, it should definitely be easily possible). |
I don’t disagree about avoiding closures in general, but I would really say that’s not the scope of this PR. |
Also, if this is semver-major, could you give a hypothetical example of code that might break? |
There likely isn't any, again it's only defensive. Now that I've had a moment free to do a search on github and Google and I'm not seeing anything of any concern. If we cannot really identify anything that would break, I'm good with dropping the major label. I disagree on the closure bit but I can open a separate pr that handles that. |
I’ll at least try to get @ChALkeR’s tooling to run again, it might be nice anyway if somebody else had practice in that (and I know I got it to build at least once) :) |
8fc47f2
to
4cd793f
Compare
This makes a subsequent possible deprecation easier. PR-URL: nodejs#16158 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
This makes a subsequent possible deprecation easier. PR-URL: nodejs#16158 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de>
PR-URL: nodejs#16158 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de>
@addaleax I've added the don't land label for 6.x... lmk if we should change that |
This makes a subsequent possible deprecation easier. PR-URL: nodejs/node#16158 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de>
PR-URL: nodejs/node#16158 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Its unused by node, and doesn't have a reasonable use outside of node. See: nodejs#25153 See: nodejs#16158
Its unused by node, and doesn't have a reasonable use outside of node. See: #25153 See: #16158 PR-URL: #26245 Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Another first step into making parts of the code base more accessible.
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
lib/