|
|
|
@ -26,6 +26,8 @@ |
|
|
|
|
#include <algorithm> |
|
|
|
|
#include <cstring> |
|
|
|
|
|
|
|
|
|
#include "absl/strings/str_format.h" |
|
|
|
|
|
|
|
|
|
#include <grpc/support/alloc.h> |
|
|
|
|
#include <grpc/support/string_util.h> |
|
|
|
|
|
|
|
|
@ -325,7 +327,8 @@ class Subchannel::ConnectedSubchannelStateWatcher |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
void OnConnectivityStateChange(grpc_connectivity_state new_state) override { |
|
|
|
|
void OnConnectivityStateChange(grpc_connectivity_state new_state, |
|
|
|
|
const absl::Status& status) override { |
|
|
|
|
Subchannel* c = subchannel_; |
|
|
|
|
MutexLock lock(&c->mu_); |
|
|
|
|
switch (new_state) { |
|
|
|
@ -343,7 +346,15 @@ class Subchannel::ConnectedSubchannelStateWatcher |
|
|
|
|
if (c->channelz_node() != nullptr) { |
|
|
|
|
c->channelz_node()->SetChildSocket(nullptr); |
|
|
|
|
} |
|
|
|
|
c->SetConnectivityStateLocked(GRPC_CHANNEL_TRANSIENT_FAILURE); |
|
|
|
|
// We need to construct our own status if the underlying state was
|
|
|
|
|
// shutdown since the accompanying status will be StatusCode::OK
|
|
|
|
|
// otherwise.
|
|
|
|
|
c->SetConnectivityStateLocked( |
|
|
|
|
GRPC_CHANNEL_TRANSIENT_FAILURE, |
|
|
|
|
new_state == GRPC_CHANNEL_SHUTDOWN |
|
|
|
|
? absl::Status(absl::StatusCode::kUnavailable, |
|
|
|
|
"Subchannel has disconnected.") |
|
|
|
|
: status); |
|
|
|
|
c->backoff_begun_ = false; |
|
|
|
|
c->backoff_.Reset(); |
|
|
|
|
} |
|
|
|
@ -354,7 +365,7 @@ class Subchannel::ConnectedSubchannelStateWatcher |
|
|
|
|
// a callback for READY, because that was the state we started
|
|
|
|
|
// this watch from. And a connected subchannel should never go
|
|
|
|
|
// from READY to CONNECTING or IDLE.
|
|
|
|
|
c->SetConnectivityStateLocked(new_state); |
|
|
|
|
c->SetConnectivityStateLocked(new_state, status); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -368,14 +379,15 @@ class Subchannel::AsyncWatcherNotifierLocked { |
|
|
|
|
public: |
|
|
|
|
AsyncWatcherNotifierLocked( |
|
|
|
|
RefCountedPtr<Subchannel::ConnectivityStateWatcherInterface> watcher, |
|
|
|
|
Subchannel* subchannel, grpc_connectivity_state state) |
|
|
|
|
Subchannel* subchannel, grpc_connectivity_state state, |
|
|
|
|
const absl::Status& status) |
|
|
|
|
: watcher_(std::move(watcher)) { |
|
|
|
|
RefCountedPtr<ConnectedSubchannel> connected_subchannel; |
|
|
|
|
if (state == GRPC_CHANNEL_READY) { |
|
|
|
|
connected_subchannel = subchannel->connected_subchannel_; |
|
|
|
|
} |
|
|
|
|
watcher_->PushConnectivityStateChange( |
|
|
|
|
{state, std::move(connected_subchannel)}); |
|
|
|
|
{state, status, std::move(connected_subchannel)}); |
|
|
|
|
ExecCtx::Run( |
|
|
|
|
DEBUG_LOCATION, |
|
|
|
|
GRPC_CLOSURE_INIT(&closure_, |
|
|
|
@ -409,9 +421,10 @@ void Subchannel::ConnectivityStateWatcherList::RemoveWatcherLocked( |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Subchannel::ConnectivityStateWatcherList::NotifyLocked( |
|
|
|
|
Subchannel* subchannel, grpc_connectivity_state state) { |
|
|
|
|
Subchannel* subchannel, grpc_connectivity_state state, |
|
|
|
|
const absl::Status& status) { |
|
|
|
|
for (const auto& p : watchers_) { |
|
|
|
|
new AsyncWatcherNotifierLocked(p.second, subchannel, state); |
|
|
|
|
new AsyncWatcherNotifierLocked(p.second, subchannel, state, status); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -450,7 +463,7 @@ class Subchannel::HealthWatcherMap::HealthWatcher |
|
|
|
|
grpc_connectivity_state initial_state, |
|
|
|
|
RefCountedPtr<Subchannel::ConnectivityStateWatcherInterface> watcher) { |
|
|
|
|
if (state_ != initial_state) { |
|
|
|
|
new AsyncWatcherNotifierLocked(watcher, subchannel_, state_); |
|
|
|
|
new AsyncWatcherNotifierLocked(watcher, subchannel_, state_, status_); |
|
|
|
|
} |
|
|
|
|
watcher_list_.AddWatcherLocked(std::move(watcher)); |
|
|
|
|
} |
|
|
|
@ -462,7 +475,7 @@ class Subchannel::HealthWatcherMap::HealthWatcher |
|
|
|
|
|
|
|
|
|
bool HasWatchers() const { return !watcher_list_.empty(); } |
|
|
|
|
|
|
|
|
|
void NotifyLocked(grpc_connectivity_state state) { |
|
|
|
|
void NotifyLocked(grpc_connectivity_state state, const absl::Status& status) { |
|
|
|
|
if (state == GRPC_CHANNEL_READY) { |
|
|
|
|
// If we had not already notified for CONNECTING state, do so now.
|
|
|
|
|
// (We may have missed this earlier, because if the transition
|
|
|
|
@ -470,13 +483,15 @@ class Subchannel::HealthWatcherMap::HealthWatcher |
|
|
|
|
// subchannel may not have sent us a notification for CONNECTING.)
|
|
|
|
|
if (state_ != GRPC_CHANNEL_CONNECTING) { |
|
|
|
|
state_ = GRPC_CHANNEL_CONNECTING; |
|
|
|
|
watcher_list_.NotifyLocked(subchannel_, state_); |
|
|
|
|
status_ = status; |
|
|
|
|
watcher_list_.NotifyLocked(subchannel_, state_, status); |
|
|
|
|
} |
|
|
|
|
// If we've become connected, start health checking.
|
|
|
|
|
StartHealthCheckingLocked(); |
|
|
|
|
} else { |
|
|
|
|
state_ = state; |
|
|
|
|
watcher_list_.NotifyLocked(subchannel_, state_); |
|
|
|
|
status_ = status; |
|
|
|
|
watcher_list_.NotifyLocked(subchannel_, state_, status); |
|
|
|
|
// We're not connected, so stop health checking.
|
|
|
|
|
health_check_client_.reset(); |
|
|
|
|
} |
|
|
|
@ -489,11 +504,13 @@ class Subchannel::HealthWatcherMap::HealthWatcher |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
void OnConnectivityStateChange(grpc_connectivity_state new_state) override { |
|
|
|
|
void OnConnectivityStateChange(grpc_connectivity_state new_state, |
|
|
|
|
const absl::Status& status) override { |
|
|
|
|
MutexLock lock(&subchannel_->mu_); |
|
|
|
|
if (new_state != GRPC_CHANNEL_SHUTDOWN && health_check_client_ != nullptr) { |
|
|
|
|
state_ = new_state; |
|
|
|
|
watcher_list_.NotifyLocked(subchannel_, new_state); |
|
|
|
|
status_ = status; |
|
|
|
|
watcher_list_.NotifyLocked(subchannel_, new_state, status); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -508,6 +525,7 @@ class Subchannel::HealthWatcherMap::HealthWatcher |
|
|
|
|
grpc_core::UniquePtr<char> health_check_service_name_; |
|
|
|
|
OrphanablePtr<HealthCheckClient> health_check_client_; |
|
|
|
|
grpc_connectivity_state state_; |
|
|
|
|
absl::Status status_; |
|
|
|
|
ConnectivityStateWatcherList watcher_list_; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -547,9 +565,10 @@ void Subchannel::HealthWatcherMap::RemoveWatcherLocked( |
|
|
|
|
if (!it->second->HasWatchers()) map_.erase(it); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Subchannel::HealthWatcherMap::NotifyLocked(grpc_connectivity_state state) { |
|
|
|
|
void Subchannel::HealthWatcherMap::NotifyLocked(grpc_connectivity_state state, |
|
|
|
|
const absl::Status& status) { |
|
|
|
|
for (const auto& p : map_) { |
|
|
|
|
p.second->NotifyLocked(state); |
|
|
|
|
p.second->NotifyLocked(state, status); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -826,7 +845,7 @@ void Subchannel::WatchConnectivityState( |
|
|
|
|
} |
|
|
|
|
if (health_check_service_name == nullptr) { |
|
|
|
|
if (state_ != initial_state) { |
|
|
|
|
new AsyncWatcherNotifierLocked(watcher, this, state_); |
|
|
|
|
new AsyncWatcherNotifierLocked(watcher, this, state_, status_); |
|
|
|
|
} |
|
|
|
|
watcher_list_.AddWatcherLocked(std::move(watcher)); |
|
|
|
|
} else { |
|
|
|
@ -928,8 +947,10 @@ const char* SubchannelConnectivityStateChangeString( |
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
// Note: Must be called with a state that is different from the current state.
|
|
|
|
|
void Subchannel::SetConnectivityStateLocked(grpc_connectivity_state state) { |
|
|
|
|
void Subchannel::SetConnectivityStateLocked(grpc_connectivity_state state, |
|
|
|
|
const absl::Status& status) { |
|
|
|
|
state_ = state; |
|
|
|
|
status_ = status; |
|
|
|
|
if (channelz_node_ != nullptr) { |
|
|
|
|
channelz_node_->UpdateConnectivityState(state); |
|
|
|
|
channelz_node_->AddTraceEvent( |
|
|
|
@ -938,9 +959,9 @@ void Subchannel::SetConnectivityStateLocked(grpc_connectivity_state state) { |
|
|
|
|
SubchannelConnectivityStateChangeString(state))); |
|
|
|
|
} |
|
|
|
|
// Notify non-health watchers.
|
|
|
|
|
watcher_list_.NotifyLocked(this, state); |
|
|
|
|
watcher_list_.NotifyLocked(this, state, status); |
|
|
|
|
// Notify health watchers.
|
|
|
|
|
health_watcher_map_.NotifyLocked(state); |
|
|
|
|
health_watcher_map_.NotifyLocked(state, status); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Subchannel::MaybeStartConnectingLocked() { |
|
|
|
@ -1012,7 +1033,7 @@ void Subchannel::ContinueConnectingLocked() { |
|
|
|
|
next_attempt_deadline_ = backoff_.NextAttemptTime(); |
|
|
|
|
args.deadline = std::max(next_attempt_deadline_, min_deadline); |
|
|
|
|
args.channel_args = args_; |
|
|
|
|
SetConnectivityStateLocked(GRPC_CHANNEL_CONNECTING); |
|
|
|
|
SetConnectivityStateLocked(GRPC_CHANNEL_CONNECTING, absl::Status()); |
|
|
|
|
connector_->Connect(args, &connecting_result_, &on_connecting_finished_); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1031,7 +1052,8 @@ void Subchannel::OnConnectingFinished(void* arg, grpc_error* error) { |
|
|
|
|
GRPC_SUBCHANNEL_WEAK_UNREF(c, "connecting"); |
|
|
|
|
} else { |
|
|
|
|
gpr_log(GPR_INFO, "Connect failed: %s", grpc_error_string(error)); |
|
|
|
|
c->SetConnectivityStateLocked(GRPC_CHANNEL_TRANSIENT_FAILURE); |
|
|
|
|
c->SetConnectivityStateLocked(GRPC_CHANNEL_TRANSIENT_FAILURE, |
|
|
|
|
grpc_error_to_absl_status(error)); |
|
|
|
|
GRPC_SUBCHANNEL_WEAK_UNREF(c, "connecting"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1091,7 +1113,7 @@ bool Subchannel::PublishTransportLocked() { |
|
|
|
|
connected_subchannel_->StartWatch( |
|
|
|
|
pollset_set_, MakeOrphanable<ConnectedSubchannelStateWatcher>(this)); |
|
|
|
|
// Report initial state.
|
|
|
|
|
SetConnectivityStateLocked(GRPC_CHANNEL_READY); |
|
|
|
|
SetConnectivityStateLocked(GRPC_CHANNEL_READY, absl::Status()); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|