|
39 | 39 | import reactor.netty.ConnectionObserver;
|
40 | 40 | import reactor.netty.channel.ChannelMetricsRecorder;
|
41 | 41 | import reactor.netty.channel.ChannelOperations;
|
| 42 | +import reactor.netty.internal.shaded.reactor.pool.PoolBuilder; |
| 43 | +import reactor.netty.internal.shaded.reactor.pool.PoolConfig; |
| 44 | +import reactor.netty.internal.shaded.reactor.pool.decorators.InstrumentedPoolDecorators; |
42 | 45 | import reactor.netty.resources.ConnectionProvider;
|
43 | 46 | import reactor.netty.resources.PooledConnectionProvider;
|
44 | 47 | import reactor.netty.transport.ClientTransportConfig;
|
|
51 | 54 | import reactor.util.annotation.Nullable;
|
52 | 55 | import reactor.util.concurrent.Queues;
|
53 | 56 | import reactor.util.context.Context;
|
| 57 | +import reactor.util.function.Tuples; |
54 | 58 |
|
55 | 59 | import java.io.IOException;
|
56 | 60 | import java.net.SocketAddress;
|
57 | 61 | import java.time.Duration;
|
| 62 | +import java.util.Iterator; |
| 63 | +import java.util.List; |
58 | 64 | import java.util.Queue;
|
| 65 | +import java.util.concurrent.Executor; |
| 66 | +import java.util.concurrent.atomic.AtomicInteger; |
59 | 67 | import java.util.function.BiPredicate;
|
60 | 68 | import java.util.function.Function;
|
| 69 | +import java.util.stream.Collectors; |
| 70 | +import java.util.stream.StreamSupport; |
61 | 71 |
|
62 | 72 | import static reactor.netty.ReactorNetty.format;
|
63 | 73 | import static reactor.netty.ReactorNetty.getChannelContext;
|
@@ -565,12 +575,56 @@ static final class PooledConnectionAllocator {
|
565 | 575 | this.config = (HttpClientConfig) config;
|
566 | 576 | this.remoteAddress = remoteAddress;
|
567 | 577 | this.resolver = resolver;
|
568 |
| - this.pool = id == null ? |
569 |
| - poolFactory.newPool(connectChannel(), null, DEFAULT_DESTROY_HANDLER, DEFAULT_EVICTION_PREDICATE, |
570 |
| - poolConfig -> new Http2Pool(poolConfig, poolFactory.allocationStrategy())) : |
571 |
| - poolFactory.newPool(connectChannel(), DEFAULT_DESTROY_HANDLER, DEFAULT_EVICTION_PREDICATE, |
572 |
| - new MicrometerPoolMetricsRecorder(id, name, remoteAddress), |
573 |
| - poolConfig -> new Http2Pool(poolConfig, poolFactory.allocationStrategy())); |
| 578 | + |
| 579 | + Http2AllocationStrategy http2Strategy = poolFactory.allocationStrategy() instanceof Http2AllocationStrategy ? |
| 580 | + (Http2AllocationStrategy) poolFactory.allocationStrategy() : null; |
| 581 | + |
| 582 | + if (http2Strategy == null || !http2Strategy.enableWorkStealing) { |
| 583 | + this.pool = id == null ? |
| 584 | + poolFactory.newPool(connectChannel(), null, DEFAULT_DESTROY_HANDLER, DEFAULT_EVICTION_PREDICATE, |
| 585 | + poolConfig -> new Http2Pool(poolConfig, poolFactory.allocationStrategy())) : |
| 586 | + poolFactory.newPool(connectChannel(), DEFAULT_DESTROY_HANDLER, DEFAULT_EVICTION_PREDICATE, |
| 587 | + new MicrometerPoolMetricsRecorder(id, name, remoteAddress), |
| 588 | + poolConfig -> new Http2Pool(poolConfig, poolFactory.allocationStrategy())); |
| 589 | + } |
| 590 | + else { |
| 591 | + // Create one connection allocator (it will be shared by all Http2Pool instances) |
| 592 | + Publisher<Connection> allocator = connectChannel(); |
| 593 | + |
| 594 | + List<Executor> execs = StreamSupport.stream(config.loopResources().onClient(true).spliterator(), false) |
| 595 | + .limit(http2Strategy.maxConnections) |
| 596 | + .collect(Collectors.toList()); |
| 597 | + Iterator<Executor> execsIter = execs.iterator(); |
| 598 | + |
| 599 | + MicrometerPoolMetricsRecorder micrometerRecorder = id == null ? null : new MicrometerPoolMetricsRecorder(id, name, remoteAddress); |
| 600 | + AtomicInteger subPoolIndex = new AtomicInteger(); |
| 601 | + |
| 602 | + this.pool = InstrumentedPoolDecorators.concurrentPools(execs.size(), allocator, |
| 603 | + (PoolBuilder<Connection, PoolConfig<Connection>> poolBuilder) -> { |
| 604 | + int index = subPoolIndex.getAndIncrement(); |
| 605 | + int minDiv = http2Strategy.minConnections / execs.size(); |
| 606 | + int minMod = http2Strategy.minConnections % execs.size(); |
| 607 | + int maxDiv = http2Strategy.maxConnections / execs.size(); |
| 608 | + int maxMod = http2Strategy.maxConnections % execs.size(); |
| 609 | + |
| 610 | + int minConn = index < minMod ? minDiv + 1 : minDiv; |
| 611 | + int maxConn = index < maxMod ? maxDiv + 1 : maxDiv; |
| 612 | + |
| 613 | + Http2AllocationStrategy adaptedH2Strategy = Http2AllocationStrategy.builder(http2Strategy) |
| 614 | + .minConnections(minConn) |
| 615 | + .maxConnections(maxConn) |
| 616 | + .build(); |
| 617 | + |
| 618 | + InstrumentedPool<Connection> pool = |
| 619 | + id == null ? |
| 620 | + poolFactory.newPool(poolBuilder, maxConn, adaptedH2Strategy, DEFAULT_DESTROY_HANDLER, DEFAULT_EVICTION_PREDICATE, |
| 621 | + poolConfig -> new Http2Pool(poolConfig, adaptedH2Strategy)) : |
| 622 | + poolFactory.newPool(poolBuilder, maxConn, adaptedH2Strategy, DEFAULT_DESTROY_HANDLER, DEFAULT_EVICTION_PREDICATE, |
| 623 | + micrometerRecorder, |
| 624 | + poolConfig -> new Http2Pool(poolConfig, adaptedH2Strategy)); |
| 625 | + return Tuples.of(pool, execsIter.next()); |
| 626 | + }); |
| 627 | + } |
574 | 628 | }
|
575 | 629 |
|
576 | 630 | Publisher<Connection> connectChannel() {
|
|
0 commit comments