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

net: replace _writableState with writableFinished #27974

Merged
merged 0 commits into from
Jun 26, 2019
Merged

Conversation

Trott
Copy link
Member

@Trott Trott commented May 30, 2019

Replace use of quasi-private streams _writableState property in net.js with
use of the public streams finished() method.

Refs: #445

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • commit message follows commit guidelines

@Trott
Copy link
Member Author

Trott commented May 30, 2019

/ping @mcollina

@nodejs-github-bot

This comment has been minimized.

@nodejs-github-bot
Copy link
Collaborator

@Trott Trott added author ready PRs that have at least one approval, no pending requests for changes, and a CI started. net Issues and PRs related to the net subsystem. stream Issues and PRs related to the stream subsystem. labels May 30, 2019
@nodejs-github-bot
Copy link
Collaborator

@lpinca
Copy link
Member

lpinca commented May 30, 2019

Since this already had a few approvals I'm not going to block it but in my opinion this:

  • hinders readability (I have to jump to to eos() definition to see what it does).
  • trades simplicity and efficiency for complexity (eos() does a lot of unneeded work in this case).
  • still uses the "private" _writableState property indirectly via eos().

I see only disadvantages.

@lpinca
Copy link
Member

lpinca commented May 31, 2019

Commit message title and body should be updated as they are misleading. There is no _finished property.

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

@Trott Trott removed the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label May 31, 2019
@Trott Trott changed the title net: replace _finished with finished() net: replace _writableState with finished() May 31, 2019
@Trott
Copy link
Member Author

Trott commented May 31, 2019

Since this already had a few approvals I'm not going to block it but in my opinion this:

  • hinders readability (I have to jump to to eos() definition to see what it does).
  • trades simplicity and efficiency for complexity (eos() does a lot of unneeded work in this case).
  • still uses the "private" _writableState property indirectly via eos().

I see only disadvantages.

@lpinca I find myself agreeing more than disagreeing with your points. If you were trying to adjust this code in the spirit of #445, what would you recommend? (I can think of a few things, but opted for this as it didn't involve adding new stuff to the stream module, which I would expect to meet resistance.) Or is #445 mostly misguided in your view?

@lpinca
Copy link
Member

lpinca commented Jun 1, 2019

I would add a getter to Writable.prototype like

but yes I think #445 is a bit misguided because it means exposing most (if not all) attributes of ReadableState and WritableState. There are cases also in userland where you really need to read those properties. end-of-stream is just an example.

I think _readableState and _writableState should be public and documented as "use at your own risk".

@Trott
Copy link
Member Author

Trott commented Jun 1, 2019

I would add a getter to Writable.prototype like

but yes I think #445 is a bit misguided because it means exposing most (if not all) attributes of ReadableState and WritableState. There are cases also in userland where you really need to read those properties. end-of-stream is just an example.

I think _readableState and _writableState should be public and documented as "use at your own risk".

Hey, @nodejs/streams, what do you think?

@Trott
Copy link
Member Author

Trott commented Jun 1, 2019

(Is @nodejs/streams the wrong team to ask? Who is the right team?)

lib/net.js Outdated
@@ -551,13 +551,9 @@ function onReadableStreamEnd() {


Socket.prototype.destroySoon = function() {
stream.finished(this, { error: false, readable: false }, this.destroy);
Copy link
Member

@ronag ronag Jun 1, 2019

Choose a reason for hiding this comment

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

Note sure if the callback can be called synchronously? Just to be safe... put it after the end() call? i.e. keep the order as it was

Copy link
Member

Choose a reason for hiding this comment

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

eos() unconditionally adds one listener for the 'finish' event and one for 'close' event (and actually another for 'end' event even if the readable option is false).

If _writableState.finished is already true then the 'finish' event won't be emitted and it will wait for 'close'. Even if this is emitted synchronously it is not a problem because it means the socket is already destroyed and no longer writable.

If _writableState.finished is false then the 'finish' event won't be emitted until socket.end() is called and if this already happened then the socket is no longer writable.

So the order should not matter. However I can see a case where the behavior is different.

'use strict';

const net = require('net');

const server = net.createServer(function(socket) {
  socket.write('foo');
});

server.listen(function() {
  const socket = net.connect(this.address().port, function() {
    socket.on('finish', function() {
      socket.destroySoon();
    });
    socket.on('close', function() {
      console.log('close');
    });

    setTimeout(function() {
      socket.end();
    }, 100);
  });
});

Yes, it's a fabricated example that probably will never happen in reality but with this patch the socket is not destroyed ('close' is not emitted) until the buffered data is actually read. This is not the case with the current implementation of destroySoon().

@mcollina
Copy link
Member

mcollina commented Jun 1, 2019

Close this PR and leave the code alone. (#445 should probably be closed? Maybe document _readableState and _writableState, even if we discourage people from using them?)

Accessing _readableState and _writableState  directly is really a bad idea. They contain our buffering system, and those should not really be touched. I fully agree on #445.

A getter like @lpinca proposes above is the way to go?

I'm +1 to that approach (#27974 (comment)).
It's also consistent with the approach we have been following to fix #445.

This PR is the way to go?

I'm +1 to this PR as well. However I concur that finished does a lot of things, and adding a getter would be the most performant way to solve the problem.


(Is @nodejs/streams the wrong team to ask? Who is the right team?)

@nodejs/streams is likely the team to target for this question.

@lpinca
Copy link
Member

lpinca commented Jun 1, 2019

Accessing _readableState and _writableState directly is really a bad idea. They contain our buffering system, and those should not really be touched.

I think if someone messes with the internal buffers it means they either know what they are doing or want to break things intentionally. This is the reason for "use at your own risk".

Take this data for example https://github.com/search?p=1&q=_readableState&type=Code, just from the first results we see use of

  • resumeScheduled
  • flowing
  • pipesCount

Yes, exposing all of that via getters is an option, but it does not seem the right solution to me.

@Trott Trott added the wip Issues and PRs that are still a work in progress. label Jun 2, 2019
@Trott
Copy link
Member Author

Trott commented Jun 2, 2019

Marking this WIP for now but if someone else wants to open a PR that does this the "right" way before I get around to it, by all means, please do.

@Trott Trott closed this Jun 25, 2019
@Trott Trott removed the wip Issues and PRs that are still a work in progress. label Jun 25, 2019
@Trott Trott reopened this Jun 25, 2019
@nodejs-github-bot
Copy link
Collaborator

@Trott
Copy link
Member Author

Trott commented Jun 25, 2019

Used the writableFinished property as implemented by @zero1five in #28007. Removed WIP label. I think this is ready for re-reviews.

@nodejs-github-bot
Copy link
Collaborator

@Trott Trott added the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Jun 26, 2019
@Trott
Copy link
Member Author

Trott commented Jun 26, 2019

(@addaleax Sorry, I didn't meant to request a re-review from you since you had already re-reviewed, but I don't see a way to undo my request in the GitHub interface.)

@Trott Trott changed the title net: replace _writableState with finished() net: replace _writableState with writableFinished Jun 26, 2019
@Trott
Copy link
Member Author

Trott commented Jun 26, 2019

Landed in 3832713

@Trott Trott deleted the finished branch June 26, 2019 15:15
@Trott Trott merged commit 3832713 into nodejs:master Jun 26, 2019
targos pushed a commit that referenced this pull request Jul 2, 2019
Replace usage of quasi-private _writableState.finished with public
writableFinished property.

PR-URL: #27974
Refs: #445
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
@targos targos mentioned this pull request Jul 2, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
author ready PRs that have at least one approval, no pending requests for changes, and a CI started. 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.

9 participants