Skip to content

Commit

Permalink
backport to 1.53: xDS: fix crash when removing the last endpoint from…
Browse files Browse the repository at this point in the history
… the last locality in weighted_target (#32592)

Backport #32571 to 1.53.x.
  • Loading branch information
markdroth authored Mar 10, 2023
1 parent 7c7712a commit c11153c
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -641,8 +641,8 @@ void WeightedTargetLb::WeightedChild::OnConnectivityStateUpdateLocked(
state == GRPC_CHANNEL_READY) {
connectivity_state_ = state;
}
// Notify the LB policy.
weighted_target_policy_->UpdateStateLocked();
// Update the LB policy's state if this child is not deactivated.
if (weight_ != 0) weighted_target_policy_->UpdateStateLocked();
}

void WeightedTargetLb::WeightedChild::DeactivateLocked() {
Expand Down
42 changes: 42 additions & 0 deletions test/cpp/end2end/xds/xds_cluster_end2end_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,48 @@ TEST_P(EdsTest, OneLocalityWithNoEndpoints) {
});
}

// This tests the bug described in https://github.com/grpc/grpc/issues/32486.
TEST_P(EdsTest, LocalityBecomesEmptyWithDeactivatedChildStateUpdate) {
CreateAndStartBackends(1);
// Initial EDS resource has one locality with no endpoints.
EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
WaitForAllBackends(DEBUG_LOCATION);
// EDS update removes all endpoints from the locality.
EdsResourceArgs::Locality empty_locality("locality0", {});
args = EdsResourceArgs({std::move(empty_locality)});
balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
// Wait for RPCs to start failing.
constexpr char kErrorMessage[] =
"no children in weighted_target policy: "
"EDS resource eds_service_name contains empty localities: "
"\\[\\{region=\"xds_default_locality_region\", "
"zone=\"xds_default_locality_zone\", sub_zone=\"locality0\"\\}\\]";
SendRpcsUntil(DEBUG_LOCATION, [&](const RpcResult& result) {
if (result.status.ok()) return true;
EXPECT_EQ(result.status.error_code(), StatusCode::UNAVAILABLE);
EXPECT_THAT(result.status.error_message(),
::testing::MatchesRegex(kErrorMessage));
return false;
});
// Shut down backend. This triggers a connectivity state update from the
// deactivated child of the weighted_target policy.
ShutdownAllBackends();
// Now restart the backend.
StartAllBackends();
// Re-add endpoint.
args = EdsResourceArgs({{"locality0", CreateEndpointsForBackends()}});
balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
// RPCs should eventually succeed.
WaitForAllBackends(DEBUG_LOCATION, 0, 1, [&](const RpcResult& result) {
if (!result.status.ok()) {
EXPECT_EQ(result.status.error_code(), StatusCode::UNAVAILABLE);
EXPECT_THAT(result.status.error_message(),
::testing::MatchesRegex(kErrorMessage));
}
});
}

TEST_P(EdsTest, NoLocalities) {
CreateAndStartBackends(1);
// Initial EDS resource has no localities.
Expand Down

0 comments on commit c11153c

Please sign in to comment.