-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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: make sure readable is called on empty chunk followed by eof #29762
Conversation
fdab801
to
2c0ab44
Compare
2c0ab44
to
3a02aea
Compare
a5c58e9
to
eebae1f
Compare
eebae1f
to
4eb889f
Compare
ca14482
to
fe92fc7
Compare
An empty chunk should be treated like any other chunk and trigger the read logic. Fixes: nodejs#29758
914138e
to
26d983f
Compare
26d983f
to
2c720a1
Compare
This seems to fix the issue on my end. Should this also be backported? |
@awwright: Thanks for testing! I'm not sure whether this fix will break something else. We will have to wait for someone more familiar with |
@@ -44,7 +44,7 @@ class TestReader extends R { | |||
} | |||
|
|||
const reader = new TestReader(); | |||
setImmediate(function() { | |||
process.nextTick(function() { |
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.
This test kind of contradicts the added test, i.e. it expects the stream to stop reading after pushing an empty chunk.
Not sure if this is something that indicates whether this fix will cause other problems.
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 you please articulate this a bit more? Is this change needed to make the test pass?
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.
Yes, otherwise it live locks. Basically it gets into an infinite loop (with nextTick) between. Because it pushes an empty chunk, which invokes a read call which pushes an empty chunk etc...
By changing it to nextTick instead of setImmediate it's possible to get between that loop and end it. But as I wrote I'm unsure of the implications.
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 think we should avoid that live lock in code.
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 think we should avoid that live lock in code.
What does that mean in practice? Should we add a guard? Or is the current state of the PR ok in that regard?
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 think @mcollina would like to add a guard in the streams implementation that this can not cause an infinite loop / that this test does not need to change.
cd10310
to
2f13cdd
Compare
Yeah it looks like test/parallel/test-stream2-compatibility.js timed out for me, I suspect if it breaks that it would break someone in the wild |
Yep, the problem is that fixing your issue will per definition break this test, i.e. one of the expects a new read to be scheduled when pushing and empty chunk while the other expects the exact opposite. :/ |
Hm, I'm not very well versed in the details of streams, but both tests here look reasonable; are they really mutually exclusive? There's got to be something more to this. |
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’m unsure about the semver level of this. This fixes a bug for me, but I’m uncertain if it diverges enough to be considered a major.
@@ -44,7 +44,7 @@ class TestReader extends R { | |||
} | |||
|
|||
const reader = new TestReader(); | |||
setImmediate(function() { | |||
process.nextTick(function() { |
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 you please articulate this a bit more? Is this change needed to make the test pass?
Would you mind adding a unit test that only use Readable? |
} | ||
|
||
// Reset emittedReadable once it is safe to schedule another | ||
// emitReadable. | ||
state.emittedReadable = false; |
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.
@mcollina: Please also observe this change. I'm pretty sure it's fine but just making sure I have a second opinion on that.
@mcollina: I noticed another possible issue while looking into making that |
@lpinca: I've been trying to wrap my head around this and I believe something is wrong with
I think the behaviour of What further confuses me is why this problem is only triggered by empty chunks. As far as I understand empty chunks (for whatever reason) are actually the one behaving correctly. |
Yes I agree, that assumption seems wrong. |
Ok, I think this PR is not correct then. I will try to dig into this from the other direction. |
An empty chunk should be treated like any other chunk and trigger the corresponding read logic.
Fixes: #29758
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes