|
|
|
@ -65,6 +65,36 @@ |
|
|
|
|
|
|
|
|
|
namespace grpc_core { |
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// ResolvingLoadBalancingPolicy::ResolverResultHandler
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
class ResolvingLoadBalancingPolicy::ResolverResultHandler |
|
|
|
|
: public Resolver::ResultHandler { |
|
|
|
|
public: |
|
|
|
|
explicit ResolverResultHandler( |
|
|
|
|
RefCountedPtr<ResolvingLoadBalancingPolicy> parent) |
|
|
|
|
: parent_(std::move(parent)) {} |
|
|
|
|
|
|
|
|
|
~ResolverResultHandler() { |
|
|
|
|
if (parent_->tracer_->enabled()) { |
|
|
|
|
gpr_log(GPR_INFO, "resolving_lb=%p: resolver shutdown complete", |
|
|
|
|
parent_.get()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ReturnResult(const grpc_channel_args* result) override { |
|
|
|
|
parent_->OnResolverResultChangedLocked(result); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ReturnError(grpc_error* error) override { |
|
|
|
|
parent_->OnResolverError(error); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
RefCountedPtr<ResolvingLoadBalancingPolicy> parent_; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// ResolvingLoadBalancingPolicy::ResolvingControlHelper
|
|
|
|
|
//
|
|
|
|
@ -196,12 +226,9 @@ ResolvingLoadBalancingPolicy::ResolvingLoadBalancingPolicy( |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_error* ResolvingLoadBalancingPolicy::Init(const grpc_channel_args& args) { |
|
|
|
|
GRPC_CLOSURE_INIT( |
|
|
|
|
&on_resolver_result_changed_, |
|
|
|
|
&ResolvingLoadBalancingPolicy::OnResolverResultChangedLocked, this, |
|
|
|
|
grpc_combiner_scheduler(combiner())); |
|
|
|
|
resolver_ = ResolverRegistry::CreateResolver( |
|
|
|
|
target_uri_.get(), &args, interested_parties(), combiner()); |
|
|
|
|
target_uri_.get(), &args, interested_parties(), combiner(), |
|
|
|
|
UniquePtr<Resolver::ResultHandler>(New<ResolverResultHandler>(Ref()))); |
|
|
|
|
if (resolver_ == nullptr) { |
|
|
|
|
return GRPC_ERROR_CREATE_FROM_STATIC_STRING("resolver creation failed"); |
|
|
|
|
} |
|
|
|
@ -288,62 +315,34 @@ void ResolvingLoadBalancingPolicy::StartResolvingLocked() { |
|
|
|
|
channel_control_helper()->UpdateState( |
|
|
|
|
GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE, |
|
|
|
|
UniquePtr<SubchannelPicker>(New<QueuePicker>(Ref()))); |
|
|
|
|
Ref().release(); |
|
|
|
|
resolver_->NextLocked(&resolver_result_, &on_resolver_result_changed_); |
|
|
|
|
resolver_->StartLocked(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Invoked from the resolver NextLocked() callback when the resolver
|
|
|
|
|
// is shutting down.
|
|
|
|
|
void ResolvingLoadBalancingPolicy::OnResolverShutdownLocked(grpc_error* error) { |
|
|
|
|
if (tracer_->enabled()) { |
|
|
|
|
gpr_log(GPR_INFO, "resolving_lb=%p: shutting down", this); |
|
|
|
|
void ResolvingLoadBalancingPolicy::OnResolverError(grpc_error* error) { |
|
|
|
|
if (resolver_ == nullptr) { |
|
|
|
|
GRPC_ERROR_UNREF(error); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
{ |
|
|
|
|
MutexLock lock(&lb_policy_mu_); |
|
|
|
|
if (lb_policy_ != nullptr) { |
|
|
|
|
if (tracer_->enabled()) { |
|
|
|
|
gpr_log(GPR_INFO, "resolving_lb=%p: shutting down lb_policy=%p", this, |
|
|
|
|
lb_policy_.get()); |
|
|
|
|
} |
|
|
|
|
grpc_pollset_set_del_pollset_set(lb_policy_->interested_parties(), |
|
|
|
|
interested_parties()); |
|
|
|
|
lb_policy_.reset(); |
|
|
|
|
} |
|
|
|
|
if (pending_lb_policy_ != nullptr) { |
|
|
|
|
if (tracer_->enabled()) { |
|
|
|
|
gpr_log(GPR_INFO, "resolving_lb=%p: shutting down pending lb_policy=%p", |
|
|
|
|
this, pending_lb_policy_.get()); |
|
|
|
|
} |
|
|
|
|
grpc_pollset_set_del_pollset_set(pending_lb_policy_->interested_parties(), |
|
|
|
|
interested_parties()); |
|
|
|
|
pending_lb_policy_.reset(); |
|
|
|
|
} |
|
|
|
|
if (tracer_->enabled()) { |
|
|
|
|
gpr_log(GPR_INFO, "resolving_lb=%p: resolver transient failure: %s", this, |
|
|
|
|
grpc_error_string(error)); |
|
|
|
|
} |
|
|
|
|
if (resolver_ != nullptr) { |
|
|
|
|
// This should never happen; it can only be triggered by a resolver
|
|
|
|
|
// implementation spotaneously deciding to report shutdown without
|
|
|
|
|
// being orphaned. This code is included just to be defensive.
|
|
|
|
|
if (tracer_->enabled()) { |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"resolving_lb=%p: spontaneous shutdown from resolver %p", this, |
|
|
|
|
resolver_.get()); |
|
|
|
|
} |
|
|
|
|
resolver_.reset(); |
|
|
|
|
grpc_error* error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( |
|
|
|
|
"Resolver spontaneous shutdown", &error, 1); |
|
|
|
|
// If we already have an LB policy from a previous resolution
|
|
|
|
|
// result, then we continue to let it set the connectivity state.
|
|
|
|
|
// Otherwise, we go into TRANSIENT_FAILURE.
|
|
|
|
|
if (lb_policy_ == nullptr) { |
|
|
|
|
grpc_error* state_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( |
|
|
|
|
"Resolver transient failure", &error, 1); |
|
|
|
|
channel_control_helper()->UpdateState( |
|
|
|
|
GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_REF(error), |
|
|
|
|
UniquePtr<SubchannelPicker>(New<TransientFailurePicker>(error))); |
|
|
|
|
GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(state_error), |
|
|
|
|
UniquePtr<SubchannelPicker>(New<TransientFailurePicker>(state_error))); |
|
|
|
|
} |
|
|
|
|
grpc_channel_args_destroy(resolver_result_); |
|
|
|
|
resolver_result_ = nullptr; |
|
|
|
|
GRPC_ERROR_UNREF(error); |
|
|
|
|
Unref(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ResolvingLoadBalancingPolicy::CreateOrUpdateLbPolicyLocked( |
|
|
|
|
const char* lb_policy_name, RefCountedPtr<Config> lb_policy_config, |
|
|
|
|
TraceStringVector* trace_strings) { |
|
|
|
|
const grpc_channel_args& args, TraceStringVector* trace_strings) { |
|
|
|
|
// If the child policy name changes, we need to create a new child
|
|
|
|
|
// policy. When this happens, we leave child_policy_ as-is and store
|
|
|
|
|
// the new child policy in pending_child_policy_. Once the new child
|
|
|
|
@ -411,7 +410,7 @@ void ResolvingLoadBalancingPolicy::CreateOrUpdateLbPolicyLocked( |
|
|
|
|
gpr_log(GPR_INFO, "resolving_lb=%p: Creating new %schild policy %s", this, |
|
|
|
|
lb_policy_ == nullptr ? "" : "pending ", lb_policy_name); |
|
|
|
|
} |
|
|
|
|
auto new_policy = CreateLbPolicyLocked(lb_policy_name, trace_strings); |
|
|
|
|
auto new_policy = CreateLbPolicyLocked(lb_policy_name, args, trace_strings); |
|
|
|
|
auto& lb_policy = lb_policy_ == nullptr ? lb_policy_ : pending_lb_policy_; |
|
|
|
|
{ |
|
|
|
|
MutexLock lock(&lb_policy_mu_); |
|
|
|
@ -432,21 +431,21 @@ void ResolvingLoadBalancingPolicy::CreateOrUpdateLbPolicyLocked( |
|
|
|
|
policy_to_update == pending_lb_policy_.get() ? "pending " : "", |
|
|
|
|
policy_to_update); |
|
|
|
|
} |
|
|
|
|
policy_to_update->UpdateLocked(*resolver_result_, |
|
|
|
|
std::move(lb_policy_config)); |
|
|
|
|
policy_to_update->UpdateLocked(args, std::move(lb_policy_config)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Creates a new LB policy.
|
|
|
|
|
// Updates trace_strings to indicate what was done.
|
|
|
|
|
OrphanablePtr<LoadBalancingPolicy> |
|
|
|
|
ResolvingLoadBalancingPolicy::CreateLbPolicyLocked( |
|
|
|
|
const char* lb_policy_name, TraceStringVector* trace_strings) { |
|
|
|
|
const char* lb_policy_name, const grpc_channel_args& args, |
|
|
|
|
TraceStringVector* trace_strings) { |
|
|
|
|
ResolvingControlHelper* helper = New<ResolvingControlHelper>(Ref()); |
|
|
|
|
LoadBalancingPolicy::Args lb_policy_args; |
|
|
|
|
lb_policy_args.combiner = combiner(); |
|
|
|
|
lb_policy_args.channel_control_helper = |
|
|
|
|
UniquePtr<ChannelControlHelper>(helper); |
|
|
|
|
lb_policy_args.args = resolver_result_; |
|
|
|
|
lb_policy_args.args = &args; |
|
|
|
|
OrphanablePtr<LoadBalancingPolicy> lb_policy = |
|
|
|
|
LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy( |
|
|
|
|
lb_policy_name, std::move(lb_policy_args)); |
|
|
|
@ -480,9 +479,10 @@ ResolvingLoadBalancingPolicy::CreateLbPolicyLocked( |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ResolvingLoadBalancingPolicy::MaybeAddTraceMessagesForAddressChangesLocked( |
|
|
|
|
const grpc_channel_args& resolver_result, |
|
|
|
|
TraceStringVector* trace_strings) { |
|
|
|
|
const ServerAddressList* addresses = |
|
|
|
|
FindServerAddressListChannelArg(resolver_result_); |
|
|
|
|
FindServerAddressListChannelArg(&resolver_result); |
|
|
|
|
const bool resolution_contains_addresses = |
|
|
|
|
addresses != nullptr && addresses->size() > 0; |
|
|
|
|
if (!resolution_contains_addresses && |
|
|
|
@ -516,27 +516,16 @@ void ResolvingLoadBalancingPolicy::ConcatenateAndAddChannelTraceLocked( |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Callback invoked when a resolver result is available.
|
|
|
|
|
void ResolvingLoadBalancingPolicy::OnResolverResultChangedLocked( |
|
|
|
|
void* arg, grpc_error* error) { |
|
|
|
|
auto* self = static_cast<ResolvingLoadBalancingPolicy*>(arg); |
|
|
|
|
if (self->tracer_->enabled()) { |
|
|
|
|
const char* disposition = |
|
|
|
|
self->resolver_result_ != nullptr |
|
|
|
|
? "" |
|
|
|
|
: (error == GRPC_ERROR_NONE ? " (transient error)" |
|
|
|
|
: " (resolver shutdown)"); |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"resolving_lb=%p: got resolver result: resolver_result=%p " |
|
|
|
|
"error=%s%s", |
|
|
|
|
self, self->resolver_result_, grpc_error_string(error), |
|
|
|
|
disposition); |
|
|
|
|
} |
|
|
|
|
// Handle shutdown.
|
|
|
|
|
if (error != GRPC_ERROR_NONE || self->resolver_ == nullptr) { |
|
|
|
|
self->OnResolverShutdownLocked(GRPC_ERROR_REF(error)); |
|
|
|
|
const grpc_channel_args* result) { |
|
|
|
|
// Handle race conditions.
|
|
|
|
|
if (resolver_ == nullptr) { |
|
|
|
|
grpc_channel_args_destroy(result); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (tracer_->enabled()) { |
|
|
|
|
gpr_log(GPR_INFO, "resolving_lb=%p: got resolver result %p", this, result); |
|
|
|
|
} |
|
|
|
|
// We only want to trace the address resolution in the follow cases:
|
|
|
|
|
// (a) Address resolution resulted in service config change.
|
|
|
|
|
// (b) Address resolution that causes number of backends to go from
|
|
|
|
@ -547,63 +536,34 @@ void ResolvingLoadBalancingPolicy::OnResolverResultChangedLocked( |
|
|
|
|
//
|
|
|
|
|
// we track a list of strings to eventually be concatenated and traced.
|
|
|
|
|
TraceStringVector trace_strings; |
|
|
|
|
// resolver_result_ will be null in the case of a transient
|
|
|
|
|
// resolution error. In that case, we don't have any new result to
|
|
|
|
|
// process, which means that we keep using the previous result (if any).
|
|
|
|
|
if (self->resolver_result_ == nullptr) { |
|
|
|
|
if (self->tracer_->enabled()) { |
|
|
|
|
gpr_log(GPR_INFO, "resolving_lb=%p: resolver transient failure", self); |
|
|
|
|
} |
|
|
|
|
// If we already have an LB policy from a previous resolution
|
|
|
|
|
// result, then we continue to let it set the connectivity state.
|
|
|
|
|
// Otherwise, we go into TRANSIENT_FAILURE.
|
|
|
|
|
if (self->lb_policy_ == nullptr) { |
|
|
|
|
// TODO(roth): When we change the resolver API to be able to
|
|
|
|
|
// return transient errors in a cleaner way, we should make it the
|
|
|
|
|
// resolver's responsibility to attach a status to the error,
|
|
|
|
|
// rather than doing it centrally here.
|
|
|
|
|
grpc_error* state_error = grpc_error_set_int( |
|
|
|
|
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( |
|
|
|
|
"Resolver transient failure", &error, 1), |
|
|
|
|
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE); |
|
|
|
|
self->channel_control_helper()->UpdateState( |
|
|
|
|
GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(state_error), |
|
|
|
|
UniquePtr<SubchannelPicker>( |
|
|
|
|
New<TransientFailurePicker>(state_error))); |
|
|
|
|
} |
|
|
|
|
// Parse the resolver result.
|
|
|
|
|
const char* lb_policy_name = nullptr; |
|
|
|
|
RefCountedPtr<Config> lb_policy_config; |
|
|
|
|
bool service_config_changed = false; |
|
|
|
|
if (process_resolver_result_ != nullptr) { |
|
|
|
|
service_config_changed = |
|
|
|
|
process_resolver_result_(process_resolver_result_user_data_, *result, |
|
|
|
|
&lb_policy_name, &lb_policy_config); |
|
|
|
|
} else { |
|
|
|
|
// Parse the resolver result.
|
|
|
|
|
const char* lb_policy_name = nullptr; |
|
|
|
|
RefCountedPtr<Config> lb_policy_config; |
|
|
|
|
bool service_config_changed = false; |
|
|
|
|
if (self->process_resolver_result_ != nullptr) { |
|
|
|
|
service_config_changed = self->process_resolver_result_( |
|
|
|
|
self->process_resolver_result_user_data_, *self->resolver_result_, |
|
|
|
|
&lb_policy_name, &lb_policy_config); |
|
|
|
|
} else { |
|
|
|
|
lb_policy_name = self->child_policy_name_.get(); |
|
|
|
|
lb_policy_config = self->child_lb_config_; |
|
|
|
|
} |
|
|
|
|
GPR_ASSERT(lb_policy_name != nullptr); |
|
|
|
|
self->CreateOrUpdateLbPolicyLocked( |
|
|
|
|
lb_policy_name, std::move(lb_policy_config), &trace_strings); |
|
|
|
|
// Add channel trace event.
|
|
|
|
|
if (self->channelz_node() != nullptr) { |
|
|
|
|
if (service_config_changed) { |
|
|
|
|
// TODO(ncteisen): might be worth somehow including a snippet of the
|
|
|
|
|
// config in the trace, at the risk of bloating the trace logs.
|
|
|
|
|
trace_strings.push_back(gpr_strdup("Service config changed")); |
|
|
|
|
} |
|
|
|
|
self->MaybeAddTraceMessagesForAddressChangesLocked(&trace_strings); |
|
|
|
|
self->ConcatenateAndAddChannelTraceLocked(&trace_strings); |
|
|
|
|
lb_policy_name = child_policy_name_.get(); |
|
|
|
|
lb_policy_config = child_lb_config_; |
|
|
|
|
} |
|
|
|
|
GPR_ASSERT(lb_policy_name != nullptr); |
|
|
|
|
// Create or update LB policy, as needed.
|
|
|
|
|
CreateOrUpdateLbPolicyLocked(lb_policy_name, std::move(lb_policy_config), |
|
|
|
|
*result, &trace_strings); |
|
|
|
|
// Add channel trace event.
|
|
|
|
|
if (channelz_node() != nullptr) { |
|
|
|
|
if (service_config_changed) { |
|
|
|
|
// TODO(ncteisen): might be worth somehow including a snippet of the
|
|
|
|
|
// config in the trace, at the risk of bloating the trace logs.
|
|
|
|
|
trace_strings.push_back(gpr_strdup("Service config changed")); |
|
|
|
|
} |
|
|
|
|
// Clean up.
|
|
|
|
|
grpc_channel_args_destroy(self->resolver_result_); |
|
|
|
|
self->resolver_result_ = nullptr; |
|
|
|
|
MaybeAddTraceMessagesForAddressChangesLocked(*result, &trace_strings); |
|
|
|
|
ConcatenateAndAddChannelTraceLocked(&trace_strings); |
|
|
|
|
} |
|
|
|
|
// Renew resolver callback.
|
|
|
|
|
self->resolver_->NextLocked(&self->resolver_result_, |
|
|
|
|
&self->on_resolver_result_changed_); |
|
|
|
|
// Clean up.
|
|
|
|
|
grpc_channel_args_destroy(result); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} // namespace grpc_core
|
|
|
|
|