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: fix y.pipe(x)+y.pipe(x)+y.unpipe(x) scenario #12746

Closed

Conversation

addaleax
Copy link
Member

Fix the uncommon situation when a readable stream is piped twice into
the same destination stream, and then unpiped once.

Previously, the unpipe event handlers weren’t able to tell whether
they were corresponding to the “right” conceptual pipe that was being
removed; this fixes this by adding a counter to the unpipe event
handler and only removing a single piping destination at most.

Fixes: #12718

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)

stream

@addaleax addaleax added lts-watch-v4.x stream Issues and PRs related to the stream subsystem. labels Apr 29, 2017
@addaleax
Copy link
Member Author

addaleax commented Apr 29, 2017

CI: https://ci.nodejs.org/job/node-test-commit/9508/
CITGM: https://ci.nodejs.org/view/Node.js-citgm/job/citgm-smoker/753/
(Very recent master CITGM for comparison: https://ci.nodejs.org/view/Node.js-citgm/job/citgm-smoker/752/. Also, I hope I did the right thing by checking the DISABLE_READABLE_STREAM box)

Edit: CI failures are infra-related, CITGM compares good to master

/cc @nodejs/streams

debug('onunpipe');
if (readable === src) {
cleanup();
if (unpipeInfo.counter++ === 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: how about only incrementing inside to avoid incrementing when unnecessary? Or just use a boolean?

Copy link
Member Author

Choose a reason for hiding this comment

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

@mscdex I’m fine either way, updated this to switch to a boolean

@jasnell jasnell requested a review from mcollina April 29, 2017 19:35
Copy link
Member

@benjamingr benjamingr left a comment

Choose a reason for hiding this comment

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

Changes LGTM assuming CI and CITGM are green, we might want to mark this as semver-minor for safety reasons as it changes stream behavior.

@addaleax
Copy link
Member Author

we might want to mark this as semver-minor for safety reasons as it changes stream behavior

Not sure, it isn’t really adding anything … if you think it’s a change that should be pointed out explicitly, then adding notable-change sounds better. But really, this is a very very niche use case that’s being fixed, even for streams…

@addaleax addaleax force-pushed the stream-pipe-same-destination-twice branch from 81ad497 to ca8f430 Compare April 29, 2017 19:42
@calvinmetcalf
Copy link
Contributor

calvinmetcalf commented Apr 30, 2017 via email

@addaleax
Copy link
Member Author

@calvinmetcalf I mean, sure, if you think that that makes anything easier, we can talk in person … but it might be good to know what you’d like to discuss? 😄

@calvinmetcalf
Copy link
Contributor

calvinmetcalf commented Apr 30, 2017 via email

@addaleax
Copy link
Member Author

Sure … but I don’t have a problem discussing it here, either. I know the streams WG has a good chance of being quite complete in Berlin, but there might be other people with thoughts on this that can’t make it there. (That doesn’t mean we can’t talk about it in person if we don’t come to a conclusion here).

I would say that this is semver-patch, because it fixes a bug; the current behaviour is definitely broken (or needs to be document as something that’s just fundamentally not supported), and this is a way to make the behaviour at least consistent in a way that would match my expectations as a streams user, and presumably @ovikholt’s expectations, too.

I would say that this is not semver-major because the edge case that is affected by this change would just be broken before, so there’s no reason to believe anybody relies on it.

I would say that this is not semver-minor because it doesn’t add a feature to the API. It does add another parameter to an event callback, but one that’s for internal use, that’s intentionally undocumented and that userland applications won’t really be able to use. I wish there would be an easier way to hide it, but I don’t see any (at least as long as we’re also talking about solutions that include all environments supported by readable-stream).

If we want to be careful, then landing it in current and waiting a reasonably long time before backporting it to LTS seems like a better approach than assigning it a semver level out of caution.

@mcollina
Copy link
Member

mcollina commented May 1, 2017

I'm not convinced of this PR. I think y.pipe(x); y.pipe(x); should be discouraged, and I am wondering why it was supported in the first place. Maybe we should stop supporting piping the same stream multiple times to the same destination, but that would be a semver-major change.

Would you mind adding a test that does y.pipe(x); y.pipe(x); y.unpipe(x); y.unpipe(x); and check that everything is still in order?

@addaleax
Copy link
Member Author

addaleax commented May 1, 2017

I'm not convinced of this PR. I think y.pipe(x); y.pipe(x); should be discouraged, and I am wondering why it was supported in the first place. Maybe we should stop supporting piping the same stream multiple times to the same destination, but that would be a semver-major change.

I agree, supporting that is odd (especially for non-object mode) and we should consider un-supporting it. Are you okay with this change as a bugfix, though?

Would you mind adding a test that does y.pipe(x); y.pipe(x); y.unpipe(x); y.unpipe(x); and check that everything is still in order?

Done!

@addaleax addaleax force-pushed the stream-pipe-same-destination-twice branch from ca8f430 to 87cdba9 Compare May 1, 2017 17:00
@mcollina
Copy link
Member

mcollina commented May 2, 2017

I agree, supporting that is odd (especially for non-object mode) and we should consider un-supporting it. Are you okay with this change as a bugfix, though?

Yes, I'm ok as being a backportable bugfix. We can aim to port this to lts as well.

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

@mcollina
Copy link
Member

mcollina commented May 2, 2017

Just one nit, can you amend the commit and the title to the PR to y.pipe(x)+y.pipe(x)+y.unpipe(x), as otherwise I've read it wrongly the first time y.pipe(x).pipe(x).unpipe(x), which has a completely different meaning.

Fix the uncommon situation when a readable stream is piped twice into
the same destination stream, and then unpiped once.

Previously, the `unpipe` event handlers weren’t able to tell whether
they were corresponding to the “right” conceptual pipe that was being
removed; this fixes this by adding a counter to the `unpipe` event
handler and only removing a single piping destination at most.

Fixes: nodejs#12718
@addaleax addaleax force-pushed the stream-pipe-same-destination-twice branch from 87cdba9 to 86b9243 Compare May 2, 2017 13:52
@addaleax
Copy link
Member Author

addaleax commented May 2, 2017

Just one nit, can you amend the commit and the title to the PR to y.pipe(x)+y.pipe(x)+y.unpipe(x)

Done!

@mcollina
Copy link
Member

mcollina commented May 2, 2017

Fantastic, you can go ahead and merge this for me. @calvinmetcalf have you got any other concerns?

@mcollina mcollina changed the title stream: fix pipe(x)+pipe(x)+unpipe(x) scenario stream: fix y.pipe(x)+y.pipe(x)+y.unpipe(x) scenario May 2, 2017
@calvinmetcalf
Copy link
Contributor

calvinmetcalf commented May 2, 2017 via email

@addaleax
Copy link
Member Author

addaleax commented May 3, 2017

Landed in 6993eb0

This is streams code and a very edge-case-y thing, so it might be good to let it sit in Current for a while before backporting.

@addaleax addaleax closed this May 3, 2017
@addaleax addaleax deleted the stream-pipe-same-destination-twice branch May 3, 2017 13:35
addaleax added a commit that referenced this pull request May 3, 2017
Fix the uncommon situation when a readable stream is piped twice into
the same destination stream, and then unpiped once.

Previously, the `unpipe` event handlers weren’t able to tell whether
they were corresponding to the “right” conceptual pipe that was being
removed; this fixes this by adding a counter to the `unpipe` event
handler and only removing a single piping destination at most.

Fixes: #12718
PR-URL: #12746
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
anchnk pushed a commit to anchnk/node that referenced this pull request May 6, 2017
Fix the uncommon situation when a readable stream is piped twice into
the same destination stream, and then unpiped once.

Previously, the `unpipe` event handlers weren’t able to tell whether
they were corresponding to the “right” conceptual pipe that was being
removed; this fixes this by adding a counter to the `unpipe` event
handler and only removing a single piping destination at most.

Fixes: nodejs#12718
PR-URL: nodejs#12746
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
@jasnell jasnell mentioned this pull request May 11, 2017
@gibfahn gibfahn mentioned this pull request Jun 15, 2017
3 tasks
@gibfahn gibfahn added the baking-for-lts PRs that need to wait before landing in a LTS release. label Jun 18, 2017
MoonBall pushed a commit to MoonBall/node that referenced this pull request Jan 20, 2018
mcollina pushed a commit that referenced this pull request Feb 5, 2018
This PR makes sure the object emitted as the 'unpipe'
event in the destination stream is not shared between
destination, as it would be muted.

Refs: #12746
PR-URL: #18266
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
MylesBorins pushed a commit that referenced this pull request Feb 21, 2018
This PR makes sure the object emitted as the 'unpipe'
event in the destination stream is not shared between
destination, as it would be muted.

Refs: #12746
PR-URL: #18266
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
MylesBorins pushed a commit that referenced this pull request Feb 21, 2018
This PR makes sure the object emitted as the 'unpipe'
event in the destination stream is not shared between
destination, as it would be muted.

Refs: #12746
PR-URL: #18266
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
MylesBorins pushed a commit that referenced this pull request Feb 21, 2018
This PR makes sure the object emitted as the 'unpipe'
event in the destination stream is not shared between
destination, as it would be muted.

Refs: #12746
PR-URL: #18266
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
gibfahn pushed a commit that referenced this pull request Apr 13, 2018
This PR makes sure the object emitted as the 'unpipe'
event in the destination stream is not shared between
destination, as it would be muted.

Refs: #12746
PR-URL: #18266
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
@MylesBorins MylesBorins added dont-land-on-v6.x and removed baking-for-lts PRs that need to wait before landing in a LTS release. lts-watch-v4.x labels Apr 13, 2018
@lpinca
Copy link
Member

lpinca commented Apr 16, 2018

@MylesBorins any reason to not backport this to v6.x?

@MylesBorins
Copy link
Member

@lpinca I opted to not land this as @addaleax mentioned it was edgecasey and #18266 showed there was at least one regression.

More than happy to backport both if it makes sense.

@addaleax
Copy link
Member Author

I think backporting both should be fine by now, it’s been almost a year. :)

@lpinca
Copy link
Member

lpinca commented Apr 16, 2018

+1 for backporting both.

@MylesBorins
Copy link
Member

@lpinca done 🎉

Will report back if there is any weirdness

MylesBorins pushed a commit that referenced this pull request Apr 16, 2018
Fix the uncommon situation when a readable stream is piped twice into
the same destination stream, and then unpiped once.

Previously, the `unpipe` event handlers weren’t able to tell whether
they were corresponding to the “right” conceptual pipe that was being
removed; this fixes this by adding a counter to the `unpipe` event
handler and only removing a single piping destination at most.

Fixes: #12718
PR-URL: #12746
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
MylesBorins pushed a commit that referenced this pull request Apr 16, 2018
This PR makes sure the object emitted as the 'unpipe'
event in the destination stream is not shared between
destination, as it would be muted.

Refs: #12746
PR-URL: #18266
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
@MylesBorins MylesBorins mentioned this pull request Apr 16, 2018
MayaLekova pushed a commit to MayaLekova/node that referenced this pull request May 8, 2018
This PR makes sure the object emitted as the 'unpipe'
event in the destination stream is not shared between
destination, as it would be muted.

Refs: nodejs#12746
PR-URL: nodejs#18266
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stream Issues and PRs related to the stream subsystem.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Piping twice to same stream then unpiping loses data
8 participants