15
15
*/
16
16
package rx .internal .operators ;
17
17
18
- import java .util .concurrent .atomic .AtomicIntegerFieldUpdater ;
19
- import java .util .concurrent .atomic .AtomicLongFieldUpdater ;
18
+ import java .util .concurrent .atomic .*;
20
19
21
20
import rx .Observable .Operator ;
22
- import rx .Producer ;
23
- import rx .Scheduler ;
24
- import rx .Subscriber ;
25
- import rx .Subscription ;
21
+ import rx .*;
26
22
import rx .exceptions .MissingBackpressureException ;
27
23
import rx .functions .Action0 ;
28
24
import rx .internal .util .RxRingBuffer ;
29
- import rx .schedulers . ImmediateScheduler ;
30
- import rx .schedulers .TrampolineScheduler ;
25
+ import rx .internal . util . unsafe . SpscArrayQueue ;
26
+ import rx .schedulers .* ;
31
27
32
28
/**
33
29
* Delivers events on the specified {@code Scheduler} asynchronously via an unbounded buffer.
@@ -64,16 +60,15 @@ public Subscriber<? super T> call(Subscriber<? super T> child) {
64
60
/** Observe through individual queue per observer. */
65
61
private static final class ObserveOnSubscriber <T > extends Subscriber <T > {
66
62
final Subscriber <? super T > child ;
67
- private final Scheduler .Worker recursiveScheduler ;
68
- private final ScheduledUnsubscribe scheduledUnsubscribe ;
63
+ final Scheduler .Worker recursiveScheduler ;
64
+ final ScheduledUnsubscribe scheduledUnsubscribe ;
69
65
final NotificationLite <T > on = NotificationLite .instance ();
70
66
71
- private final RxRingBuffer queue = RxRingBuffer .getSpscInstance ( );
72
- private boolean completed = false ;
73
- private boolean failure = false ;
67
+ final SpscArrayQueue < Object > queue = new SpscArrayQueue < Object >( RxRingBuffer .SIZE );
68
+ volatile boolean completed = false ;
69
+ volatile boolean failure = false ;
74
70
75
- @ SuppressWarnings ("unused" )
76
- private volatile long requested = 0 ;
71
+ volatile long requested = 0 ;
77
72
@ SuppressWarnings ("rawtypes" )
78
73
static final AtomicLongFieldUpdater <ObserveOnSubscriber > REQUESTED = AtomicLongFieldUpdater .newUpdater (ObserveOnSubscriber .class , "requested" );
79
74
@@ -82,12 +77,14 @@ private static final class ObserveOnSubscriber<T> extends Subscriber<T> {
82
77
@ SuppressWarnings ("rawtypes" )
83
78
static final AtomicLongFieldUpdater <ObserveOnSubscriber > COUNTER_UPDATER = AtomicLongFieldUpdater .newUpdater (ObserveOnSubscriber .class , "counter" );
84
79
80
+ volatile Throwable error ;
81
+
85
82
// do NOT pass the Subscriber through to couple the subscription chain ... unsubscribing on the parent should
86
83
// not prevent anything downstream from consuming, which will happen if the Subscription is chained
87
84
public ObserveOnSubscriber (Scheduler scheduler , Subscriber <? super T > child ) {
88
85
this .child = child ;
89
86
this .recursiveScheduler = scheduler .createWorker ();
90
- this .scheduledUnsubscribe = new ScheduledUnsubscribe (recursiveScheduler , queue );
87
+ this .scheduledUnsubscribe = new ScheduledUnsubscribe (recursiveScheduler );
91
88
child .add (scheduledUnsubscribe );
92
89
child .setProducer (new Producer () {
93
90
@@ -113,10 +110,8 @@ public void onNext(final T t) {
113
110
if (isUnsubscribed () || completed ) {
114
111
return ;
115
112
}
116
- try {
117
- queue .onNext (t );
118
- } catch (MissingBackpressureException e ) {
119
- onError (e );
113
+ if (!queue .offer (on .next (t ))) {
114
+ onError (new MissingBackpressureException ());
120
115
return ;
121
116
}
122
117
schedule ();
@@ -127,8 +122,10 @@ public void onCompleted() {
127
122
if (isUnsubscribed () || completed ) {
128
123
return ;
129
124
}
125
+ if (error != null ) {
126
+ return ;
127
+ }
130
128
completed = true ;
131
- queue .onCompleted ();
132
129
schedule ();
133
130
}
134
131
@@ -137,53 +134,64 @@ public void onError(final Throwable e) {
137
134
if (isUnsubscribed () || completed ) {
138
135
return ;
139
136
}
137
+ if (error != null ) {
138
+ return ;
139
+ }
140
+ error = e ;
140
141
// unsubscribe eagerly since time will pass before the scheduled onError results in an unsubscribe event
141
142
unsubscribe ();
142
- completed = true ;
143
143
// mark failure so the polling thread will skip onNext still in the queue
144
+ completed = true ;
144
145
failure = true ;
145
- queue .onError (e );
146
146
schedule ();
147
147
}
148
148
149
- protected void schedule () {
150
- if (COUNTER_UPDATER .getAndIncrement (this ) == 0 ) {
151
- recursiveScheduler .schedule (new Action0 () {
149
+ final Action0 action = new Action0 () {
152
150
153
- @ Override
154
- public void call () {
155
- pollQueue ();
156
- }
151
+ @ Override
152
+ public void call () {
153
+ pollQueue ();
154
+ }
157
155
158
- });
156
+ };
157
+
158
+ protected void schedule () {
159
+ if (COUNTER_UPDATER .getAndIncrement (this ) == 0 ) {
160
+ recursiveScheduler .schedule (action );
159
161
}
160
162
}
161
163
162
164
// only execute this from schedule()
163
- private void pollQueue () {
165
+ void pollQueue () {
164
166
int emitted = 0 ;
165
167
do {
166
168
/*
167
169
* Set to 1 otherwise it could have grown very large while in the last poll loop
168
170
* and then we can end up looping all those times again here before exiting even once we've drained
169
171
*/
170
- COUNTER_UPDATER . set ( this , 1 ) ;
172
+ counter = 1 ;
171
173
174
+ // middle:
172
175
while (!scheduledUnsubscribe .isUnsubscribed ()) {
173
176
if (failure ) {
174
- // special handling to short-circuit an error propagation
175
- Object o = queue .poll ();
176
- // completed so we will skip onNext if they exist and only emit terminal events
177
- if (on .isError (o )) {
178
- // only emit error
179
- on .accept (child , o );
180
- // we have emitted a terminal event so return (exit the loop we're in)
177
+ child .onError (error );
178
+ return ;
179
+ } else {
180
+ if (requested == 0 && completed && queue .isEmpty ()) {
181
+ child .onCompleted ();
181
182
return ;
182
183
}
183
- } else {
184
184
if (REQUESTED .getAndDecrement (this ) != 0 ) {
185
185
Object o = queue .poll ();
186
186
if (o == null ) {
187
+ if (completed ) {
188
+ if (failure ) {
189
+ child .onError (error );
190
+ } else {
191
+ child .onCompleted ();
192
+ }
193
+ return ;
194
+ }
187
195
// nothing in queue
188
196
REQUESTED .incrementAndGet (this );
189
197
break ;
@@ -213,12 +221,10 @@ static final class ScheduledUnsubscribe implements Subscription {
213
221
final Scheduler .Worker worker ;
214
222
volatile int once ;
215
223
static final AtomicIntegerFieldUpdater <ScheduledUnsubscribe > ONCE_UPDATER = AtomicIntegerFieldUpdater .newUpdater (ScheduledUnsubscribe .class , "once" );
216
- final RxRingBuffer queue ;
217
224
volatile boolean unsubscribed = false ;
218
225
219
- public ScheduledUnsubscribe (Scheduler .Worker worker , RxRingBuffer queue ) {
226
+ public ScheduledUnsubscribe (Scheduler .Worker worker ) {
220
227
this .worker = worker ;
221
- this .queue = queue ;
222
228
}
223
229
224
230
@ Override
0 commit comments