Skip to content

Commit d6579d2

Browse files
committed
1.x: make just() support backpressure
1 parent e802bb7 commit d6579d2

File tree

10 files changed

+635
-196
lines changed

10 files changed

+635
-196
lines changed

src/main/java/rx/Observable.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8304,7 +8304,7 @@ public final Observable<T> subscribeOn(Scheduler scheduler) {
83048304
if (this instanceof ScalarSynchronousObservable) {
83058305
return ((ScalarSynchronousObservable<T>)this).scalarScheduleOn(scheduler);
83068306
}
8307-
return nest().lift(new OperatorSubscribeOn<T>(scheduler));
8307+
return create(new OperatorSubscribeOn<T>(this, scheduler));
83088308
}
83098309

83108310
/**

src/main/java/rx/Single.java

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1679,8 +1679,43 @@ public void onNext(T t) {
16791679
* @see <a href="http://www.grahamlea.com/2014/07/rxjava-threading-examples/">RxJava Threading Examples</a>
16801680
* @see #observeOn
16811681
*/
1682-
public final Single<T> subscribeOn(Scheduler scheduler) {
1683-
return nest().lift(new OperatorSubscribeOn<T>(scheduler));
1682+
public final Single<T> subscribeOn(final Scheduler scheduler) {
1683+
return create(new OnSubscribe<T>() {
1684+
@Override
1685+
public void call(final SingleSubscriber<? super T> t) {
1686+
final Scheduler.Worker w = scheduler.createWorker();
1687+
t.add(w);
1688+
1689+
w.schedule(new Action0() {
1690+
@Override
1691+
public void call() {
1692+
SingleSubscriber<T> ssub = new SingleSubscriber<T>() {
1693+
@Override
1694+
public void onSuccess(T value) {
1695+
try {
1696+
t.onSuccess(value);
1697+
} finally {
1698+
w.unsubscribe();
1699+
}
1700+
}
1701+
1702+
@Override
1703+
public void onError(Throwable error) {
1704+
try {
1705+
t.onError(error);
1706+
} finally {
1707+
w.unsubscribe();
1708+
}
1709+
}
1710+
};
1711+
1712+
t.add(ssub);
1713+
1714+
Single.this.subscribe(ssub);
1715+
}
1716+
});
1717+
}
1718+
});
16841719
}
16851720

16861721
/**

src/main/java/rx/internal/operators/OperatorSubscribeOn.java

Lines changed: 55 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -15,96 +15,84 @@
1515
*/
1616
package rx.internal.operators;
1717

18-
import rx.Observable;
19-
import rx.Observable.Operator;
20-
import rx.Producer;
21-
import rx.Scheduler;
18+
import rx.*;
19+
import rx.Observable.OnSubscribe;
2220
import rx.Scheduler.Worker;
23-
import rx.Subscriber;
2421
import rx.functions.Action0;
2522

2623
/**
2724
* Subscribes Observers on the specified {@code Scheduler}.
2825
* <p>
2926
* <img width="640" src="https://github.com/ReactiveX/RxJava/wiki/images/rx-operators/subscribeOn.png" alt="">
27+
*
28+
* @param <T> the value type of the actual source
3029
*/
31-
public class OperatorSubscribeOn<T> implements Operator<T, Observable<T>> {
30+
public class OperatorSubscribeOn<T> implements OnSubscribe<T> {
3231

33-
private final Scheduler scheduler;
32+
final Scheduler scheduler;
33+
final Observable<T> source;
3434

35-
public OperatorSubscribeOn(Scheduler scheduler) {
35+
public OperatorSubscribeOn(Observable<T> source, Scheduler scheduler) {
3636
this.scheduler = scheduler;
37+
this.source = source;
3738
}
3839

3940
@Override
40-
public Subscriber<? super Observable<T>> call(final Subscriber<? super T> subscriber) {
41+
public void call(final Subscriber<? super T> subscriber) {
4142
final Worker inner = scheduler.createWorker();
4243
subscriber.add(inner);
43-
return new Subscriber<Observable<T>>(subscriber) {
44-
45-
@Override
46-
public void onCompleted() {
47-
// ignore because this is a nested Observable and we expect only 1 Observable<T> emitted to onNext
48-
}
49-
50-
@Override
51-
public void onError(Throwable e) {
52-
subscriber.onError(e);
53-
}
54-
44+
45+
inner.schedule(new Action0() {
5546
@Override
56-
public void onNext(final Observable<T> o) {
57-
inner.schedule(new Action0() {
58-
47+
public void call() {
48+
final Thread t = Thread.currentThread();
49+
50+
Subscriber<T> s = new Subscriber<T>(subscriber) {
5951
@Override
60-
public void call() {
61-
final Thread t = Thread.currentThread();
62-
o.unsafeSubscribe(new Subscriber<T>(subscriber) {
63-
64-
@Override
65-
public void onCompleted() {
66-
subscriber.onCompleted();
67-
}
68-
69-
@Override
70-
public void onError(Throwable e) {
71-
subscriber.onError(e);
72-
}
73-
74-
@Override
75-
public void onNext(T t) {
76-
subscriber.onNext(t);
77-
}
78-
52+
public void onNext(T t) {
53+
subscriber.onNext(t);
54+
}
55+
56+
@Override
57+
public void onError(Throwable e) {
58+
try {
59+
subscriber.onError(e);
60+
} finally {
61+
inner.unsubscribe();
62+
}
63+
}
64+
65+
@Override
66+
public void onCompleted() {
67+
try {
68+
subscriber.onCompleted();
69+
} finally {
70+
inner.unsubscribe();
71+
}
72+
}
73+
74+
@Override
75+
public void setProducer(final Producer p) {
76+
subscriber.setProducer(new Producer() {
7977
@Override
80-
public void setProducer(final Producer producer) {
81-
subscriber.setProducer(new Producer() {
82-
83-
@Override
84-
public void request(final long n) {
85-
if (Thread.currentThread() == t) {
86-
// don't schedule if we're already on the thread (primarily for first setProducer call)
87-
// see unit test 'testSetProducerSynchronousRequest' for more context on this
88-
producer.request(n);
89-
} else {
90-
inner.schedule(new Action0() {
91-
92-
@Override
93-
public void call() {
94-
producer.request(n);
95-
}
96-
});
78+
public void request(final long n) {
79+
if (t == Thread.currentThread()) {
80+
p.request(n);
81+
} else {
82+
inner.schedule(new Action0() {
83+
@Override
84+
public void call() {
85+
p.request(n);
9786
}
98-
}
99-
100-
});
87+
});
88+
}
10189
}
102-
10390
});
10491
}
105-
});
92+
};
93+
94+
source.unsafeSubscribe(s);
10695
}
107-
108-
};
96+
});
10997
}
11098
}

src/main/java/rx/internal/operators/OperatorTimeoutBase.java

Lines changed: 63 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,11 @@
1616
package rx.internal.operators;
1717

1818
import java.util.concurrent.TimeoutException;
19-
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
20-
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
2119

22-
import rx.Observable;
20+
import rx.*;
2321
import rx.Observable.Operator;
24-
import rx.Scheduler;
25-
import rx.Subscriber;
26-
import rx.Subscription;
27-
import rx.functions.Func3;
28-
import rx.functions.Func4;
22+
import rx.functions.*;
23+
import rx.internal.producers.ProducerArbiter;
2924
import rx.observers.SerializedSubscriber;
3025
import rx.subscriptions.SerialSubscription;
3126

@@ -65,74 +60,86 @@ class OperatorTimeoutBase<T> implements Operator<T, T> {
6560
public Subscriber<? super T> call(Subscriber<? super T> subscriber) {
6661
Scheduler.Worker inner = scheduler.createWorker();
6762
subscriber.add(inner);
68-
final SerialSubscription serial = new SerialSubscription();
69-
subscriber.add(serial);
7063
// Use SynchronizedSubscriber for safe memory access
7164
// as the subscriber will be accessed in the current thread or the
7265
// scheduler or other Observables.
7366
final SerializedSubscriber<T> synchronizedSubscriber = new SerializedSubscriber<T>(subscriber);
7467

68+
final SerialSubscription serial = new SerialSubscription();
69+
synchronizedSubscriber.add(serial);
70+
7571
TimeoutSubscriber<T> timeoutSubscriber = new TimeoutSubscriber<T>(synchronizedSubscriber, timeoutStub, serial, other, inner);
72+
73+
synchronizedSubscriber.add(timeoutSubscriber);
74+
synchronizedSubscriber.setProducer(timeoutSubscriber.arbiter);
75+
7676
serial.set(firstTimeoutStub.call(timeoutSubscriber, 0L, inner));
77+
7778
return timeoutSubscriber;
7879
}
7980

8081
/* package-private */static final class TimeoutSubscriber<T> extends
8182
Subscriber<T> {
8283

8384
private final SerialSubscription serial;
84-
private final Object gate = new Object();
8585

8686
private final SerializedSubscriber<T> serializedSubscriber;
8787

8888
private final TimeoutStub<T> timeoutStub;
8989

9090
private final Observable<? extends T> other;
91+
9192
private final Scheduler.Worker inner;
9293

93-
volatile int terminated;
94-
volatile long actual;
94+
final ProducerArbiter arbiter;
95+
96+
/** Guarded by this. */
97+
boolean terminated;
98+
/** Guarded by this. */
99+
long actual;
95100

96-
@SuppressWarnings("rawtypes")
97-
static final AtomicIntegerFieldUpdater<TimeoutSubscriber> TERMINATED_UPDATER
98-
= AtomicIntegerFieldUpdater.newUpdater(TimeoutSubscriber.class, "terminated");
99-
@SuppressWarnings("rawtypes")
100-
static final AtomicLongFieldUpdater<TimeoutSubscriber> ACTUAL_UPDATER
101-
= AtomicLongFieldUpdater.newUpdater(TimeoutSubscriber.class, "actual");
102-
103101
private TimeoutSubscriber(
104102
SerializedSubscriber<T> serializedSubscriber,
105103
TimeoutStub<T> timeoutStub, SerialSubscription serial,
106104
Observable<? extends T> other,
107105
Scheduler.Worker inner) {
108-
super(serializedSubscriber);
109106
this.serializedSubscriber = serializedSubscriber;
110107
this.timeoutStub = timeoutStub;
111108
this.serial = serial;
112109
this.other = other;
113110
this.inner = inner;
111+
this.arbiter = new ProducerArbiter();
114112
}
115113

114+
@Override
115+
public void setProducer(Producer p) {
116+
arbiter.setProducer(p);
117+
}
118+
116119
@Override
117120
public void onNext(T value) {
118121
boolean onNextWins = false;
119-
synchronized (gate) {
120-
if (terminated == 0) {
121-
ACTUAL_UPDATER.incrementAndGet(this);
122+
long a;
123+
synchronized (this) {
124+
if (!terminated) {
125+
a = ++actual;
122126
onNextWins = true;
127+
} else {
128+
a = actual;
123129
}
124130
}
125131
if (onNextWins) {
126132
serializedSubscriber.onNext(value);
127-
serial.set(timeoutStub.call(this, actual, value, inner));
133+
serial.set(timeoutStub.call(this, a, value, inner));
128134
}
129135
}
130136

131137
@Override
132138
public void onError(Throwable error) {
133139
boolean onErrorWins = false;
134-
synchronized (gate) {
135-
if (TERMINATED_UPDATER.getAndSet(this, 1) == 0) {
140+
synchronized (this) {
141+
if (!terminated) {
142+
terminated = true;
136143
onErrorWins = true;
137144
}
138145
}
@@ -145,8 +152,9 @@ public void onError(Throwable error) {
145152
@Override
146153
public void onCompleted() {
147154
boolean onCompletedWins = false;
148-
synchronized (gate) {
149-
if (TERMINATED_UPDATER.getAndSet(this, 1) == 0) {
155+
synchronized (this) {
156+
if (!terminated) {
157+
terminated = true;
150158
onCompletedWins = true;
151159
}
152160
}
@@ -159,17 +167,39 @@ public void onCompleted() {
159167
public void onTimeout(long seqId) {
160168
long expected = seqId;
161169
boolean timeoutWins = false;
162-
synchronized (gate) {
163-
if (expected == actual && TERMINATED_UPDATER.getAndSet(this, 1) == 0) {
170+
synchronized (this) {
171+
if (expected == actual && !terminated) {
172+
terminated = true;
164173
timeoutWins = true;
165174
}
166175
}
167176
if (timeoutWins) {
168177
if (other == null) {
169178
serializedSubscriber.onError(new TimeoutException());
170179
} else {
171-
other.unsafeSubscribe(serializedSubscriber);
172-
serial.set(serializedSubscriber);
180+
Subscriber<T> second = new Subscriber<T>() {
181+
@Override
182+
public void onNext(T t) {
183+
serializedSubscriber.onNext(t);
184+
}
185+
186+
@Override
187+
public void onError(Throwable e) {
188+
serializedSubscriber.onError(e);
189+
}
190+
191+
@Override
192+
public void onCompleted() {
193+
serializedSubscriber.onCompleted();
194+
}
195+
196+
@Override
197+
public void setProducer(Producer p) {
198+
arbiter.setProducer(p);
199+
}
200+
};
201+
other.unsafeSubscribe(second);
202+
serial.set(second);
173203
}
174204
}
175205
}

0 commit comments

Comments
 (0)