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: use actual Timeout instances on Sockets #11154

Closed

Conversation

Fishrock123
Copy link
Contributor

@Fishrock123 Fishrock123 commented Feb 3, 2017

This makes net.Sockets use actual Timeout objects in a _timeout property, rather than making the socket itself a timer and appending properties to it directly.

This should make the code generally easier to understand, and might also prevent some deopts from properties being changes on the socket itself.

It is possible this could effect performance either better or worse, but I highly doubt it would be a significant difference. I'll try to run benchmarks on it in the coming days, but if anyone else would like to that would also be appreciated.

This also exposes timers.Timeout so as to avoid a circular dependency with the new lib/internal/timers.js, but we might not want that so I should be able to refactor more of timers into the internals file if necessary. Tagging as semver-minor for now due to this. I could also split that into separate commits.

Made live on https://twitch.tv/nodesource

CI: https://ci.nodejs.org/job/node-test-pull-request/6202/

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

net, timers

@Fishrock123 Fishrock123 added net Issues and PRs related to the net subsystem. semver-minor PRs that contain new features and should be released in the next minor version. timers Issues and PRs related to the timers subsystem / setImmediate, setInterval, setTimeout. labels Feb 3, 2017
@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. timers Issues and PRs related to the timers subsystem / setImmediate, setInterval, setTimeout. labels Feb 3, 2017
@Fishrock123 Fishrock123 changed the title net: use actual Timeout instance on Sockets net: use actual Timeout instances on Sockets Feb 3, 2017
lib/net.js Outdated
for (var s = this; s !== null; s = s._parent)
timers._unrefActive(s);
for (var s = this; s !== null; s = s._parent) {
// if (!s._timeout || s._timeout._idleTimeout === -1) continue;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you remove the commented code.

lib/net.js Outdated
timers._unrefActive(s);
for (var s = this; s !== null; s = s._parent) {
// if (!s._timeout || s._timeout._idleTimeout === -1) continue;
if (!s._timeout) continue;
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe a result of the commented code, but this could be

if (s._timeout)
  timers._unrefActive(s._timeout);

@Fishrock123 Fishrock123 force-pushed the use-timeout-in-net-socket branch from 14bebdf to 18ef0d0 Compare February 3, 2017 21:36
@Fishrock123
Copy link
Contributor Author

Ah right, forgot to remove that before PRing. Updated, new CI: https://ci.nodejs.org/job/node-test-pull-request/6203/

lib/net.js Outdated
@@ -133,6 +134,7 @@ function Socket(options) {
this._handle = null;
this._parent = null;
this._host = null;
this._timeout = null;
Copy link
Member

Choose a reason for hiding this comment

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

Rather than introducing yet another _ prefixed property, I'd much prefer to use a Symbol.
Also, given that I'm following an identical pattern in the http2 work, I'd like that Symbol to be reusable (perhaps as an export off the internal/timers.js this PR creates

Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't that part of the implementation of a Timeout instance? i.e. didn't a socket already have it, it just wasn't declared in the constructor?

Copy link
Member

Choose a reason for hiding this comment

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

Not that I'm able to see. There are zero hits anywhere in the source for a _timeout property

Copy link
Contributor

Choose a reason for hiding this comment

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

It gets added if Socket#setTimeout() is called iirc https://github.com/nodejs/node/blob/master/lib/net.js#L330

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Apologies, I was thinking of ._idleTimeout. Disregard

@Fishrock123
Copy link
Contributor Author

It should be noted that in situations where timer properties were previously available on the Socket object, they will not be after this patch. I highly doubt people rely on those though, since they may not always be there to begin with.

const timers = require('timers');

// Timeout values > TIMEOUT_MAX are set to 1.
const TIMEOUT_MAX = 2147483647; // 2^31-1
Copy link
Member

Choose a reason for hiding this comment

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

Can timers.js re-use this value by importing it from here?

@lpinca
Copy link
Member

lpinca commented Feb 4, 2017

Isn't this semver-major?

@jasnell
Copy link
Member

jasnell commented Feb 4, 2017

I think I would lean more towards semver-major on this, just to be careful

@evanlucas
Copy link
Contributor

+1 to Semver-major

@Fishrock123 Fishrock123 added semver-major PRs that contain breaking changes and should be released in the next major version. and removed semver-minor PRs that contain new features and should be released in the next minor version. labels Feb 4, 2017
@Fishrock123
Copy link
Contributor Author

Theoretically semver-major yes. If people seem to think it should be then so be it, I don't hold strongly one way or other.

@Fishrock123
Copy link
Contributor Author

@Fishrock123
Copy link
Contributor Author

Addressed most of the remaining comments.

@jasnell I made the new property hidden using a kTimeout symbol. I'm slightly worried if anyone still needed to access the timeout directly on a socket after this change. Maybe we could just expose a new API if that was really necessary, or perhaps the existing APIs already cover anything that could be needed.

@jasnell
Copy link
Member

jasnell commented Feb 10, 2017

We should be safe but if someone really needed that access then adding a new API shouldn't be out of the question.

@jasnell
Copy link
Member

jasnell commented Mar 22, 2017

@Fishrock123 ... ping... what's the status on this one?

@Fishrock123
Copy link
Contributor Author

Ugh, I'm just worried that we will end up breaking some module or something.

Would anyone be calling e.g. timers.active() directly on a Socket? timers.unenroll()? I mean I highly doubt it so probably not but who knows?

... new CI: https://ci.nodejs.org/job/node-test-pull-request/6985/

Guess we might as well land if it looks good. @nodejs/ctc if anyone else has significant reservations.

@mscdex
Copy link
Contributor

mscdex commented Mar 22, 2017

Can the new internal module use the module.exports = {} format for consistency?

@Fishrock123 Fishrock123 force-pushed the use-timeout-in-net-socket branch from 768f5ec to 3c49be6 Compare March 22, 2017 22:57
@Fishrock123
Copy link
Contributor Author

@mscdex Done, updated and rebased.

CI: https://ci.nodejs.org/job/node-test-pull-request/6987/


if (msecs < 0 || !isFinite(msecs)) {
throw new RangeError('"msecs" argument must be ' +
'a non-negative finite number, was ' + msecs);
Copy link
Contributor

@mscdex mscdex Apr 23, 2017

Choose a reason for hiding this comment

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

I prefer 'positive, finite number'. I recall having a similar discussion in a previous PR about using 'non-negative' vs 'positive' in error messages. To me it sounds more straight-forward.

As far as including the original value in the error message goes, I don't know if we've "standardized" on how it's presented, but to me the current wording is a little awkward. Perhaps it could be more explicit, like

'... must be a positive, finite number. Saw value: ' + msecs

or

'... must be a positive, finite number. Received value: ' + msecs

Copy link
Member

Choose a reason for hiding this comment

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

Zero is an allowed value but is not a positive number, though.

Copy link
Contributor

@mscdex mscdex Apr 23, 2017

Choose a reason for hiding this comment

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

Zero can be positive or negative, at least as far as Javascript is concerned.

Copy link
Contributor

Choose a reason for hiding this comment

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

FWIW here was the previous PR I had in mind where "non-negative" was dropped in favor of "positive": #10769

@Fishrock123
Copy link
Contributor Author

@mscdex Does any of this really matter, since it is internal anyways?

@mscdex
Copy link
Contributor

mscdex commented Apr 23, 2017

I think to check the performance difference of these changes, we'd need to either create a new benchmark or possibly run one of the http benchmarks (since timeouts may be used there) because those in benchmarks/net do not exercise socket.setTimeout().

@mscdex
Copy link
Contributor

mscdex commented Apr 23, 2017

@Fishrock123 What do you mean "any of this?"

@mscdex
Copy link
Contributor

mscdex commented Apr 24, 2017

Just to add, just because this function is internal does not mean suggestions should be ignored, especially because functions like setUnrefTimeout() are both used during runtime and are passed user values like msecs.

@BridgeAR
Copy link
Member

@Fishrock123 this needs a rebase

@BridgeAR BridgeAR added the stalled Issues and PRs that are stalled. label Sep 8, 2017
@BridgeAR
Copy link
Member

I am closing this due to long inactivity and no response.

@Fishrock123 please reopen if you would like to follow up on this.

@BridgeAR BridgeAR closed this Sep 20, 2017
@Fishrock123
Copy link
Contributor Author

This is something I am still interested in pursuing in the very near future.

@Fishrock123 Fishrock123 reopened this Oct 7, 2017
@Fishrock123
Copy link
Contributor Author

Still very busy but on my short-term todo list

@Fishrock123 Fishrock123 force-pushed the use-timeout-in-net-socket branch from 8ca9329 to 0113d10 Compare November 17, 2017 01:57
@BridgeAR BridgeAR added author ready PRs that have at least one approval, no pending requests for changes, and a CI started. and removed stalled Issues and PRs that are stalled. labels Nov 22, 2017
@BridgeAR
Copy link
Member

@Fishrock123 I did not fully check if all comments were addressed or if you just rebased. Could you have another look? :-)

@BridgeAR
Copy link
Member

@Fishrock123
Copy link
Contributor Author

FUN FACT: this patch still needed all those internal checks!

...

@Fishrock123 Fishrock123 removed author ready PRs that have at least one approval, no pending requests for changes, and a CI started. build Issues and PRs related to build files or the CI. labels Nov 23, 2017
@Fishrock123 Fishrock123 force-pushed the use-timeout-in-net-socket branch from 0113d10 to 606abb3 Compare November 23, 2017 01:18
@Fishrock123
Copy link
Contributor Author

Fishrock123 commented Nov 23, 2017

This should fail: https://ci.nodejs.org/job/node-test-pull-request/11650/

I can't get these to pass, I'm not sure why a clientError is emitted (this was not a problem when the patch was first ready to land).

Edit: to clarify, it fails to parse the request chunk... somehow.

=== release test-http-server-keep-alive-timeout-slow-client-headers ===
Path: sequential/test-http-server-keep-alive-timeout-slow-client-headers
'HTTP/1.1 200 OK\r\nDate: Thu, 23 Nov 2017 01:12:46 GMT\r\nConnection: keep-alive\r\nContent-Length: 0\r\n\r\n'
{ Error: Parse Error
    at socketOnEnd (_http_server.js:424:20)
    at Socket.emit (events.js:164:20)
    at endReadableNT (_stream_readable.js:1062:12)
    at _combinedTickCallback (internal/process/next_tick.js:137:11)
    at process._tickCallback (internal/process/next_tick.js:179:9) bytesParsed: 0, code: 'HPE_INVALID_EOF_STATE' }
events.js:136
      throw er; // Unhandled 'error' event
      ^

Error [ERR_STREAM_WRITE_AFTER_END]: write after end
    at writeAfterEnd (_stream_writable.js:237:12)
    at Socket.Writable.write (_stream_writable.js:288:5)
    at Socket.write (net.js:739:40)
    at Timeout.setTimeout [as _onTimeout] (/Users/Jeremiah/Documents/node/test/sequential/test-http-server-keep-alive-timeout-slow-client-headers.js:41:14)
    at ontimeout (timers.js:489:11)
    at tryOnTimeout (timers.js:313:5)
    at Timer.listOnTimeout (timers.js:273:5)
Command: out/Release/node /Users/Jeremiah/Documents/node/test/sequential/test-http-server-keep-alive-timeout-slow-client-headers.js
=== release test-http-server-keep-alive-timeout-slow-server ===
Path: sequential/test-http-server-keep-alive-timeout-slow-server
events.js:136
      throw er; // Unhandled 'error' event
      ^

Error: socket hang up
    at createHangUpError (_http_client.js:330:15)
    at Socket.socketOnEnd (_http_client.js:423:23)
    at Socket.emit (events.js:164:20)
    at endReadableNT (_stream_readable.js:1062:12)
    at _combinedTickCallback (internal/process/next_tick.js:137:11)
    at process._tickCallback (internal/process/next_tick.js:179:9)
Command: out/Release/node /Users/Jeremiah/Documents/node/test/sequential/test-http-server-keep-alive-timeout-slow-server.js

cc @nodejs/http

@Fishrock123
Copy link
Contributor Author

Fishrock123 commented Nov 23, 2017

All type checking done in this patch is necessary for consistency with other parts of the code. If you want it changed open a separate PR.

@Fishrock123
Copy link
Contributor Author

Just gona open a new PR.

@Fishrock123 Fishrock123 deleted the use-timeout-in-net-socket branch December 15, 2017 23:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
net Issues and PRs related to the net subsystem. semver-major PRs that contain breaking changes and should be released in the next major version. timers Issues and PRs related to the timers subsystem / setImmediate, setInterval, setTimeout.
Projects
None yet
Development

Successfully merging this pull request may close these issues.