Skip to content
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

Closed
wants to merge 2 commits into from
Closed

Conversation

addaleax
Copy link
Member

Another first step into making parts of the code base more accessible.

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • commit message follows commit guidelines
Affected core subsystem(s)

lib/

@nodejs-github-bot nodejs-github-bot added build Issues and PRs related to build files or the CI. net Issues and PRs related to the net subsystem. stream Issues and PRs related to the stream subsystem. labels Oct 12, 2017
@addaleax addaleax changed the title lib: reactor stream_wrap lib: refactor stream_wrap Oct 12, 2017
@@ -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);
}
Copy link
Member

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?

Copy link
Member

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
Copy link
Member

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.

* 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
Copy link
Member

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 ....

* 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 {
Copy link
Member

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.

Copy link
Member

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.

Copy link
Member Author

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.

Copy link
Member

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();
Copy link
Member

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?

Copy link
Member Author

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?

@jasnell jasnell requested a review from mcollina October 12, 2017 12:58
const ondata = (chunk) => {
if (typeof chunk === 'string' ||
stream._readableState.objectMode === true) {
// Make sure that no further `data` events will happen
Copy link
Member

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.

@jasnell jasnell added the semver-major PRs that contain breaking changes and should be released in the next major version. label Oct 12, 2017
@jasnell
Copy link
Member

jasnell commented Oct 12, 2017

Marking semver-major defensively. This is a change to an _-prefixed file, but it's one that has been around for quite some time. @ChALkeR ...would it be possible to get some insights into what (if any) userrland modules are using this that could be impacted?

Copy link
Member

@mcollina mcollina left a 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');
Copy link
Member

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.

Copy link
Member Author

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.

* 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 {
Copy link
Member

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);
Copy link
Member

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);
};
Copy link
Member

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);
});
}
Copy link
Member

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();
});
}
Copy link
Member

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.

@addaleax
Copy link
Member Author

Marking semver-major defensively. This is a change to an _-prefixed file, but it's one that has been around for quite some time. @ChALkeR ...would it be possible to get some insights into what (if any) userrland modules are using this that could be impacted?

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…)

@addaleax
Copy link
Member Author

addaleax commented Oct 12, 2017

@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.

@jasnell
Copy link
Member

jasnell commented Oct 12, 2017

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.

@addaleax
Copy link
Member Author

Yeah, we can wait for an npm search for it. :)

@mcollina
Copy link
Member

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.

@jasnell
Copy link
Member

jasnell commented Oct 13, 2017

Definitely agree with @mcollina about wanting to avoid the closures if possible (looking them over, it should definitely be easily possible).

@addaleax
Copy link
Member Author

I don’t disagree about avoiding closures in general, but I would really say that’s not the scope of this PR.

@addaleax
Copy link
Member Author

Also, if this is semver-major, could you give a hypothetical example of code that might break?

@jasnell
Copy link
Member

jasnell commented Oct 13, 2017

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.

@addaleax
Copy link
Member Author

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) :)

@addaleax addaleax removed the semver-major PRs that contain breaking changes and should be released in the next major version. label Oct 17, 2017
@addaleax
Copy link
Member Author

This makes a subsequent possible deprecation easier.

PR-URL: nodejs#16158
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Franziska Hinkelmann <[email protected]>
addaleax added a commit to addaleax/node that referenced this pull request Oct 30, 2017
This makes a subsequent possible deprecation easier.

PR-URL: nodejs#16158
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Franziska Hinkelmann <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
addaleax added a commit to addaleax/node that referenced this pull request Oct 30, 2017
PR-URL: nodejs#16158
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Franziska Hinkelmann <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
gibfahn pushed a commit that referenced this pull request Oct 30, 2017
This makes a subsequent possible deprecation easier.

PR-URL: #16158
Backport-PR-URL: #16626
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Franziska Hinkelmann <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
gibfahn pushed a commit that referenced this pull request Oct 30, 2017
PR-URL: #16158
Backport-PR-URL: #16626
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Franziska Hinkelmann <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
gibfahn pushed a commit that referenced this pull request Oct 31, 2017
This makes a subsequent possible deprecation easier.

PR-URL: #16158
Backport-PR-URL: #16626
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Franziska Hinkelmann <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
gibfahn pushed a commit that referenced this pull request Oct 31, 2017
PR-URL: #16158
Backport-PR-URL: #16626
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Franziska Hinkelmann <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
@gibfahn gibfahn mentioned this pull request Oct 31, 2017
@MylesBorins
Copy link
Contributor

@addaleax I've added the don't land label for 6.x... lmk if we should change that

addaleax added a commit to ayojs/ayo that referenced this pull request Dec 7, 2017
This makes a subsequent possible deprecation easier.

PR-URL: nodejs/node#16158
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Franziska Hinkelmann <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
addaleax added a commit to ayojs/ayo that referenced this pull request Dec 7, 2017
PR-URL: nodejs/node#16158
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Franziska Hinkelmann <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
@sam-github sam-github mentioned this pull request Feb 21, 2019
3 tasks
sam-github added a commit to sam-github/node that referenced this pull request Mar 2, 2019
Its unused by node, and doesn't have a reasonable use outside of node.

See: nodejs#25153
See: nodejs#16158
sam-github added a commit that referenced this pull request Mar 4, 2019
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 <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
build Issues and PRs related to build files or the CI. net Issues and PRs related to the net subsystem. stream Issues and PRs related to the stream subsystem.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants