-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Fix a race condition that may make OperatorMaterialize emit too many terminal notifications #5850
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
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 |
akarnokd
left a comment
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. |
davidmoten
left a comment
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 thedoOnErrorhandler prior to the test assertion failure. Therefore we suspected something wrong happening in thetoBlocking.toListconversion. I debugged that in fact this conversion usesOperatorMaterializeas a part ofBlockingOperatorToIterator.I took a look at the
OperatorMaterializeand found an obvious bug. Thebusyvariable is never set to true anywhere, despite the comments showing the author of the code intended it to be true when thedrainloop was running.The PR fixes this problem by setting
busyto true at the entry of thedrainmethod.However I still have some doubts about the original code:
drainhave to be called fromrequestMore? Why isn't it enough to call it fromonCompletedandonError? It looks like thedrainlogic does anything only if theterminalNotificationis set, and it can be set only byonCompletedandonError.drainlogic supposed to do? Looks rather complex and the intent of it is not obvious. If we don't call it fromrequestMorethen maybe we don't need thedrainlogic at all? Why not emit the terminal notifications directly fromonErrorandonCompleted?Thanks,
Piotr Kołaczkowski