|
|
@@ -116,6 +116,7 @@ class SubchannelData {
|
|
|
grpc_error* error = GRPC_ERROR_NONE;
|
|
|
pending_connectivity_state_unsafe_ =
|
|
|
grpc_subchannel_check_connectivity(subchannel(), &error);
|
|
|
+ UpdateConnectedSubchannelLocked();
|
|
|
if (pending_connectivity_state_unsafe_ != curr_connectivity_state_) {
|
|
|
curr_connectivity_state_ = pending_connectivity_state_unsafe_;
|
|
|
ProcessConnectivityChangeLocked(error);
|
|
|
@@ -167,6 +168,9 @@ class SubchannelData {
|
|
|
virtual void ProcessConnectivityChangeLocked(grpc_error* error) GRPC_ABSTRACT;
|
|
|
|
|
|
private:
|
|
|
+// FIXME: document
|
|
|
+ bool UpdateConnectedSubchannelLocked();
|
|
|
+
|
|
|
static void OnConnectivityChangedLocked(void* arg, grpc_error* error);
|
|
|
|
|
|
// Backpointer to owning subchannel list. Not owned.
|
|
|
@@ -346,33 +350,47 @@ void SubchannelData<SubchannelListType, SubchannelDataType>::
|
|
|
}
|
|
|
|
|
|
template <typename SubchannelListType, typename SubchannelDataType>
|
|
|
-void SubchannelData<SubchannelListType, SubchannelDataType>::
|
|
|
- OnConnectivityChangedLocked(void* arg, grpc_error* error) {
|
|
|
- SubchannelData* sd = static_cast<SubchannelData*>(arg);
|
|
|
+bool SubchannelData<SubchannelListType, SubchannelDataType>::
|
|
|
+ UpdateConnectedSubchannelLocked() {
|
|
|
// FIXME: add trace logging
|
|
|
// If the subchannel is READY, get a ref to the connected subchannel.
|
|
|
- if (sd->pending_connectivity_state_unsafe_ == GRPC_CHANNEL_READY) {
|
|
|
- sd->connected_subchannel_ =
|
|
|
- grpc_subchannel_get_connected_subchannel(sd->subchannel_);
|
|
|
- // If the subchannel became disconnected between the time that this
|
|
|
- // callback was scheduled and the time that it was actually run in the
|
|
|
- // combiner, then the connected subchannel may have disappeared out from
|
|
|
- // under us. In that case, instead of propagating the READY notification,
|
|
|
- // we simply renew our watch and wait for the next notification.
|
|
|
- // Note that we start the renewed watch from IDLE to make sure we
|
|
|
- // get a notification for the next state, even if that state is
|
|
|
- // READY again (e.g., if the subchannel has transitioned back to
|
|
|
- // READY before the callback gets scheduled).
|
|
|
- if (sd->connected_subchannel_ == nullptr) {
|
|
|
- sd->pending_connectivity_state_unsafe_ = GRPC_CHANNEL_IDLE;
|
|
|
- sd->StartConnectivityWatchLocked();
|
|
|
- return;
|
|
|
+ if (pending_connectivity_state_unsafe_ == GRPC_CHANNEL_READY) {
|
|
|
+ connected_subchannel_ =
|
|
|
+ grpc_subchannel_get_connected_subchannel(subchannel_);
|
|
|
+ // If the subchannel became disconnected between the time that READY
|
|
|
+ // was reported and the time we got here (e.g., between when a
|
|
|
+ // notification callback is scheduled and when it was actually run in
|
|
|
+ // the combiner), then the connected subchannel may have disappeared out
|
|
|
+ // from under us. In that case, we don't actually want to consider the
|
|
|
+ // subchannel to be in state READY. Instead, we use IDLE as the
|
|
|
+ // basis for any future connectivity watch; this is the one state that
|
|
|
+ // the subchannel will never transition back into, so this ensures
|
|
|
+ // that we will get a notification for the next state, even if that state
|
|
|
+ // is READY again (e.g., if the subchannel has transitioned back to
|
|
|
+ // READY before the next watch gets requested).
|
|
|
+ if (connected_subchannel_ == nullptr) {
|
|
|
+ pending_connectivity_state_unsafe_ = GRPC_CHANNEL_IDLE;
|
|
|
+ return false;
|
|
|
}
|
|
|
}
|
|
|
+// FIXME: do this for any other state?
|
|
|
// If we get TRANSIENT_FAILURE, unref the connected subchannel.
|
|
|
- else if (sd->pending_connectivity_state_unsafe_ ==
|
|
|
+ else if (pending_connectivity_state_unsafe_ ==
|
|
|
GRPC_CHANNEL_TRANSIENT_FAILURE) {
|
|
|
- sd->connected_subchannel_.reset();
|
|
|
+ connected_subchannel_.reset();
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+template <typename SubchannelListType, typename SubchannelDataType>
|
|
|
+void SubchannelData<SubchannelListType, SubchannelDataType>::
|
|
|
+ OnConnectivityChangedLocked(void* arg, grpc_error* error) {
|
|
|
+ SubchannelData* sd = static_cast<SubchannelData*>(arg);
|
|
|
+// FIXME: add trace logging
|
|
|
+ if (!sd->UpdateConnectedSubchannelLocked()) {
|
|
|
+ // We don't want to report this connectivity state, so renew the watch.
|
|
|
+ sd->StartConnectivityWatchLocked();
|
|
|
+ return;
|
|
|
}
|
|
|
// Now that we're inside the combiner, copy the pending connectivity
|
|
|
// state (which was set by the connectivity state watcher) to
|