-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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 stream.finished on Duplex #33133
Conversation
finished would incorrectly believe that a Duplex is already closed if either the readable or writable side has completed. Fixes: nodejs#33130
@nodejs/streams @mafintosh @szmarczak |
fast-track? |
@ronag You need to delay the write to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
(wState && wState.errorEmitted) || (rState && rState.errorEmitted) || | ||
(wState && wState.finished) || (rState && rState.endEmitted) || | ||
(rState && stream.req && stream.aborted); | ||
const closed = ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we simplify this a bit? Perhaps at the very least group together similar dependencies, like:
const closed = (
(wState && (wState.closed || wState.errorEmitted)) ||
(rState && (rState.closed || rState.errorEmitted || (stream.req && stream.aborted))) ||
(
(!writable || (wState && wState.finished)) &&
(!readable || (rState && rState.endEmitted))
)
);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are grouped? See below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless there is a performance benefit to the above suggestion, I prefer @ronag's grouping because it's easier to read. Though it has more lines, it has less parentheses and the lines are ordered by the properties (e.g. closed
) of the states. It reads like "is either state closed, or either state errorEmitted, or ..".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have not personally benchmarked it, so I cannot say if it is measurable or not. However, it is reducing the number of duplicate checks so V8 should be performing less work.
However, my code suggestion was merely one possibility. I'm not opposed to rearranging the checks in other ways, such as introducing separate if
statements, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer the current formatting and believe any performance implication here would be negligible in practice. This is not a hot path as far as I'm aware. A future simplification could be to use the ?.
operator.
|
||
if (closed) { | ||
// TODO(ronag): Re-throw error if errorEmitted? | ||
// TODO(ronag): Throw premature close as if finished was called? | ||
// before being closed? i.e. if closed but not errored, ended or finished. | ||
// TODO(ronag): Throw some kind of error? Does it make sense | ||
// to call finished() on a "finished" stream? | ||
// TODO(ronag): willEmitClose? | ||
process.nextTick(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For bonus points this could also be simplified to process.nextTick(callback);
if you want to change it while we're in here. Either way is fine though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mscdex Strangely CI fails with your suggestion. Not sure why. Leaving it as is for the purposes of this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, it's because we re-assign callback in the disposer.
This reverts commit 882f704.
Landed in d84f131 |
finished would incorrectly believe that a Duplex is already
closed if either the readable or writable side has completed.
Fixes: #33130
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes