-
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
1.x: reduce stack depth with switchIfEmpty #5125
Conversation
Codecov Report
@@ Coverage Diff @@
## 1.x #5125 +/- ##
============================================
- Coverage 84.38% 84.34% -0.05%
- Complexity 2876 2878 +2
============================================
Files 290 290
Lines 18070 18085 +15
Branches 2468 2473 +5
============================================
+ Hits 15249 15254 +5
- Misses 1951 1966 +15
+ Partials 870 865 -5
Continue to review full report at Codecov.
|
} | ||
|
||
if (!active) { | ||
if (secondary) { |
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.
Is this variable needed? Seems like source == null
would accomplish the same thing.
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.
Unfortunately, no. Here is a scenario:
- Thread 1 subscribes and calls
subscribe(source)
- through subscribeOn, Thread 2 calls
onCompleted()
, and thussubscribe(null)
but finds Thread 1 still inside the loop (wip != 0
). - Thread 1 detects the completion of Thread 2 and loops back. Since
source != null
still in this method, the main source is resubscribed again instead of the alternative.
The secondary
, persisted indicator works across threads and makes sure no matter where onComplete comes from, the second time we get into that inner part, the alternative source is subscribed next.
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.
On a second thought, you are right. If I set source = null
after the source.unsafeSubscribe()
the next round will properly go into the alternative. Updated the PR.
Stack depths may get deep if
switchIfEmpty
has to switch to the alternative source at the end of an already long chain leading to theonCompleted
. Using multipleswitchIfEmpty
amplifies the impact on the stack depth.This PR introduces trampolined subscribing to both sources (similar to how
concat
works), thus given synchronous sources, the stack depth rewinds to the level it was when theswitchIfEmpty
was subscribed to. In addition, to reduce the depth even further, the operator has been turned into anOnSubscribe
-based implementation to avoid the extra depth due tolift
.Related: rxjava StackOverflowError exception in long chain