Skip to content

Commit

Permalink
Merge pull request grpc#10813 from apolcyn/fix_conn_watch_mem_accum
Browse files Browse the repository at this point in the history
get rid of connectivity state watchers right after timeout
  • Loading branch information
apolcyn committed May 18, 2017
2 parents d6499c7 + c3b1f18 commit 2502a7d
Show file tree
Hide file tree
Showing 18 changed files with 837 additions and 34 deletions.
32 changes: 32 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ add_dependencies(buildtests_c mlog_test)
add_dependencies(buildtests_c multiple_server_queues_test)
add_dependencies(buildtests_c murmur_hash_test)
add_dependencies(buildtests_c no_server_test)
add_dependencies(buildtests_c num_external_connectivity_watchers_test)
add_dependencies(buildtests_c parse_address_test)
add_dependencies(buildtests_c percent_encoding_test)
if(_gRPC_PLATFORM_LINUX)
Expand Down Expand Up @@ -7580,6 +7581,37 @@ target_link_libraries(no_server_test
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)

add_executable(num_external_connectivity_watchers_test
test/core/surface/num_external_connectivity_watchers_test.c
)


target_include_directories(num_external_connectivity_watchers_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${BORINGSSL_ROOT_DIR}/include
PRIVATE ${PROTOBUF_ROOT_DIR}/src
PRIVATE ${BENCHMARK_ROOT_DIR}/include
PRIVATE ${ZLIB_ROOT_DIR}
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
PRIVATE ${CARES_BUILD_INCLUDE_DIR}
PRIVATE ${CARES_INCLUDE_DIR}
PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
)

target_link_libraries(num_external_connectivity_watchers_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
grpc
gpr_test_util
gpr
)

endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)

add_executable(parse_address_test
test/core/client_channel/parse_address_test.c
)
Expand Down
36 changes: 36 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,7 @@ murmur_hash_test: $(BINDIR)/$(CONFIG)/murmur_hash_test
nanopb_fuzzer_response_test: $(BINDIR)/$(CONFIG)/nanopb_fuzzer_response_test
nanopb_fuzzer_serverlist_test: $(BINDIR)/$(CONFIG)/nanopb_fuzzer_serverlist_test
no_server_test: $(BINDIR)/$(CONFIG)/no_server_test
num_external_connectivity_watchers_test: $(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test
parse_address_test: $(BINDIR)/$(CONFIG)/parse_address_test
percent_decode_fuzzer: $(BINDIR)/$(CONFIG)/percent_decode_fuzzer
percent_encode_fuzzer: $(BINDIR)/$(CONFIG)/percent_encode_fuzzer
Expand Down Expand Up @@ -1427,6 +1428,7 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/multiple_server_queues_test \
$(BINDIR)/$(CONFIG)/murmur_hash_test \
$(BINDIR)/$(CONFIG)/no_server_test \
$(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test \
$(BINDIR)/$(CONFIG)/parse_address_test \
$(BINDIR)/$(CONFIG)/percent_encoding_test \
$(BINDIR)/$(CONFIG)/pollset_set_test \
Expand Down Expand Up @@ -1883,6 +1885,8 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/murmur_hash_test || ( echo test murmur_hash_test failed ; exit 1 )
$(E) "[RUN] Testing no_server_test"
$(Q) $(BINDIR)/$(CONFIG)/no_server_test || ( echo test no_server_test failed ; exit 1 )
$(E) "[RUN] Testing num_external_connectivity_watchers_test"
$(Q) $(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test || ( echo test num_external_connectivity_watchers_test failed ; exit 1 )
$(E) "[RUN] Testing parse_address_test"
$(Q) $(BINDIR)/$(CONFIG)/parse_address_test || ( echo test parse_address_test failed ; exit 1 )
$(E) "[RUN] Testing percent_encoding_test"
Expand Down Expand Up @@ -11810,6 +11814,38 @@ endif
endif


NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_SRC = \
test/core/surface/num_external_connectivity_watchers_test.c \

NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_SRC))))
ifeq ($(NO_SECURE),true)

# You can't build secure targets if you don't have OpenSSL.

$(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test: openssl_dep_error

else



$(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test: $(NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test

endif

$(OBJDIR)/$(CONFIG)/test/core/surface/num_external_connectivity_watchers_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a

deps_num_external_connectivity_watchers_test: $(NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_OBJS:.o=.dep)

ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_OBJS:.o=.dep)
endif
endif


PARSE_ADDRESS_TEST_SRC = \
test/core/client_channel/parse_address_test.c \

Expand Down
12 changes: 12 additions & 0 deletions build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2586,6 +2586,18 @@ targets:
- grpc
- gpr_test_util
- gpr
- name: num_external_connectivity_watchers_test
build: test
language: c
src:
- test/core/surface/num_external_connectivity_watchers_test.c
deps:
- grpc_test_util
- grpc
- gpr_test_util
- gpr
exclude_iomgrs:
- uv
- name: parse_address_test
build: test
language: c
Expand Down
1 change: 1 addition & 0 deletions grpc.def
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ EXPORTS
grpc_alarm_cancel
grpc_alarm_destroy
grpc_channel_check_connectivity_state
grpc_channel_num_external_connectivity_watchers
grpc_channel_watch_connectivity_state
grpc_channel_create_call
grpc_channel_ping
Expand Down
6 changes: 6 additions & 0 deletions include/grpc/grpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,12 @@ GRPCAPI void grpc_alarm_destroy(grpc_alarm *alarm);
GRPCAPI grpc_connectivity_state grpc_channel_check_connectivity_state(
grpc_channel *channel, int try_to_connect);

/** Number of active "external connectivity state watchers" attached to a
* channel.
* Useful for testing. **/
GRPCAPI int grpc_channel_num_external_connectivity_watchers(
grpc_channel *channel);

/** Watch for a change in connectivity state.
Once the channel connectivity state is different from last_observed_state,
tag will be enqueued on cq with success=1.
Expand Down
77 changes: 53 additions & 24 deletions src/core/ext/filters/client_channel/channel_connectivity.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,21 +67,22 @@ grpc_connectivity_state grpc_channel_check_connectivity_state(

typedef enum {
WAITING,
CALLING_BACK,
READY_TO_CALL_BACK,
CALLING_BACK_AND_FINISHED,
CALLED_BACK
} callback_phase;

typedef struct {
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;
} state_watcher;

Expand All @@ -105,11 +106,8 @@ static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw,
gpr_mu_lock(&w->mu);
switch (w->phase) {
case WAITING:
case CALLED_BACK:
case READY_TO_CALL_BACK:
GPR_UNREACHABLE_CODE(return );
case CALLING_BACK:
w->phase = CALLED_BACK;
break;
case CALLING_BACK_AND_FINISHED:
delete = 1;
break;
Expand All @@ -123,10 +121,14 @@ static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw,

static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w,
bool due_to_completion, grpc_error *error) {
int delete = 0;

if (due_to_completion) {
grpc_timer_cancel(exec_ctx, &w->alarm);
} else {
grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element(
grpc_channel_get_channel_stack(w->channel));
grpc_client_channel_watch_connectivity_state(exec_ctx, client_channel_elem,
grpc_cq_pollset(w->cq), NULL,
&w->on_complete, NULL);
}

gpr_mu_lock(&w->mu);
Expand All @@ -147,25 +149,27 @@ static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w,
}
switch (w->phase) {
case WAITING:
w->phase = CALLING_BACK;
grpc_cq_end_op(exec_ctx, w->cq, w->tag, GRPC_ERROR_REF(error),
finished_completion, w, &w->completion_storage);
GRPC_ERROR_REF(error);
w->error = error;
w->phase = READY_TO_CALL_BACK;
break;
case CALLING_BACK:
case READY_TO_CALL_BACK:
if (error != GRPC_ERROR_NONE) {
GPR_ASSERT(!due_to_completion);
GRPC_ERROR_UNREF(w->error);
GRPC_ERROR_REF(error);
w->error = error;
}
w->phase = CALLING_BACK_AND_FINISHED;
grpc_cq_end_op(exec_ctx, w->cq, w->tag, w->error, finished_completion, w,
&w->completion_storage);
break;
case CALLING_BACK_AND_FINISHED:
GPR_UNREACHABLE_CODE(return );
case CALLED_BACK:
delete = 1;
break;
}
gpr_mu_unlock(&w->mu);

if (delete) {
delete_state_watcher(exec_ctx, w);
}

GRPC_ERROR_UNREF(error);
}

Expand All @@ -179,6 +183,28 @@ static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw,
partly_done(exec_ctx, pw, false, GRPC_ERROR_REF(error));
}

int grpc_channel_num_external_connectivity_watchers(grpc_channel *channel) {
grpc_channel_element *client_channel_elem =
grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
return grpc_client_channel_num_external_connectivity_watchers(
client_channel_elem);
}

typedef struct watcher_timer_init_arg {
state_watcher *w;
gpr_timespec deadline;
} watcher_timer_init_arg;

static void watcher_timer_init(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error_ignored) {
watcher_timer_init_arg *wa = (watcher_timer_init_arg *)arg;

grpc_timer_init(exec_ctx, &wa->w->alarm,
gpr_convert_clock_type(wa->deadline, GPR_CLOCK_MONOTONIC),
&wa->w->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC));
gpr_free(wa);
}

void grpc_channel_watch_connectivity_state(
grpc_channel *channel, grpc_connectivity_state last_observed_state,
gpr_timespec deadline, grpc_completion_queue *cq, void *tag) {
Expand Down Expand Up @@ -208,16 +234,19 @@ void grpc_channel_watch_connectivity_state(
w->cq = cq;
w->tag = tag;
w->channel = channel;
w->error = NULL;

grpc_timer_init(&exec_ctx, &w->alarm,
gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
&w->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC));
watcher_timer_init_arg *wa = 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);

if (client_channel_elem->filter == &grpc_client_channel_filter) {
GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity");
grpc_client_channel_watch_connectivity_state(&exec_ctx, client_channel_elem,
grpc_cq_pollset(cq), &w->state,
&w->on_complete);
grpc_client_channel_watch_connectivity_state(
&exec_ctx, client_channel_elem, grpc_cq_pollset(cq), &w->state,
&w->on_complete, &w->watcher_timer_init);
} else {
abort();
}
Expand Down
Loading

0 comments on commit 2502a7d

Please sign in to comment.