@@ -118,7 +118,7 @@ private void start(final Completable responderCompletable) {
118
118
/* state of cancellation subjects during connection */
119
119
final Int2ObjectHashMap <Subscription > cancellationSubscriptions = new Int2ObjectHashMap <>();
120
120
/* streams in flight that can receive REQUEST_N messages */
121
- final Int2ObjectHashMap <Subscription > inFlight = new Int2ObjectHashMap <>(); // TODO not being used
121
+ final Int2ObjectHashMap <SubscriptionArbiter > inFlight = new Int2ObjectHashMap <>();
122
122
/* bidirectional channels */
123
123
final Int2ObjectHashMap <UnicastSubject <Payload >> channels = new Int2ObjectHashMap <>(); // TODO should/can we make this optional so that it only gets allocated per connection if channels are
124
124
// used?
@@ -205,14 +205,14 @@ public void onNext(Frame requestFrame) {
205
205
}
206
206
return ;
207
207
} else if (requestFrame .getType () == FrameType .REQUEST_N ) {
208
- Subscription inFlightSubscription = null ;
208
+ SubscriptionArbiter inFlightSubscription = null ;
209
209
synchronized (Responder .this )
210
210
{
211
211
inFlightSubscription = inFlight .get (requestFrame .getStreamId ());
212
212
}
213
213
if (inFlightSubscription != null )
214
214
{
215
- inFlightSubscription .request (Frame .RequestN .requestN (requestFrame ));
215
+ inFlightSubscription .addApplicationRequest (Frame .RequestN .requestN (requestFrame ));
216
216
return ;
217
217
}
218
218
// TODO should we do anything if we don't find the stream? emitting an error is risky as the responder could have terminated and cleaned up already
@@ -407,15 +407,15 @@ private Publisher<Frame> handleRequestStream(
407
407
Frame requestFrame ,
408
408
final RequestHandler requestHandler ,
409
409
final Int2ObjectHashMap <Subscription > cancellationSubscriptions ,
410
- final Int2ObjectHashMap <Subscription > inFlight ) {
410
+ final Int2ObjectHashMap <SubscriptionArbiter > inFlight ) {
411
411
return _handleRequestStream (requestStreamHandler , requestFrame , requestHandler , cancellationSubscriptions , inFlight , true );
412
412
}
413
413
414
414
private Publisher <Frame > handleRequestSubscription (
415
415
Frame requestFrame ,
416
416
final RequestHandler requestHandler ,
417
417
final Int2ObjectHashMap <Subscription > cancellationSubscriptions ,
418
- final Int2ObjectHashMap <Subscription > inFlight ) {
418
+ final Int2ObjectHashMap <SubscriptionArbiter > inFlight ) {
419
419
return _handleRequestStream (requestSubscriptionHandler , requestFrame , requestHandler , cancellationSubscriptions , inFlight , false );
420
420
}
421
421
@@ -434,7 +434,7 @@ private Publisher<Frame> _handleRequestStream(
434
434
Frame requestFrame ,
435
435
final RequestHandler requestHandler ,
436
436
final Int2ObjectHashMap <Subscription > cancellationSubscriptions ,
437
- final Int2ObjectHashMap <Subscription > inFlight ,
437
+ final Int2ObjectHashMap <SubscriptionArbiter > inFlight ,
438
438
final boolean allowCompletion ) {
439
439
440
440
return new Publisher <Frame >() {
@@ -445,19 +445,25 @@ public void subscribe(Subscriber<? super Frame> child) {
445
445
446
446
final AtomicBoolean started = new AtomicBoolean (false );
447
447
final AtomicReference <Subscription > parent = new AtomicReference <>();
448
+ final SubscriptionArbiter arbiter = new SubscriptionArbiter ();
448
449
449
450
@ Override
450
451
public void request (long n ) {
451
- if (n > 0 && started .compareAndSet (false , true )) {
452
+ if (n <= 0 ) {
453
+ return ;
454
+ }
455
+ if (started .compareAndSet (false , true )) {
456
+ arbiter .addTransportRequest (n );
452
457
final int streamId = requestFrame .getStreamId ();
453
458
454
459
handler .apply (requestHandler , requestFrame ).subscribe (new Subscriber <Payload >() {
455
460
456
461
@ Override
457
462
public void onSubscribe (Subscription s ) {
458
463
if (parent .compareAndSet (null , s )) {
459
- inFlight .put (streamId , s );
460
- s .request (Frame .Request .initialRequestN (requestFrame ));
464
+ inFlight .put (streamId , arbiter );
465
+ arbiter .addApplicationRequest (Frame .Request .initialRequestN (requestFrame ));
466
+ arbiter .addApplicationProducer (s );
461
467
} else {
462
468
s .cancel ();
463
469
cleanup ();
@@ -493,6 +499,8 @@ public void onComplete() {
493
499
}
494
500
495
501
});
502
+ } else {
503
+ arbiter .addTransportRequest (n );
496
504
}
497
505
}
498
506
@@ -561,7 +569,7 @@ private Publisher<Frame> handleRequestChannel(Frame requestFrame,
561
569
RequestHandler requestHandler ,
562
570
Int2ObjectHashMap <UnicastSubject <Payload >> channels ,
563
571
Int2ObjectHashMap <Subscription > cancellationSubscriptions ,
564
- Int2ObjectHashMap <Subscription > inFlight ) {
572
+ Int2ObjectHashMap <SubscriptionArbiter > inFlight ) {
565
573
566
574
UnicastSubject <Payload > channelSubject = null ;
567
575
synchronized (Responder .this ) {
@@ -576,10 +584,15 @@ public void subscribe(Subscriber<? super Frame> child) {
576
584
577
585
final AtomicBoolean started = new AtomicBoolean (false );
578
586
final AtomicReference <Subscription > parent = new AtomicReference <>();
587
+ final SubscriptionArbiter arbiter = new SubscriptionArbiter ();
579
588
580
589
@ Override
581
590
public void request (long n ) {
582
- if (n > 0 && started .compareAndSet (false , true )) {
591
+ if (n <= 0 ) {
592
+ return ;
593
+ }
594
+ if (started .compareAndSet (false , true )) {
595
+ arbiter .addTransportRequest (n );
583
596
final int streamId = requestFrame .getStreamId ();
584
597
585
598
// first request on this channel
@@ -609,8 +622,9 @@ public void request(long n) {
609
622
@ Override
610
623
public void onSubscribe (Subscription s ) {
611
624
if (parent .compareAndSet (null , s )) {
612
- inFlight .put (streamId , s );
613
- s .request (Frame .Request .initialRequestN (requestFrame ));
625
+ inFlight .put (streamId , arbiter );
626
+ arbiter .addApplicationRequest (Frame .Request .initialRequestN (requestFrame ));
627
+ arbiter .addApplicationProducer (s );
614
628
} else {
615
629
s .cancel ();
616
630
cleanup ();
@@ -638,6 +652,8 @@ public void onComplete() {
638
652
}
639
653
640
654
});
655
+ } else {
656
+ arbiter .addTransportRequest (n );
641
657
}
642
658
}
643
659
@@ -681,5 +697,51 @@ private void cleanup() {
681
697
}
682
698
}
683
699
}
700
+
701
+ private static class SubscriptionArbiter {
702
+ private Subscription applicationProducer ;
703
+ private long appRequested = 0 ;
704
+ private long transportRequested = 0 ;
705
+ private long requestedToProducer = 0 ;
706
+
707
+ public void addApplicationRequest (long n ) {
708
+ synchronized (this ) {
709
+ appRequested += n ;
710
+ }
711
+ tryRequest ();
712
+ }
713
+
714
+ public void addApplicationProducer (Subscription s ) {
715
+ synchronized (this ) {
716
+ applicationProducer = s ;
717
+ }
718
+ tryRequest ();
719
+ }
720
+
721
+ public void addTransportRequest (long n ) {
722
+ synchronized (this ) {
723
+ transportRequested += n ;
724
+ }
725
+ tryRequest ();
726
+ }
727
+
728
+ private void tryRequest () {
729
+ long toRequest = 0 ;
730
+ Subscription s = null ;
731
+ synchronized (this ) {
732
+ if (applicationProducer == null ) {
733
+ return ;
734
+ }
735
+ s = applicationProducer ;
736
+ long minToRequest = Math .min (appRequested , transportRequested );
737
+ toRequest = minToRequest - requestedToProducer ;
738
+ requestedToProducer += toRequest ;
739
+ }
740
+ if (toRequest > 0 ) {
741
+ s .request (toRequest );
742
+ }
743
+ }
744
+
745
+ }
684
746
685
747
}
0 commit comments