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