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

fix needDrain emitting to match the amount of pauses #4

Merged
merged 2 commits into from Sep 5, 2016

Conversation

dignifiedquire
Copy link
Member

Trying to work out a test for this, which I will hopefully push soon

@dominictarr
Copy link
Member

what is currently happening? the way you phrased it it sounds like it's emitting too many pauses not not enough drains. it should not emit another pause unless it's emitted drain since the last pause.

As a regular expression: /(PD)*/
if it's emitting PPPD that is a too many pauses,
PPPDDD has the same number of pauses and drains, but is not valid.

@dignifiedquire
Copy link
Member Author

I was able to simulate the problem I had in my code with a test, that I just added, the change fixes that. I hope that code explains better what issue I am trying to solve.

@dominictarr
Copy link
Member

it would help if you describe the problem? it's harder to interpret code than text

@dignifiedquire
Copy link
Member Author

it would help if you describe the problem? it's harder to interpret code than text

Of course.

Given a src readable stream and a dest writable stream, which are src.pipe(dest) together, the following happens

The above behaviour results in what you mentioned of pausing multiple times one after another, without 'drain' in between. Because there is a counter, which checks how often writes returned false, dest needs to emit the exact same amount of 'drain' events to makes src return into flowing mode.

With the current code where I put the needDrain = false into the nextTick call, this does not happen, as those write() === false calls in between are not tracked properly.

The best solution I could come up with was to move the needDrain = false out, such that it is process synchronously, triggering in the next round a new 'drain' event, corresponding to the write call that returned false.

@dominictarr
Copy link
Member

Thanks! Now I understand.

When I learnt nodestreams, it worked the way I described! emitting lots of drain events will still work correctly with old streams. unfortunately they can't describe the state of a node stream with a finite state machine now! you have to have a stack-based automaton.

but if node uses a counter here, I think we should use a counter too, even if we emit drain inside a loop

@dominictarr
Copy link
Member

as I think about this more, I realize that actually that change in node streams would not be backwards compatible with older node streams. I think we better figure out what is really going on here

@dominictarr
Copy link
Member

for reference, this is the commit that introduced that feature nodejs/node@0f8de5e

@dignifiedquire
Copy link
Member Author

Found the original referenced issue with discussion: nodejs/node-v0.x-archive#5860

@dignifiedquire
Copy link
Member Author

I realize that actually that change in node streams would not be backwards compatible with older node streams

What exactly do you think break compat here, and to which streams version?
In your blog on the history of streams you write

The version of streams now in contemporary node@5 is considered streams3. it’s a significant refactor from streams2, but, is still backwards compatible.

do you think this is not true anymore, or just the implementation in here?

@dominictarr
Copy link
Member

I'm a bit confused by this drain counter thing. Although, maybe ... it would make sense if it's for when you pipe a stream to multiple destinations?

I'm gonna study your test code and figure out what is going on there

@dominictarr
Copy link
Member

oh, now I see it. this is a big no-no d5b8ffd#diff-168726dbe96b3ce427e7fedce31bb0bcR68

the problem here is that you have emitted the event, then updated the state, but it should be the other way around. You must be very careful with this, because the anything (sync) can happen during the event listener, including triggering other events. In this case, you emit the drain event, which triggers more writes, etc, but the stream still thinks it's no longer needing to drain, when actually, it may have reentered the needDrain state. if you just shift the needDrain = false before the emit, then your test passes.

@dignifiedquire
Copy link
Member Author

@dominictarr rebased based on your changes and passes all my integration tests :)

@dominictarr
Copy link
Member

cool, merging!

@dignifiedquire
Copy link
Member Author

@dominictarr I think you published without pushing to github :)

@daviddias
Copy link

Hey! Just to confirm, has this been merged? Seems that there is a new version on npm, but the last commit in github master is from 6 days ago

@dominictarr dominictarr merged commit 43a3266 into pull-stream:master Sep 5, 2016
@dominictarr
Copy link
Member

yes, sorry - I just forgot which branch I was on.

@dominictarr
Copy link
Member

merged into 1.3.2

@dignifiedquire
Copy link
Member Author

Thank you 🙂

@dignifiedquire dignifiedquire deleted the fix-drain branch September 5, 2016 22:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants