-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
2.x: Add fusion (perf++) to ObservableSwitchMap inner source (#5919)
- Loading branch information
Showing
7 changed files
with
342 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,7 +21,8 @@ | |
import io.reactivex.functions.Function; | ||
import io.reactivex.internal.disposables.DisposableHelper; | ||
import io.reactivex.internal.functions.ObjectHelper; | ||
import io.reactivex.internal.queue.*; | ||
import io.reactivex.internal.fuseable.*; | ||
import io.reactivex.internal.queue.SpscLinkedArrayQueue; | ||
import io.reactivex.internal.util.AtomicThrowable; | ||
import io.reactivex.plugins.RxJavaPlugins; | ||
|
||
|
@@ -181,6 +182,8 @@ void drain() { | |
} | ||
|
||
final Observer<? super R> a = actual; | ||
final AtomicReference<SwitchMapInnerObserver<T, R>> active = this.active; | ||
final boolean delayErrors = this.delayErrors; | ||
|
||
int missing = 1; | ||
|
||
|
@@ -218,66 +221,85 @@ void drain() { | |
SwitchMapInnerObserver<T, R> inner = active.get(); | ||
|
||
if (inner != null) { | ||
SpscLinkedArrayQueue<R> q = inner.queue; | ||
|
||
if (inner.done) { | ||
boolean empty = q.isEmpty(); | ||
if (delayErrors) { | ||
if (empty) { | ||
active.compareAndSet(inner, null); | ||
continue; | ||
SimpleQueue<R> q = inner.queue; | ||
|
||
if (q != null) { | ||
if (inner.done) { | ||
boolean empty = q.isEmpty(); | ||
if (delayErrors) { | ||
if (empty) { | ||
active.compareAndSet(inner, null); | ||
continue; | ||
} | ||
} else { | ||
Throwable ex = errors.get(); | ||
if (ex != null) { | ||
a.onError(errors.terminate()); | ||
return; | ||
} | ||
if (empty) { | ||
active.compareAndSet(inner, null); | ||
continue; | ||
} | ||
} | ||
} else { | ||
Throwable ex = errors.get(); | ||
if (ex != null) { | ||
a.onError(errors.terminate()); | ||
} | ||
|
||
boolean retry = false; | ||
|
||
for (;;) { | ||
if (cancelled) { | ||
return; | ||
} | ||
if (empty) { | ||
active.compareAndSet(inner, null); | ||
continue; | ||
if (inner != active.get()) { | ||
retry = true; | ||
break; | ||
} | ||
} | ||
} | ||
|
||
boolean retry = false; | ||
if (!delayErrors) { | ||
Throwable ex = errors.get(); | ||
if (ex != null) { | ||
a.onError(errors.terminate()); | ||
return; | ||
} | ||
} | ||
|
||
for (;;) { | ||
if (cancelled) { | ||
return; | ||
} | ||
if (inner != active.get()) { | ||
retry = true; | ||
break; | ||
} | ||
boolean d = inner.done; | ||
R v; | ||
|
||
if (!delayErrors) { | ||
Throwable ex = errors.get(); | ||
if (ex != null) { | ||
a.onError(errors.terminate()); | ||
return; | ||
try { | ||
v = q.poll(); | ||
} catch (Throwable ex) { | ||
Exceptions.throwIfFatal(ex); | ||
errors.addThrowable(ex); | ||
active.compareAndSet(inner, null); | ||
if (!delayErrors) { | ||
disposeInner(); | ||
s.dispose(); | ||
done = true; | ||
} else { | ||
inner.cancel(); | ||
} | ||
v = null; | ||
retry = true; | ||
} | ||
} | ||
boolean empty = v == null; | ||
|
||
boolean d = inner.done; | ||
R v = q.poll(); | ||
boolean empty = v == null; | ||
if (d && empty) { | ||
active.compareAndSet(inner, null); | ||
retry = true; | ||
break; | ||
} | ||
|
||
if (d && empty) { | ||
active.compareAndSet(inner, null); | ||
retry = true; | ||
break; | ||
} | ||
if (empty) { | ||
break; | ||
} | ||
|
||
if (empty) { | ||
break; | ||
a.onNext(v); | ||
} | ||
|
||
a.onNext(v); | ||
} | ||
|
||
if (retry) { | ||
continue; | ||
if (retry) { | ||
continue; | ||
} | ||
} | ||
} | ||
|
||
|
@@ -306,25 +328,49 @@ static final class SwitchMapInnerObserver<T, R> extends AtomicReference<Disposab | |
private static final long serialVersionUID = 3837284832786408377L; | ||
final SwitchMapObserver<T, R> parent; | ||
final long index; | ||
final SpscLinkedArrayQueue<R> queue; | ||
|
||
final int bufferSize; | ||
|
||
volatile SimpleQueue<R> queue; | ||
|
||
volatile boolean done; | ||
|
||
SwitchMapInnerObserver(SwitchMapObserver<T, R> parent, long index, int bufferSize) { | ||
this.parent = parent; | ||
this.index = index; | ||
this.queue = new SpscLinkedArrayQueue<R>(bufferSize); | ||
this.bufferSize = bufferSize; | ||
} | ||
|
||
@Override | ||
public void onSubscribe(Disposable s) { | ||
DisposableHelper.setOnce(this, s); | ||
if (DisposableHelper.setOnce(this, s)) { | ||
if (s instanceof QueueDisposable) { | ||
@SuppressWarnings("unchecked") | ||
QueueDisposable<R> qd = (QueueDisposable<R>) s; | ||
|
||
int m = qd.requestFusion(QueueDisposable.ANY); | ||
if (m == QueueDisposable.SYNC) { | ||
queue = qd; | ||
done = true; | ||
parent.drain(); | ||
return; | ||
} | ||
if (m == QueueDisposable.ASYNC) { | ||
queue = qd; | ||
return; | ||
} | ||
} | ||
|
||
queue = new SpscLinkedArrayQueue<R>(bufferSize); | ||
} | ||
} | ||
|
||
@Override | ||
public void onNext(R t) { | ||
if (index == parent.unique) { | ||
queue.offer(t); | ||
if (t != null) { | ||
queue.offer(t); | ||
} | ||
parent.drain(); | ||
} | ||
} | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
akarnokd
Author
Member
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
@akarnokd With this change, if the
onNext()
above is called before theonSubscribe()
, aNullPointerException
will be thrown like below:The
LocationServicesOkObservableApi23
fromRxAndroidBle
actually has this case:On Android, somehow the
context.registerReceiver()
will trigger theonNext()
call insidebroadcastReceiver
beforeonSubscribe()
call.So I'm wondering the problem is from RxJava side or RxAndroidBle implementation side?