Skip to content

Conversation

@ronag
Copy link
Member

@ronagronag commented Apr 21, 2020

pipeline was too agressive with destroying Duplex
streams which were the first argument into pipeline.

Just because it's !writable does not mean that it
is safe to be destroyed, unless it has also emitted
'finish'.

Fixes: #32955

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

@ronagronag added the stream Issues and PRs related to the stream subsystem. label Apr 21, 2020
@ronagronag requested a review from mafintoshApril 21, 2020 10:25
@ronagronagforce-pushed the pipeline-destroy branch 2 times, most recently from fcb17b5 to 229f5d2CompareApril 21, 2020 10:26
pipeline was too agressive with destroying Duplex streams which were the first argument into pipeline. Just because it's !writable does not mean that it is safe to be destroyed, unless it has also emitted 'finish'. Fixes: nodejs#32955
@ronagronag changed the title stream: pipeline should not destroy Duplex src/dststream: pipeline don't destroy Duplex src before 'finish'Apr 21, 2020
@ronagronag added the v13.x label Apr 21, 2020
Comment on lines 53 to 73
constwState=stream._writableState;

constwritableEnded=stream.writableEnded||
(wState&&wState.ended);
constwritableFinished=stream.writableFinished||
(wState&&wState.finished);

constwillFinish=stream.writable||
(writableEnded&&!writableFinished);
constwillEnd=stream.readable;

if(err||!final||!stream.readable){
destroyImpl.destroyer(stream,err);
if(!err){
// First
if(reading&&!writing&&willFinish){
returncallback();
}

// Last
if(!reading&&writing&&willEnd){
returncallback();
}
Copy link
Member

Choose a reason for hiding this comment

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

Nit: it is possible to reduce the code branches a bit:

Suggested change
constwState=stream._writableState;
constwritableEnded=stream.writableEnded||
(wState&&wState.ended);
constwritableFinished=stream.writableFinished||
(wState&&wState.finished);
constwillFinish=stream.writable||
(writableEnded&&!writableFinished);
constwillEnd=stream.readable;
if(err||!final||!stream.readable){
destroyImpl.destroyer(stream,err);
if(!err){
// First
if(reading&&!writing&&willFinish){
returncallback();
}
// Last
if(!reading&&writing&&willEnd){
returncallback();
}
if(!err){
// Check if the last stream will end:
if(!reading){
if(writing&&stream.readable){
returncallback();
}
// First stream
}elseif(!writing){
if(stream.writable){
returncallback();
}
constwState=stream._writableState;
constwritableEnded=stream.writableEnded||
(wState&&wState.ended);
constwritableFinished=stream.writableFinished||
(wState&&wState.finished);
if(writableEnded&&!writableFinished)
returncallback();
}
}

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

@BridgeAR: Any specific reason? This does make it a bit harder to read in my opinon.

Copy link
Member

Choose a reason for hiding this comment

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

Code should IMO always only run when necessary. Right now some code is executed that is only needed in some situations.

Copy link
MemberAuthor

Choose a reason for hiding this comment

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

This is not a hot path so readability should IMO come first. I think I can make a compromise 😄. PTAL.

@ronagronag mentioned this pull request Apr 21, 2020
4 tasks
destroyImpl.destroyer(stream,err);
if(!err){
// First
if(reading&&!writing&&willFinish){
Copy link
MemberAuthor

@ronagronagApr 21, 2020

Choose a reason for hiding this comment

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

The willFinish part here is the significant change. Before we only checked stream.writable.

The rest of the changes should be logically the same.

@ronagronag added the blocked PRs that are blocked by other issues or PRs. label Apr 21, 2020
@ronag
Copy link
MemberAuthor

blocked pending #32954

@ronag
Copy link
MemberAuthor

closed in favor of #32968

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

blockedPRs that are blocked by other issues or PRs.streamIssues and PRs related to the stream subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Duplex stream pipeline regression in 13

2 participants

@ronag@BridgeAR