-
Notifications
You must be signed in to change notification settings - Fork 147
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 Buffering Issue With parallel() #302
Fix Buffering Issue With parallel() #302
Conversation
Yep. Here's the intent of the algorithm Some definitions:
It goes like this:
Here's the property that makes (2)(iii)(a)(a) work and its proof.
Proof by induction: Assume true for the first
Thus, the next time that the |
As it turns out, doesn't satisfy the invariant. var _ = require('./lib/index.js'),
sinon = require('sinon');
var clock = sinon.useFakeTimers();
function delay(push, ms, x) {
setTimeout(function () {
push(null, x);
}, ms);
}
var s1 = _(function (push) {
delay(push, 1, 1);
delay(push, 2, 2);
delay(push, 3, _.nil);
});
var s2 = _(function (push) {
delay(push, 1, 10);
delay(push, 2, 20);
delay(push, 3, 30);
delay(push, 4, 40);
delay(push, 5, _.nil);
});
var s3 = _(function (push, next) {
console.log("S3 generator");
push(null, 100);
push(null, _.nil);
});
var ss = _([s1, s2, s3]).parallel(2).each(_.log);
clock.tick(10); You expect
What actually happens is
The reason is that
The solution is to call diff --git a/lib/index.js b/lib/index.js
index a50247e..8b728db 100755
--- a/lib/index.js
+++ b/lib/index.js
@@ -2933,6 +2933,7 @@ Stream.prototype.parallel = function (n) {
if (running.length && running[0].buffer.length) {
// send buffered data
flushBuffer();
+ next();
// still waiting for more data before we can shift
// the running array...
}
@@ -2961,9 +2962,7 @@ Stream.prototype.parallel = function (n) {
if (running.length && running[0].buffer.length) {
flushBuffer();
}
- else {
- next();
- }
+ next();
}
else {
@@ -2996,7 +2995,6 @@ Stream.prototype.parallel = function (n) {
if (buf[i][1] === nil) {
// this stream has ended
running.shift();
- return next();
}
else {
// send the buffered output If you apply this patch, you'll then notice the true consequence of the code not following the invariant I described. The test case above will continually repeat
The real fix, of course, is to also clear the buffer in diff --git a/lib/index.js b/lib/index.js
index a50247e..6d8f10b 100755
--- a/lib/index.js
+++ b/lib/index.js
@@ -2933,6 +2933,7 @@ Stream.prototype.parallel = function (n) {
if (running.length && running[0].buffer.length) {
// send buffered data
flushBuffer();
+ next();
// still waiting for more data before we can shift
// the running array...
}
@@ -2961,9 +2962,7 @@ Stream.prototype.parallel = function (n) {
if (running.length && running[0].buffer.length) {
flushBuffer();
}
- else {
- next();
- }
+ next();
}
else {
@@ -2996,13 +2995,14 @@ Stream.prototype.parallel = function (n) {
if (buf[i][1] === nil) {
// this stream has ended
running.shift();
- return next();
+ return;
}
else {
// send the buffered output
push.apply(null, buf[i]);
}
}
+ buf.length = 0;
}
// else wait for more data to arrive from running streams
}); |
By the way, thanks for asking for an explanation. I only noticed these bugs when writing the proof for why |
Thanks @vqvu for such a thorough explanation. I really am in awe at your knowledge and understanding of the codebase. I knew something wasn't right but I don't think I would ever have figured this out on my own. I've made your suggested changes and also added a test case for the liveness bug too. |
I don't think your test actually tests the liveness bug. Does it fail if you don't apply my patch? The bug is about when You probably want to set a flag in the generator for |
7de1562
to
51d6939
Compare
Ah yes, I get what you mean. |
}); | ||
}; | ||
|
||
exports['parallel - behaviour of parallel with fork() - invariant violation - issue #234'] = function (test) { |
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 isn't "behavior of parallel with fork()". It's more "parallel consumption liveness". Also, reference this issue (302) instead of 234.
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.
Done!
fix liveness bug and add tests fix liveness test rename liveness test remove doto logging function
a9482c8
to
13c4d87
Compare
What is going on with Travis? These builds are taking hours. |
Looks like there's a problem but it's been resolved: |
Cool. |
…arallel Fix buffering Issue With parallel(). Fixes #234.
Resolves #234. I finally got round to looking at this and although I've managed to fix it I'm still a bit hazy as to why what I've done works and wouldn't mind if someone could explain a bit as to what exactly is happening in the function. There's a lot of state and mutation going on and I find it very hard to follow.