|
|
@ -24,6 +24,9 @@ |
|
|
|
|
|
|
|
|
|
|
|
namespace grpc_core { |
|
|
|
namespace grpc_core { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define GRPC_REGISTER_SUBCHANNEL_CALM_DOWN_AFTER_ATTEMPTS 100 |
|
|
|
|
|
|
|
#define GRPC_REGISTER_SUBCHANNEL_CALM_DOWN_MICROS 10 |
|
|
|
|
|
|
|
|
|
|
|
GlobalSubchannelPool::GlobalSubchannelPool() { |
|
|
|
GlobalSubchannelPool::GlobalSubchannelPool() { |
|
|
|
subchannel_map_ = grpc_avl_create(&subchannel_avl_vtable_); |
|
|
|
subchannel_map_ = grpc_avl_create(&subchannel_avl_vtable_); |
|
|
|
gpr_mu_init(&mu_); |
|
|
|
gpr_mu_init(&mu_); |
|
|
@ -58,7 +61,7 @@ Subchannel* GlobalSubchannelPool::RegisterSubchannel(SubchannelKey* key, |
|
|
|
Subchannel* constructed) { |
|
|
|
Subchannel* constructed) { |
|
|
|
Subchannel* c = nullptr; |
|
|
|
Subchannel* c = nullptr; |
|
|
|
// Compare and swap (CAS) loop:
|
|
|
|
// Compare and swap (CAS) loop:
|
|
|
|
while (c == nullptr) { |
|
|
|
for (int attempt_count = 0; c == nullptr; attempt_count++) { |
|
|
|
// Ref the shared map to have a local copy.
|
|
|
|
// Ref the shared map to have a local copy.
|
|
|
|
gpr_mu_lock(&mu_); |
|
|
|
gpr_mu_lock(&mu_); |
|
|
|
grpc_avl old_map = grpc_avl_ref(subchannel_map_, nullptr); |
|
|
|
grpc_avl old_map = grpc_avl_ref(subchannel_map_, nullptr); |
|
|
@ -72,7 +75,24 @@ Subchannel* GlobalSubchannelPool::RegisterSubchannel(SubchannelKey* key, |
|
|
|
GRPC_SUBCHANNEL_UNREF(constructed, |
|
|
|
GRPC_SUBCHANNEL_UNREF(constructed, |
|
|
|
"subchannel_register+found_existing"); |
|
|
|
"subchannel_register+found_existing"); |
|
|
|
// Exit the CAS loop without modifying the shared map.
|
|
|
|
// Exit the CAS loop without modifying the shared map.
|
|
|
|
} // Else, reuse failed, so retry CAS loop.
|
|
|
|
} else { |
|
|
|
|
|
|
|
// Reuse of the subchannel failed, so retry CAS loop
|
|
|
|
|
|
|
|
if (attempt_count >= |
|
|
|
|
|
|
|
GRPC_REGISTER_SUBCHANNEL_CALM_DOWN_AFTER_ATTEMPTS) { |
|
|
|
|
|
|
|
// GRPC_SUBCHANNEL_REF_FROM_WEAK_REF returning nullptr means that the
|
|
|
|
|
|
|
|
// subchannel we got is no longer valid and it's going to be removed
|
|
|
|
|
|
|
|
// from the AVL tree soon. Spinning here excesively here can actually
|
|
|
|
|
|
|
|
// prevent another thread from removing the subchannel, basically
|
|
|
|
|
|
|
|
// resulting in a live lock. See b/157516542 for more details.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// gpr does not support thread yield operation, this is the best we
|
|
|
|
|
|
|
|
// can do.
|
|
|
|
|
|
|
|
gpr_sleep_until(gpr_time_add( |
|
|
|
|
|
|
|
gpr_now(GPR_CLOCK_REALTIME), |
|
|
|
|
|
|
|
gpr_time_from_micros(GRPC_REGISTER_SUBCHANNEL_CALM_DOWN_MICROS, |
|
|
|
|
|
|
|
GPR_TIMESPAN))); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// There hasn't been such subchannel. Add one.
|
|
|
|
// There hasn't been such subchannel. Add one.
|
|
|
|
// Note that we should ref the old map first because grpc_avl_add() will
|
|
|
|
// Note that we should ref the old map first because grpc_avl_add() will
|
|
|
|