|
1 | 1 | /*
|
2 |
| - * Copyright (c) 2020-2023 VMware, Inc. or its affiliates, All Rights Reserved. |
| 2 | + * Copyright (c) 2020-2024 VMware, Inc. or its affiliates, All Rights Reserved. |
3 | 3 | *
|
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 5 | * you may not use this file except in compliance with the License.
|
|
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.TransportConfig;
|
|
50 | 53 | import reactor.util.annotation.Nullable;
|
51 | 54 | import reactor.util.concurrent.Queues;
|
52 | 55 | import reactor.util.context.Context;
|
| 56 | +import reactor.util.function.Tuples; |
53 | 57 |
|
54 | 58 | import java.io.IOException;
|
55 | 59 | import java.net.SocketAddress;
|
56 | 60 | import java.time.Duration;
|
| 61 | +import java.util.Iterator; |
| 62 | +import java.util.List; |
57 | 63 | import java.util.Queue;
|
| 64 | +import java.util.concurrent.Executor; |
| 65 | +import java.util.concurrent.atomic.AtomicInteger; |
58 | 66 | import java.util.function.BiPredicate;
|
59 | 67 | import java.util.function.Function;
|
| 68 | +import java.util.stream.Collectors; |
| 69 | +import java.util.stream.StreamSupport; |
60 | 70 |
|
61 | 71 | import static reactor.netty.ReactorNetty.format;
|
62 | 72 | import static reactor.netty.ReactorNetty.getChannelContext;
|
@@ -536,12 +546,56 @@ static final class PooledConnectionAllocator {
|
536 | 546 | this.config = (HttpClientConfig) config;
|
537 | 547 | this.remoteAddress = remoteAddress;
|
538 | 548 | this.resolver = resolver;
|
539 |
| - this.pool = id == null ? |
540 |
| - poolFactory.newPool(connectChannel(), null, DEFAULT_DESTROY_HANDLER, DEFAULT_EVICTION_PREDICATE, |
541 |
| - poolConfig -> new Http2Pool(poolConfig, poolFactory.allocationStrategy())) : |
542 |
| - poolFactory.newPool(connectChannel(), DEFAULT_DESTROY_HANDLER, DEFAULT_EVICTION_PREDICATE, |
543 |
| - new MicrometerPoolMetricsRecorder(id, name, remoteAddress), |
544 |
| - poolConfig -> new Http2Pool(poolConfig, poolFactory.allocationStrategy())); |
| 549 | + |
| 550 | + Http2AllocationStrategy http2Strategy = poolFactory.allocationStrategy() instanceof Http2AllocationStrategy ? |
| 551 | + (Http2AllocationStrategy) poolFactory.allocationStrategy() : null; |
| 552 | + |
| 553 | + if (http2Strategy == null || !http2Strategy.enableWorkStealing) { |
| 554 | + this.pool = id == null ? |
| 555 | + poolFactory.newPool(connectChannel(), null, DEFAULT_DESTROY_HANDLER, DEFAULT_EVICTION_PREDICATE, |
| 556 | + poolConfig -> new Http2Pool(poolConfig, poolFactory.allocationStrategy())) : |
| 557 | + poolFactory.newPool(connectChannel(), DEFAULT_DESTROY_HANDLER, DEFAULT_EVICTION_PREDICATE, |
| 558 | + new MicrometerPoolMetricsRecorder(id, name, remoteAddress), |
| 559 | + poolConfig -> new Http2Pool(poolConfig, poolFactory.allocationStrategy())); |
| 560 | + } |
| 561 | + else { |
| 562 | + // Create one connection allocator (it will be shared by all Http2Pool instances) |
| 563 | + Publisher<Connection> allocator = connectChannel(); |
| 564 | + |
| 565 | + List<Executor> execs = StreamSupport.stream(config.loopResources().onClient(true).spliterator(), false) |
| 566 | + .limit(http2Strategy.maxConnections) |
| 567 | + .collect(Collectors.toList()); |
| 568 | + Iterator<Executor> execsIter = execs.iterator(); |
| 569 | + |
| 570 | + MicrometerPoolMetricsRecorder micrometerRecorder = id == null ? null : new MicrometerPoolMetricsRecorder(id, name, remoteAddress); |
| 571 | + AtomicInteger subPoolIndex = new AtomicInteger(); |
| 572 | + |
| 573 | + this.pool = InstrumentedPoolDecorators.concurrentPools(execs.size(), allocator, |
| 574 | + (PoolBuilder<Connection, PoolConfig<Connection>> poolBuilder) -> { |
| 575 | + int index = subPoolIndex.getAndIncrement(); |
| 576 | + int minDiv = http2Strategy.minConnections / execs.size(); |
| 577 | + int minMod = http2Strategy.minConnections % execs.size(); |
| 578 | + int maxDiv = http2Strategy.maxConnections / execs.size(); |
| 579 | + int maxMod = http2Strategy.maxConnections % execs.size(); |
| 580 | + |
| 581 | + int minConn = index < minMod ? minDiv + 1 : minDiv; |
| 582 | + int maxConn = index < maxMod ? maxDiv + 1 : maxDiv; |
| 583 | + |
| 584 | + Http2AllocationStrategy adaptedH2Strategy = Http2AllocationStrategy.builder(http2Strategy) |
| 585 | + .minConnections(minConn) |
| 586 | + .maxConnections(maxConn) |
| 587 | + .build(); |
| 588 | + |
| 589 | + InstrumentedPool<Connection> pool = |
| 590 | + id == null ? |
| 591 | + poolFactory.newPool(poolBuilder, maxConn, adaptedH2Strategy, DEFAULT_DESTROY_HANDLER, DEFAULT_EVICTION_PREDICATE, |
| 592 | + poolConfig -> new Http2Pool(poolConfig, adaptedH2Strategy)) : |
| 593 | + poolFactory.newPool(poolBuilder, maxConn, adaptedH2Strategy, DEFAULT_DESTROY_HANDLER, DEFAULT_EVICTION_PREDICATE, |
| 594 | + micrometerRecorder, |
| 595 | + poolConfig -> new Http2Pool(poolConfig, adaptedH2Strategy)); |
| 596 | + return Tuples.of(pool, execsIter.next()); |
| 597 | + }); |
| 598 | + } |
545 | 599 | }
|
546 | 600 |
|
547 | 601 | Publisher<Connection> connectChannel() {
|
|
0 commit comments