Skip to content

Commit e166852

Browse files
authored
balancer: reduce lock scope in exact balance by splitting incNumConnections (#43862)
Commit Message: Move the resource-limit bookkeeping (openConnections().inc()) outside the critical section in ExactConnectionBalancerImpl::pickTargetHandler(). Only the raw connection counter increment, needed for balancing correctness, is held under the lock; the ResourceLimit gauge update is deferred to after lock release. This is achieved by adding two optional virtual methods to BalancedConnectionHandler with safe defaults: - incConnectionCount(): increments only the balancing counter (defaults to incNumConnections() for backward compatibility) - postConnectionAccepted(): performs resource-limit bookkeeping (defaults to no-op) ActiveTcpListener overrides both to split the work that was previously done in a single incNumConnections() call. Additional Description: Risk Level: Testing: Docs Changes: Release Notes: Platform Specific Features: [Optional Runtime guard:] [Optional Fixes #Issue] [Optional Fixes commit #PR or SHA] [Optional Deprecated:] [Optional [API Considerations](https://github.com/envoyproxy/envoy/blob/main/api/review_checklist.md):] Signed-off-by: William Dauchy <william.dauchy@datadoghq.com>
1 parent bd279ea commit e166852

8 files changed

Lines changed: 54 additions & 28 deletions

File tree

contrib/dlb/source/connection_balancer_impl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ class DlbBalancedConnectionHandlerImpl : public Envoy::Network::BalancedConnecti
4343

4444
// Only for override, those are never used.
4545
uint64_t numConnections() const override { return 0; }
46-
void incNumConnections() override {}
46+
void preIncNumConnections() override {}
47+
void postIncNumConnections() override {}
4748

4849
private:
4950
Envoy::Network::BalancedConnectionHandler& handler_;

envoy/network/connection_balancer.h

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,20 @@ class BalancedConnectionHandler {
1919
virtual uint64_t numConnections() const PURE;
2020

2121
/**
22-
* Increment the number of connections within the handler. This must be called by a connection
23-
* balancer implementation prior to a connection being picked via pickTargetHandler(). This makes
24-
* sure that connection counts are accurate during connection transfer (i.e., that the target
25-
* balancer accounts for the incoming connection). This is done by the balancer vs. the
26-
* connection handler to account for different locking needs inside the balancer.
22+
* Increment the connection count used for balancing decisions. Balancer implementations must call
23+
* this prior to returning from pickTargetHandler() to ensure accurate connection counts during
24+
* connection transfer. For balancers that hold a lock (e.g., ExactConnectionBalancerImpl), this
25+
* should be called inside the critical section, while postIncNumConnections() is called after
26+
* the lock is released.
2727
*/
28-
virtual void incNumConnections() PURE;
28+
virtual void preIncNumConnections() PURE;
29+
30+
/**
31+
* Perform any resource-limit bookkeeping after a connection has been assigned by the balancer.
32+
* This is the counterpart to preIncNumConnections() and must be called outside any balancer lock
33+
* to avoid holding the lock longer than necessary.
34+
*/
35+
virtual void postIncNumConnections() PURE;
2936

3037
/**
3138
* Post a connected socket to this connection handler. This is used for cross-thread connection
@@ -69,8 +76,9 @@ class ConnectionBalancer {
6976
* @return current_handler if the connection should stay bound to the current handler, or a
7077
* different handler if the connection should be rebalanced.
7178
*
72-
* NOTE: It is the responsibility of the balancer to call incNumConnections() on the returned
73-
* balancer. See the comments above for more explanation.
79+
* NOTE: It is the responsibility of the balancer to call preIncNumConnections() and
80+
* postIncNumConnections() on the returned handler. See the comments above for more
81+
* explanation.
7482
*/
7583
virtual BalancedConnectionHandler&
7684
pickTargetHandler(BalancedConnectionHandler& current_handler) PURE;

source/common/listener_manager/active_tcp_listener.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,13 @@ class ActiveTcpListener final : public Network::TcpListenerCallbacks,
6868

6969
// Network::BalancedConnectionHandler
7070
uint64_t numConnections() const override { return num_listener_connections_; }
71+
void preIncNumConnections() override { ++num_listener_connections_; }
72+
void postIncNumConnections() override { config_->openConnections().inc(); }
73+
74+
// ActiveStreamListenerBase
7175
void incNumConnections() override {
72-
++num_listener_connections_;
73-
config_->openConnections().inc();
76+
preIncNumConnections();
77+
postIncNumConnections();
7478
}
7579
void post(Network::ConnectionSocketPtr&& socket) override;
7680
void onAcceptWorker(Network::ConnectionSocketPtr&& socket,

source/common/network/connection_balancer_impl.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ ExactConnectionBalancerImpl::pickTargetHandler(BalancedConnectionHandler&) {
3232
}
3333
}
3434

35-
min_connection_handler->incNumConnections(); // NOLINT(clang-analyzer-core.CallAndMessage)
35+
min_connection_handler->preIncNumConnections(); // NOLINT(clang-analyzer-core.CallAndMessage)
3636
}
3737

38+
min_connection_handler->postIncNumConnections();
3839
return *min_connection_handler;
3940
}
4041

source/common/network/connection_balancer_impl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ class NopConnectionBalancerImpl : public ConnectionBalancer {
5656
BalancedConnectionHandler&
5757
pickTargetHandler(BalancedConnectionHandler& current_handler) override {
5858
// In the NOP case just increment the connection count and return the current handler.
59-
current_handler.incNumConnections();
59+
current_handler.preIncNumConnections();
60+
current_handler.postIncNumConnections();
6061
return current_handler;
6162
}
6263
};

source/extensions/bootstrap/internal_listener/active_internal_listener.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class ActiveInternalListener : public Network::InternalListener,
8686
}
8787
void onAccept(Network::ConnectionSocketPtr&& socket) override;
8888

89-
// Network::BalancedConnectionHandler
89+
// ActiveStreamListenerBase
9090
void incNumConnections() override { config_->openConnections().inc(); }
9191
void decNumConnections() override { config_->openConnections().dec(); }
9292

test/server/active_tcp_listener_test.cc

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -701,9 +701,11 @@ TEST_F(ActiveTcpListenerTest, RedirectedRebalancer) {
701701

702702
// 1. Listener1 re-balance. Set the balance target to the the active listener itself.
703703
EXPECT_CALL(balancer1, pickTargetHandler(_))
704-
.WillOnce(testing::DoAll(
705-
testing::WithArg<0>(Invoke([](auto& target) { target.incNumConnections(); })),
706-
ReturnRef(*active_listener1)));
704+
.WillOnce(testing::DoAll(testing::WithArg<0>(Invoke([](auto& target) {
705+
target.preIncNumConnections();
706+
target.postIncNumConnections();
707+
})),
708+
ReturnRef(*active_listener1)));
707709

708710
EXPECT_CALL(listener_config1, filterChainFactory())
709711
.WillRepeatedly(ReturnRef(filter_chain_factory_));
@@ -732,9 +734,11 @@ TEST_F(ActiveTcpListenerTest, RedirectedRebalancer) {
732734

733735
// 3. Listener2 re-balance. Set the balance target to the the active listener itself.
734736
EXPECT_CALL(balancer2, pickTargetHandler(_))
735-
.WillOnce(testing::DoAll(
736-
testing::WithArg<0>(Invoke([](auto& target) { target.incNumConnections(); })),
737-
ReturnRef(*active_listener2)));
737+
.WillOnce(testing::DoAll(testing::WithArg<0>(Invoke([](auto& target) {
738+
target.preIncNumConnections();
739+
target.postIncNumConnections();
740+
})),
741+
ReturnRef(*active_listener2)));
738742

739743
EXPECT_CALL(listener_config2, filterChainFactory())
740744
.WillRepeatedly(ReturnRef(filter_chain_factory_));
@@ -810,9 +814,11 @@ TEST_F(ActiveTcpListenerTest, SkipRedirection) {
810814

811815
// 1. Listener1 re-balance. Set the balance target to the the active listener itself.
812816
EXPECT_CALL(balancer1, pickTargetHandler(_))
813-
.WillOnce(testing::DoAll(
814-
testing::WithArg<0>(Invoke([](auto& target) { target.incNumConnections(); })),
815-
ReturnRef(*active_listener1)));
817+
.WillOnce(testing::DoAll(testing::WithArg<0>(Invoke([](auto& target) {
818+
target.preIncNumConnections();
819+
target.postIncNumConnections();
820+
})),
821+
ReturnRef(*active_listener1)));
816822

817823
EXPECT_CALL(listener_config1, filterChainFactory())
818824
.WillRepeatedly(ReturnRef(filter_chain_factory_));
@@ -901,7 +907,8 @@ TEST_F(ActiveTcpListenerTest, Rebalance) {
901907
// active_listener1 re-balance. Set the balance target to the the active_listener2.
902908
EXPECT_CALL(balancer1, pickTargetHandler(_))
903909
.WillOnce(testing::DoAll(testing::WithArg<0>(Invoke([&active_listener2](auto&) {
904-
active_listener2->incNumConnections();
910+
active_listener2->preIncNumConnections();
911+
active_listener2->postIncNumConnections();
905912
})),
906913
ReturnRef(*active_listener2)));
907914

test/server/connection_handler_test.cc

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,8 @@ TEST_F(ConnectionHandlerTest, RemoveListenerDuringRebalance) {
515515
post_cb = std::move(cb);
516516
});
517517
Network::MockConnectionSocket* connection = new NiceMock<Network::MockConnectionSocket>();
518-
current_handler->incNumConnections();
518+
current_handler->preIncNumConnections();
519+
current_handler->postIncNumConnections();
519520
#ifndef NDEBUG
520521
EXPECT_CALL(*access_log_, log(_, _));
521522
#endif
@@ -791,7 +792,8 @@ TEST_F(ConnectionHandlerTest, RebalanceWithMultiAddressListener) {
791792
EXPECT_CALL(*access_log_, log(_, _));
792793
EXPECT_CALL(manager_, findFilterChain(_, _)).WillOnce(Return(nullptr));
793794

794-
current_handler1->incNumConnections();
795+
current_handler1->preIncNumConnections();
796+
current_handler1->postIncNumConnections();
795797
listener_callbacks1->onAccept(std::make_unique<NiceMock<Network::MockConnectionSocket>>());
796798

797799
// Send connection to the second listener, expect mock_connection_balancer2 will be called.
@@ -801,7 +803,8 @@ TEST_F(ConnectionHandlerTest, RebalanceWithMultiAddressListener) {
801803
EXPECT_CALL(*access_log_, log(_, _));
802804
EXPECT_CALL(manager_, findFilterChain(_, _)).WillOnce(Return(nullptr));
803805

804-
current_handler2->incNumConnections();
806+
current_handler2->preIncNumConnections();
807+
current_handler2->postIncNumConnections();
805808
listener_callbacks2->onAccept(std::make_unique<NiceMock<Network::MockConnectionSocket>>());
806809

807810
EXPECT_CALL(*mock_connection_balancer1, unregisterHandler(_));
@@ -2328,7 +2331,8 @@ TEST_F(ConnectionHandlerTest, TcpListenerInplaceUpdate) {
23282331
<< "new listener should be inplace added and callback should not change";
23292332

23302333
Network::MockConnectionSocket* connection = new NiceMock<Network::MockConnectionSocket>();
2331-
current_handler->incNumConnections();
2334+
current_handler->preIncNumConnections();
2335+
current_handler->postIncNumConnections();
23322336

23332337
EXPECT_CALL(*mock_connection_balancer, pickTargetHandler(_))
23342338
.WillOnce(ReturnRef(*current_handler));

0 commit comments

Comments
 (0)