-
Notifications
You must be signed in to change notification settings - Fork 7.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
Fix a race condition that may make OperatorMaterialize emit too many terminal notifications #5850
Conversation
Codecov Report
@@ Coverage Diff @@
## 1.x #5850 +/- ##
============================================
- Coverage 84.28% 84.27% -0.01%
- Complexity 2889 2891 +2
============================================
Files 290 290
Lines 18264 18265 +1
Branches 2495 2495
============================================
Hits 15393 15393
- Misses 1989 1990 +1
Partials 882 882
Continue to review full report at Codecov.
|
Let's assume the source generates N item, completes and the consumer requests N notifications. Since the source completion is another Notification, it can't be emitted unless the consumer request yet another notification. Since this can happen after the original |
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.
It would be great if you'd adapted this v2 test to verify this change. The TestUtil.race()
is there for v1.
Thanks! I get it. You're right, somehow I missed the fact that BTW: This is not the real cause of the bug I'm hunting for, because I've just found another occurrence that was not invoking iterators / lists at all. So I dug more into it, and I found another race in OperatorMerge. I submitted a 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.
Great find @pkolaczk, thanks!
Unit test confirms that without the patch |
May I rebase and fix the commit message of the fix? It says "miss the item" while in fact it may emit too many items. |
terminal notification more than once The guards in `OperatorMaterialize.ParentSubscriber#drain` were never working, because `busy` was actually never set to true. Therefore it was possible that the `drain` loop was executed by more than one thread concurrently, which could led to undefined behavior. This fix sets `busy` to true at the entry of `drain`.
If you really want to. |
3e754d9
to
ad5b16d
Compare
Misleading commit messages are bad. |
This PR keeps failing due to overcrowded Travis CI. In v2, we solved this with |
We're using RxJava 1.3.5 and one of our tests occasionally fails (very hard to reproduce). The test asserts that
anObservable.toBlocking.toList
(RxScala) expression throws a particular exception, because we expect the observable to be in error state by emitting a singleonError
. However, in rare cases, we observe that there is no exception thrown, and an empty list is returned instead. We verified that the problem is not the observable we use. The observable properly fires thedoOnError
handler prior to the test assertion failure. Therefore we suspected something wrong happening in thetoBlocking.toList
conversion. I debugged that in fact this conversion usesOperatorMaterialize
as a part ofBlockingOperatorToIterator
.I took a look at the
OperatorMaterialize
and found an obvious bug. Thebusy
variable is never set to true anywhere, despite the comments showing the author of the code intended it to be true when thedrain
loop was running.The PR fixes this problem by setting
busy
to true at the entry of thedrain
method.However I still have some doubts about the original code:
drain
have to be called fromrequestMore
? Why isn't it enough to call it fromonCompleted
andonError
? It looks like thedrain
logic does anything only if theterminalNotification
is set, and it can be set only byonCompleted
andonError
.drain
logic supposed to do? Looks rather complex and the intent of it is not obvious. If we don't call it fromrequestMore
then maybe we don't need thedrain
logic at all? Why not emit the terminal notifications directly fromonError
andonCompleted
?Thanks,
Piotr Kołaczkowski