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

stream: use more explicit statements #13863

Closed
wants to merge 1 commit into from

Conversation

BridgeAR
Copy link
Member

Writing explicit statements produces better outcomes from the
compiler.
More important though: the instanceof Buffer check is expensive
and can be avoided as nothing besides strings could be passed
to the handler. This also fixes a TODO entry.

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

streams

@nodejs-github-bot nodejs-github-bot added the stream Issues and PRs related to the stream subsystem. label Jun 22, 2017
@mscdex
Copy link
Contributor

mscdex commented Jun 22, 2017

Writing explicit statements produces better outcomes from the
compiler.

Can you show how you determined this? Also, what is "better" ?

@BridgeAR
Copy link
Member Author

@mscdex this comes from @bmeurer (e.g. on a meetup)

@jasnell
Copy link
Member

jasnell commented Jun 22, 2017

Ping @nodejs/streams

@mscdex
Copy link
Contributor

mscdex commented Jun 22, 2017

@BridgeAR That leaves some questions though, like:

  • What version(s) of V8 does that pertain to? 5.9? 6.0? 6.1? Is it something that is/can be backported to 5.9/6.0/etc.?

  • Is this specific to undefined? Someone specifically asked about null in that linked video, but it wasn't clear what the answer to that is/was or if this is an optimization that works for any explicit, strict equality/inequality check.

@TimothyGu
Copy link
Member

nothing besides strings could be passed to the handler

How can you be sure of this? If you want to get rid of the instanceof check, Object.getPrototypeOf() === Buffer.prototype or process.binding('util').isUint8Array is generally faster.

@mcollina
Copy link
Member

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.

LGTM if CI is green

@BridgeAR
Copy link
Member Author

@TimothyGu I forgot about the object mode even though it does not really work with the object mode and the error thrown in that situation is actually wrong. I added a test for the object mode and changed to throw that error always when using objectMode. Otherwise using objectMode would result in a weird situation where you can theoretically use this by only using Buffers but nothing else.
Besides being in the objectMode the data event can only emit strings or Buffers.

@mscdex there is more to read about this in his blog post. As far as I know it's mainly about Turbofan and that being explicit is always best but I guess @bmeurer can answer these questions better than me.

@@ -47,12 +44,12 @@ function StreamWrap(stream) {
self.emit('error', err);
});
this.stream.on('data', function ondata(chunk) {
if (!(chunk instanceof Buffer)) {
if (typeof chunk === 'string' || this._readableState.objectMode === true) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The object mode check could actually be moved in the StreamWrap constructor but it is currently possible to change the objectMode variable from an existing stream and in that case the upper check would not be sufficient anymore.
It is explicitly noted in the docs that this is not safe but I'm thinking about opening a PR to make the objectMode read only.

@mcollina do you think that's reasonable?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Streams implementors often change objectMode after the fact, so we cannot assume that. It'd a semver-major change, and several of us are -1 on those.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What you did here is ok.

@BridgeAR
Copy link
Member Author

PTAL

// Make sure that no further `data` events will happen
this.pause();
this.removeListener('data', ondata);

self.emit('error', new errors.Error('ERR_STREAM_HAS_STRINGDECODER'));
self.emit('error', new errors.Error('ERR_STREAM_WRAP'));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this error code change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the error code was very specific and somewhat misleading that objectMode would or should not trigger this even though objectMode always would have resulted in a misleading error since it's first existence.

I think now it better represents both cases. I do see that it's not ideal to rename the code though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that I don't believe the other error code had actually shipped in a release yet, this is fine. Definitely makes this semver-major tho.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new error code needs to be included in the docs tho

@mcollina
Copy link
Member

@mcollina
Copy link
Member

The linter is failing, can you fix that? make lint will show them.

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

I'm flagging this as semver-major because it changes the error code.

cc @jasnell

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.

LGTM when the linter is ok.

@@ -76,7 +76,7 @@ function afterTransform(er, data) {

var cb = ts.writecb;

if (!cb) {
if (cb === null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This potentially could be a breaking change given that it would miss other falsy values potentially passed for cb

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked. We are setting this internally, it's not user-driven.

Using objectMode with stream_wrap has not worked properly
before and would end in an error.
Therefore prohibit the usage of objectMode alltogether.

This also improves the handling performance due to the
cheaper chunk check and by using explicit statements as they
produce better code from the compiler.
@BridgeAR
Copy link
Member Author

BridgeAR commented Jun 29, 2017

Comment addressed and rebased due to a conflict.

@mcollina I could change the error in a separate commit to allow the main change without being semver-major if you like me to. But IMHO this is not semver-major as the error code has not yet landed in any release (to my best knowledge).

@mcollina mcollina added dont-land-on-v4.x and removed semver-major PRs that contain breaking changes and should be released in the next major version. labels Jun 29, 2017
@mcollina
Copy link
Member

@mcollina
Copy link
Member

Failures are unrelated, landing.

@mcollina
Copy link
Member

Landed as 1b54371.

@mcollina mcollina closed this Jun 29, 2017
mcollina pushed a commit that referenced this pull request Jun 29, 2017
Using objectMode with stream_wrap has not worked properly
before and would end in an error.
Therefore prohibit the usage of objectMode alltogether.

This also improves the handling performance due to the
cheaper chunk check and by using explicit statements as they
produce better code from the compiler.

PR-URL: #13863
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
@BridgeAR BridgeAR added the performance Issues and PRs related to the performance of Node.js. label Sep 14, 2017
@BridgeAR BridgeAR deleted the improve-streams branch April 1, 2019 23:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
performance Issues and PRs related to the performance of Node.js. stream Issues and PRs related to the stream subsystem.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants