Convert client channel connectivity watch code to C++. (#25987)

* Convert client channel connectivity watch code to C++.

* clang-format
pull/26051/head
Mark D. Roth 4 years ago committed by GitHub
parent 61b239848a
commit efe3c991e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 285
      src/core/ext/filters/client_channel/channel_connectivity.cc

@ -1,28 +1,23 @@
/* //
* // Copyright 2015 gRPC authors.
* Copyright 2015 gRPC authors. //
* // Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License. // You may obtain a copy of the License at
* You may obtain a copy of the License at //
* // http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0 //
* // Unless required by applicable law or agreed to in writing, software
* Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS,
* distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and
* See the License for the specific language governing permissions and // limitations under the License.
* limitations under the License. //
*
*/
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
#include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/channel.h"
#include <inttypes.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include "src/core/ext/filters/client_channel/client_channel.h" #include "src/core/ext/filters/client_channel/client_channel.h"
@ -49,73 +44,108 @@ grpc_connectivity_state grpc_channel_check_connectivity_state(
return client_channel->CheckConnectivityState(try_to_connect); return client_channel->CheckConnectivityState(try_to_connect);
} }
typedef enum { int grpc_channel_num_external_connectivity_watchers(grpc_channel* channel) {
WAITING, grpc_core::ClientChannel* client_channel =
READY_TO_CALL_BACK, grpc_core::ClientChannel::GetFromChannel(channel);
CALLING_BACK_AND_FINISHED, if (client_channel == nullptr) {
} callback_phase; gpr_log(GPR_ERROR,
"grpc_channel_num_external_connectivity_watchers called on "
"something that is not a client channel");
return 0;
}
return client_channel->NumExternalConnectivityWatchers();
}
int grpc_channel_support_connectivity_watcher(grpc_channel* channel) {
return grpc_core::ClientChannel::GetFromChannel(channel) != nullptr;
}
namespace grpc_core {
namespace { namespace {
struct state_watcher {
gpr_mu mu;
callback_phase phase;
grpc_closure on_complete;
grpc_closure on_timeout;
grpc_closure watcher_timer_init;
grpc_timer alarm;
grpc_connectivity_state state;
grpc_completion_queue* cq;
grpc_cq_completion completion_storage;
grpc_channel* channel;
grpc_error* error;
void* tag;
};
} // namespace
static void delete_state_watcher(state_watcher* w) { class StateWatcher {
GRPC_CHANNEL_INTERNAL_UNREF(w->channel, "watch_channel_connectivity"); public:
gpr_mu_destroy(&w->mu); StateWatcher(grpc_channel* channel, grpc_completion_queue* cq, void* tag,
gpr_free(w); grpc_connectivity_state last_observed_state,
} gpr_timespec deadline)
: channel_(channel), cq_(cq), tag_(tag), state_(last_observed_state) {
GPR_ASSERT(grpc_cq_begin_op(cq, tag));
GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity");
GRPC_CLOSURE_INIT(&on_complete_, WatchComplete, this, nullptr);
GRPC_CLOSURE_INIT(&on_timeout_, TimeoutComplete, this, nullptr);
auto* watcher_timer_init_state = new WatcherTimerInitState(
this, grpc_timespec_to_millis_round_up(deadline));
ClientChannel* client_channel = ClientChannel::GetFromChannel(channel);
GPR_ASSERT(client_channel != nullptr);
client_channel->AddExternalConnectivityWatcher(
grpc_polling_entity_create_from_pollset(grpc_cq_pollset(cq)), &state_,
&on_complete_, watcher_timer_init_state->closure());
}
~StateWatcher() {
GRPC_CHANNEL_INTERNAL_UNREF(channel_, "watch_channel_connectivity");
}
private:
// A fire-and-forget object used to delay starting the timer until the
// ClientChannel actually starts the watch.
class WatcherTimerInitState {
public:
WatcherTimerInitState(StateWatcher* state_watcher, grpc_millis deadline)
: state_watcher_(state_watcher), deadline_(deadline) {
GRPC_CLOSURE_INIT(&closure_, WatcherTimerInit, this, nullptr);
}
static void finished_completion(void* pw, grpc_cq_completion* /*ignored*/) { grpc_closure* closure() { return &closure_; }
private:
static void WatcherTimerInit(void* arg, grpc_error* /*error*/) {
auto* self = static_cast<WatcherTimerInitState*>(arg);
grpc_timer_init(&self->state_watcher_->timer_, self->deadline_,
&self->state_watcher_->on_timeout_);
delete self;
}
StateWatcher* state_watcher_;
grpc_millis deadline_;
grpc_closure closure_;
};
enum CallbackPhase { kWaiting, kReadyToCallBack, kCallingBackAndFinished };
// Called when the completion is returned to the CQ.
static void FinishedCompletion(void* arg, grpc_cq_completion* /*ignored*/) {
auto* self = static_cast<StateWatcher*>(arg);
bool should_delete = false; bool should_delete = false;
state_watcher* w = static_cast<state_watcher*>(pw); {
gpr_mu_lock(&w->mu); MutexLock lock(&self->mu_);
switch (w->phase) { switch (self->phase_) {
case WAITING: case kWaiting:
case READY_TO_CALL_BACK: case kReadyToCallBack:
GPR_UNREACHABLE_CODE(return ); GPR_UNREACHABLE_CODE(return );
case CALLING_BACK_AND_FINISHED: case kCallingBackAndFinished:
should_delete = true; should_delete = true;
break;
} }
gpr_mu_unlock(&w->mu);
if (should_delete) {
delete_state_watcher(w);
} }
} if (should_delete) delete self;
}
static void partly_done(state_watcher* w, bool due_to_completion, void PartlyDone(bool due_to_completion, grpc_error* error) {
grpc_error* error) {
bool end_op = false; bool end_op = false;
void* end_op_tag = nullptr; void* end_op_tag = nullptr;
grpc_error* end_op_error = nullptr; grpc_error* end_op_error = nullptr;
grpc_completion_queue* end_op_cq = nullptr; grpc_completion_queue* end_op_cq = nullptr;
grpc_cq_completion* end_op_completion_storage = nullptr; grpc_cq_completion* end_op_completion_storage = nullptr;
if (due_to_completion) { if (due_to_completion) {
grpc_timer_cancel(&w->alarm); grpc_timer_cancel(&timer_);
} else { } else {
grpc_core::ClientChannel* client_channel = grpc_core::ClientChannel* client_channel =
grpc_core::ClientChannel::GetFromChannel(w->channel); grpc_core::ClientChannel::GetFromChannel(channel_);
GPR_ASSERT(client_channel != nullptr); GPR_ASSERT(client_channel != nullptr);
client_channel->CancelExternalConnectivityWatcher(&w->on_complete); client_channel->CancelExternalConnectivityWatcher(&on_complete_);
} }
{
gpr_mu_lock(&w->mu); MutexLock lock(&mu_);
if (due_to_completion) { if (due_to_completion) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures)) { if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures)) {
GRPC_LOG_IF_ERROR("watch_completion_error", GRPC_ERROR_REF(error)); GRPC_LOG_IF_ERROR("watch_completion_error", GRPC_ERROR_REF(error));
@ -130,76 +160,66 @@ static void partly_done(state_watcher* w, bool due_to_completion,
error = GRPC_ERROR_NONE; error = GRPC_ERROR_NONE;
} }
} }
switch (w->phase) { switch (phase_) {
case WAITING: case kWaiting:
GRPC_ERROR_REF(error); GRPC_ERROR_REF(error);
w->error = error; error_ = error;
w->phase = READY_TO_CALL_BACK; phase_ = kReadyToCallBack;
break; break;
case READY_TO_CALL_BACK: case kReadyToCallBack:
if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_NONE) {
GPR_ASSERT(!due_to_completion); GPR_ASSERT(!due_to_completion);
GRPC_ERROR_UNREF(w->error); GRPC_ERROR_UNREF(error_);
GRPC_ERROR_REF(error); GRPC_ERROR_REF(error);
w->error = error; error_ = error;
} }
w->phase = CALLING_BACK_AND_FINISHED; phase_ = kCallingBackAndFinished;
end_op = true; end_op = true;
end_op_cq = w->cq; end_op_cq = cq_;
end_op_tag = w->tag; end_op_tag = tag_;
end_op_error = w->error; end_op_error = error_;
end_op_completion_storage = &w->completion_storage; end_op_completion_storage = &completion_storage_;
break; break;
case CALLING_BACK_AND_FINISHED: case kCallingBackAndFinished:
GPR_UNREACHABLE_CODE(return ); GPR_UNREACHABLE_CODE(return );
break;
} }
gpr_mu_unlock(&w->mu); }
if (end_op) { if (end_op) {
grpc_cq_end_op(end_op_cq, end_op_tag, end_op_error, finished_completion, w, grpc_cq_end_op(end_op_cq, end_op_tag, end_op_error, FinishedCompletion,
end_op_completion_storage); this, end_op_completion_storage);
} }
GRPC_ERROR_UNREF(error); GRPC_ERROR_UNREF(error);
} }
static void watch_complete(void* pw, grpc_error* error) {
partly_done(static_cast<state_watcher*>(pw), true, GRPC_ERROR_REF(error));
}
static void timeout_complete(void* pw, grpc_error* error) { static void WatchComplete(void* arg, grpc_error* error) {
partly_done(static_cast<state_watcher*>(pw), false, GRPC_ERROR_REF(error)); auto* self = static_cast<StateWatcher*>(arg);
} self->PartlyDone(/*due_to_completion=*/true, GRPC_ERROR_REF(error));
}
int grpc_channel_num_external_connectivity_watchers(grpc_channel* channel) { static void TimeoutComplete(void* arg, grpc_error* error) {
grpc_core::ClientChannel* client_channel = auto* self = static_cast<StateWatcher*>(arg);
grpc_core::ClientChannel::GetFromChannel(channel); self->PartlyDone(/*due_to_completion=*/false, GRPC_ERROR_REF(error));
if (client_channel == nullptr) {
gpr_log(GPR_ERROR,
"grpc_channel_num_external_connectivity_watchers called on "
"something that is not a client channel");
return 0;
} }
return client_channel->NumExternalConnectivityWatchers();
}
typedef struct watcher_timer_init_arg { grpc_channel* channel_;
state_watcher* w; grpc_completion_queue* cq_;
gpr_timespec deadline; void* tag_;
} watcher_timer_init_arg;
static void watcher_timer_init(void* arg, grpc_error* /*error_ignored*/) { grpc_connectivity_state state_;
watcher_timer_init_arg* wa = static_cast<watcher_timer_init_arg*>(arg);
grpc_timer_init(&wa->w->alarm, grpc_timespec_to_millis_round_up(wa->deadline), grpc_cq_completion completion_storage_;
&wa->w->on_timeout);
gpr_free(wa);
}
int grpc_channel_support_connectivity_watcher(grpc_channel* channel) { grpc_closure on_complete_;
return grpc_core::ClientChannel::GetFromChannel(channel) != nullptr; grpc_timer timer_;
} grpc_closure on_timeout_;
Mutex mu_;
CallbackPhase phase_ ABSL_GUARDED_BY(mu_) = kWaiting;
grpc_error* error_ ABSL_GUARDED_BY(mu_) = GRPC_ERROR_NONE;
};
} // namespace
} // namespace grpc_core
void grpc_channel_watch_connectivity_state( void grpc_channel_watch_connectivity_state(
grpc_channel* channel, grpc_connectivity_state last_observed_state, grpc_channel* channel, grpc_connectivity_state last_observed_state,
@ -215,34 +235,5 @@ void grpc_channel_watch_connectivity_state(
7, 7,
(channel, (int)last_observed_state, deadline.tv_sec, deadline.tv_nsec, (channel, (int)last_observed_state, deadline.tv_sec, deadline.tv_nsec,
(int)deadline.clock_type, cq, tag)); (int)deadline.clock_type, cq, tag));
new grpc_core::StateWatcher(channel, cq, tag, last_observed_state, deadline);
GPR_ASSERT(grpc_cq_begin_op(cq, tag));
state_watcher* w = static_cast<state_watcher*>(gpr_malloc(sizeof(*w)));
gpr_mu_init(&w->mu);
GRPC_CLOSURE_INIT(&w->on_complete, watch_complete, w,
grpc_schedule_on_exec_ctx);
GRPC_CLOSURE_INIT(&w->on_timeout, timeout_complete, w,
grpc_schedule_on_exec_ctx);
w->phase = WAITING;
w->state = last_observed_state;
w->cq = cq;
w->tag = tag;
w->channel = channel;
w->error = nullptr;
watcher_timer_init_arg* wa = static_cast<watcher_timer_init_arg*>(
gpr_malloc(sizeof(watcher_timer_init_arg)));
wa->w = w;
wa->deadline = deadline;
GRPC_CLOSURE_INIT(&w->watcher_timer_init, watcher_timer_init, wa,
grpc_schedule_on_exec_ctx);
GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity");
grpc_core::ClientChannel* client_channel =
grpc_core::ClientChannel::GetFromChannel(channel);
GPR_ASSERT(client_channel != nullptr);
client_channel->AddExternalConnectivityWatcher(
grpc_polling_entity_create_from_pollset(grpc_cq_pollset(cq)), &w->state,
&w->on_complete, &w->watcher_timer_init);
} }

Loading…
Cancel
Save