@@ -407,8 +407,11 @@ void drainLoop() {
407407 log .debug (format (slot .connection .channel (), "Channel activated" ));
408408 }
409409 ACQUIRED .incrementAndGet (this );
410+ // Reserve concurrency and re-offer the slot before async deliver so concurrent acquires can reuse the connection
411+ slot .incrementConcurrencyAndGet ();
412+ slot .deactivate ();
410413 slot .connection .channel ().eventLoop ().execute (() -> {
411- borrower .deliver (new Http2PooledRef (slot ));
414+ borrower .deliver (new Http2PooledRef (slot ), true );
412415 drain ();
413416 });
414417 }
@@ -836,17 +839,31 @@ public String toString() {
836839 }
837840
838841 void deliver (Http2PooledRef poolSlot ) {
842+ deliver (poolSlot , false );
843+ }
844+
845+ void deliver (Http2PooledRef poolSlot , boolean alreadyReserved ) {
839846 assert poolSlot .slot .connection .channel ().eventLoop ().inEventLoop ();
840847 poolSlot .slot .updateMaxConcurrentStreams ();
841- if (!poolSlot .slot .canOpenStream ()) {
842- poolSlot .slot .deactivate ();
848+
849+ int effectiveConcurrency = poolSlot .slot .concurrency () - (alreadyReserved ? 1 : 0 );
850+ if (!poolSlot .slot .canOpenStream (effectiveConcurrency )) {
851+ if (alreadyReserved ) {
852+ // Concurrency was reserved in drainLoop, rollback reservation
853+ poolSlot .slot .decrementConcurrencyAndGet ();
854+ }
855+ else {
856+ poolSlot .slot .deactivate ();
857+ }
843858 pool .addPending (pool .pending , this , true );
844859 return ;
845860 }
846861 stopPendingCountdown (true );
847- // Increment concurrency BEFORE deactivate so that canOpenStream() is correct for other threads
848- poolSlot .slot .incrementConcurrencyAndGet ();
849- poolSlot .slot .deactivate ();
862+ if (!alreadyReserved ) {
863+ // Increment concurrency BEFORE deactivate so that canOpenStream() is correct for other threads
864+ poolSlot .slot .incrementConcurrencyAndGet ();
865+ poolSlot .slot .deactivate ();
866+ }
850867 if (get ()) {
851868 //CANCELLED or timeout reached
852869 poolSlot .invalidate ().subscribe (aVoid -> {}, e -> Operators .onErrorDropped (e , Context .empty ()));
@@ -1037,7 +1054,13 @@ private long computeMaxConcurrentStreams() {
10371054 }
10381055
10391056 boolean canOpenStream () {
1040- int concurrency = this .concurrency ;
1057+ return canOpenStream (this .concurrency );
1058+ }
1059+
1060+ boolean canOpenStream (int concurrency ) {
1061+ if (concurrency < 0 ) {
1062+ return false ;
1063+ }
10411064 long max = this .maxConcurrentStreams ;
10421065 // For non-HTTP/2 connections (max == 0), allow opening a stream if concurrency is 0
10431066 // For HTTP/2 connections, check that we haven't reached max concurrent streams
0 commit comments