18
18
import java .time .Duration ;
19
19
import java .util .concurrent .CancellationException ;
20
20
import java .util .concurrent .atomic .AtomicIntegerFieldUpdater ;
21
- import java .util .concurrent .atomic .AtomicLongFieldUpdater ;
22
21
import java .util .concurrent .atomic .AtomicReferenceFieldUpdater ;
23
22
import java .util .function .BiConsumer ;
24
- import org .reactivestreams .Subscription ;
25
- import reactor .core .CoreSubscriber ;
26
23
import reactor .core .Disposable ;
27
24
import reactor .core .Exceptions ;
28
- import reactor .core .Scannable ;
29
25
import reactor .core .publisher .Operators ;
30
26
import reactor .util .annotation .Nullable ;
31
27
import reactor .util .context .Context ;
@@ -170,19 +166,19 @@ public T block(@Nullable Duration timeout) {
170
166
delay = System .nanoTime () + timeout .toNanos ();
171
167
}
172
168
for (; ; ) {
173
- BiConsumer < T , Throwable >[] inners = this .subscribers ;
169
+ subscribers = this .subscribers ;
174
170
175
- if (inners == READY ) {
171
+ if (subscribers == READY ) {
176
172
final T value = this .value ;
177
173
if (value != null ) {
178
174
return value ;
179
175
} else {
180
176
// value == null means racing between invalidate and this block
181
177
// thus, we have to update the state again and see what happened
182
- inners = this .subscribers ;
178
+ subscribers = this .subscribers ;
183
179
}
184
180
}
185
- if (inners == TERMINATED ) {
181
+ if (subscribers == TERMINATED ) {
186
182
RuntimeException re = Exceptions .propagate (this .t );
187
183
re = Exceptions .addSuppressed (re , new Exception ("Terminated with an error" ));
188
184
throw re ;
@@ -191,6 +187,12 @@ public T block(@Nullable Duration timeout) {
191
187
throw new IllegalStateException ("Timeout on Mono blocking read" );
192
188
}
193
189
190
+ // connect again since invalidate() has happened in between
191
+ if (subscribers == EMPTY_UNSUBSCRIBED
192
+ && SUBSCRIBERS .compareAndSet (this , EMPTY_UNSUBSCRIBED , EMPTY_SUBSCRIBED )) {
193
+ this .doSubscribe ();
194
+ }
195
+
194
196
Thread .sleep (1 );
195
197
}
196
198
} catch (InterruptedException ie ) {
@@ -203,6 +205,7 @@ public T block(@Nullable Duration timeout) {
203
205
@ SuppressWarnings ("unchecked" )
204
206
final void terminate (Throwable t ) {
205
207
if (isDisposed ()) {
208
+ Operators .onErrorDropped (t , Context .empty ());
206
209
return ;
207
210
}
208
211
@@ -390,175 +393,4 @@ final void remove(BiConsumer<T, Throwable> ps) {
390
393
}
391
394
}
392
395
}
393
-
394
- abstract static class DeferredResolution <T , R >
395
- implements CoreSubscriber <T >, Subscription , Scannable , BiConsumer <R , Throwable > {
396
-
397
- final ResolvingOperator <R > parent ;
398
- final CoreSubscriber <? super T > actual ;
399
-
400
- volatile long requested ;
401
-
402
- @ SuppressWarnings ("rawtypes" )
403
- static final AtomicLongFieldUpdater <DeferredResolution > REQUESTED =
404
- AtomicLongFieldUpdater .newUpdater (DeferredResolution .class , "requested" );
405
-
406
- static final long STATE_SUBSCRIBED = -1 ;
407
- static final long STATE_CANCELLED = Long .MIN_VALUE ;
408
-
409
- Subscription s ;
410
- boolean done ;
411
-
412
- DeferredResolution (ResolvingOperator <R > parent , CoreSubscriber <? super T > actual ) {
413
- this .parent = parent ;
414
- this .actual = actual ;
415
- }
416
-
417
- @ Override
418
- public final Context currentContext () {
419
- return this .actual .currentContext ();
420
- }
421
-
422
- @ Nullable
423
- @ Override
424
- public Object scanUnsafe (Attr key ) {
425
- long state = this .requested ;
426
-
427
- if (key == Attr .PARENT ) {
428
- return this .s ;
429
- }
430
- if (key == Attr .ACTUAL ) {
431
- return this .parent ;
432
- }
433
- if (key == Attr .TERMINATED ) {
434
- return this .done ;
435
- }
436
- if (key == Attr .CANCELLED ) {
437
- return state == STATE_CANCELLED ;
438
- }
439
-
440
- return null ;
441
- }
442
-
443
- @ Override
444
- public final void onSubscribe (Subscription s ) {
445
- final long state = this .requested ;
446
- Subscription a = this .s ;
447
- if (state == STATE_CANCELLED ) {
448
- s .cancel ();
449
- return ;
450
- }
451
- if (a != null ) {
452
- s .cancel ();
453
- return ;
454
- }
455
-
456
- long r ;
457
- long accumulated = 0 ;
458
- for (; ; ) {
459
- r = this .requested ;
460
-
461
- if (r == STATE_CANCELLED || r == STATE_SUBSCRIBED ) {
462
- s .cancel ();
463
- return ;
464
- }
465
-
466
- this .s = s ;
467
-
468
- long toRequest = r - accumulated ;
469
- if (toRequest > 0 ) { // if there is something,
470
- s .request (toRequest ); // then we do a request on the given subscription
471
- }
472
- accumulated = r ;
473
-
474
- if (REQUESTED .compareAndSet (this , r , STATE_SUBSCRIBED )) {
475
- return ;
476
- }
477
- }
478
- }
479
-
480
- @ Override
481
- public final void onNext (T payload ) {
482
- this .actual .onNext (payload );
483
- }
484
-
485
- @ Override
486
- public final void onError (Throwable t ) {
487
- if (this .done ) {
488
- Operators .onErrorDropped (t , this .actual .currentContext ());
489
- return ;
490
- }
491
-
492
- this .done = true ;
493
- this .actual .onError (t );
494
- }
495
-
496
- @ Override
497
- public final void onComplete () {
498
- if (this .done ) {
499
- return ;
500
- }
501
-
502
- this .done = true ;
503
- this .actual .onComplete ();
504
- }
505
-
506
- @ Override
507
- public void request (long n ) {
508
- if (Operators .validate (n )) {
509
- long r = this .requested ; // volatile read beforehand
510
-
511
- if (r > STATE_SUBSCRIBED ) { // works only in case onSubscribe has not happened
512
- long u ;
513
- for (; ; ) { // normal CAS loop with overflow protection
514
- if (r == Long .MAX_VALUE ) {
515
- // if r == Long.MAX_VALUE then we dont care and we can loose this
516
- // request just in case of racing
517
- return ;
518
- }
519
- u = Operators .addCap (r , n );
520
- if (REQUESTED .compareAndSet (this , r , u )) {
521
- // Means increment happened before onSubscribe
522
- return ;
523
- } else {
524
- // Means increment happened after onSubscribe
525
-
526
- // update new state to see what exactly happened (onSubscribe |cancel | requestN)
527
- r = this .requested ;
528
-
529
- // check state (expect -1 | -2 to exit, otherwise repeat)
530
- if (r < 0 ) {
531
- break ;
532
- }
533
- }
534
- }
535
- }
536
-
537
- if (r == STATE_CANCELLED ) { // if canceled, just exit
538
- return ;
539
- }
540
-
541
- // if onSubscribe -> subscription exists (and we sure of that because volatile read
542
- // after volatile write) so we can execute requestN on the subscription
543
- this .s .request (n );
544
- }
545
- }
546
-
547
- public boolean isCancelled () {
548
- return this .requested == STATE_CANCELLED ;
549
- }
550
-
551
- public void cancel () {
552
- long state = REQUESTED .getAndSet (this , STATE_CANCELLED );
553
- if (state == STATE_CANCELLED ) {
554
- return ;
555
- }
556
-
557
- if (state == STATE_SUBSCRIBED ) {
558
- this .s .cancel ();
559
- } else {
560
- this .parent .remove (this );
561
- }
562
- }
563
- }
564
396
}
0 commit comments