From a6435bd3f78fd3e0634b9f712df9ef612a7ff9ac Mon Sep 17 00:00:00 2001 From: jiangtaoli2016 Date: Fri, 28 Apr 2017 09:45:07 -0700 Subject: [PATCH 01/65] Update security_handshaker to use new TSI --- .../security/transport/security_connector.c | 31 ++- .../security/transport/security_handshaker.c | 220 ++++++++++-------- 2 files changed, 137 insertions(+), 114 deletions(-) diff --git a/src/core/lib/security/transport/security_connector.c b/src/core/lib/security/transport/security_connector.c index 30431a4e4a5..7dbed1c1e8e 100644 --- a/src/core/lib/security/transport/security_connector.c +++ b/src/core/lib/security/transport/security_connector.c @@ -56,6 +56,7 @@ #include "src/core/lib/support/string.h" #include "src/core/tsi/fake_transport_security.h" #include "src/core/tsi/ssl_transport_security.h" +#include "src/core/tsi/transport_security_adapter.h" /* -- Constants. -- */ @@ -388,20 +389,22 @@ static void fake_channel_add_handshakers( grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, grpc_handshake_manager *handshake_mgr) { grpc_handshake_manager_add( - handshake_mgr, - grpc_security_handshaker_create( - exec_ctx, tsi_create_fake_handshaker(true /* is_client */), - &sc->base)); + handshake_mgr, grpc_security_handshaker_create( + exec_ctx, + tsi_create_adapter_handshaker( + tsi_create_fake_handshaker(true /* is_client */)), + &sc->base)); } static void fake_server_add_handshakers(grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc, grpc_handshake_manager *handshake_mgr) { grpc_handshake_manager_add( - handshake_mgr, - grpc_security_handshaker_create( - exec_ctx, tsi_create_fake_handshaker(false /* is_client */), - &sc->base)); + handshake_mgr, grpc_security_handshaker_create( + exec_ctx, + tsi_create_adapter_handshaker( + tsi_create_fake_handshaker(false /* is_client */)), + &sc->base)); } static grpc_security_connector_vtable fake_channel_vtable = { @@ -495,8 +498,10 @@ static void ssl_channel_add_handshakers(grpc_exec_ctx *exec_ctx, } // Create handshakers. - grpc_handshake_manager_add(handshake_mgr, grpc_security_handshaker_create( - exec_ctx, tsi_hs, &sc->base)); + grpc_handshake_manager_add( + handshake_mgr, + grpc_security_handshaker_create( + exec_ctx, tsi_create_adapter_handshaker(tsi_hs), &sc->base)); } static void ssl_server_add_handshakers(grpc_exec_ctx *exec_ctx, @@ -515,8 +520,10 @@ static void ssl_server_add_handshakers(grpc_exec_ctx *exec_ctx, } // Create handshakers. - grpc_handshake_manager_add(handshake_mgr, grpc_security_handshaker_create( - exec_ctx, tsi_hs, &sc->base)); + grpc_handshake_manager_add( + handshake_mgr, + grpc_security_handshaker_create( + exec_ctx, tsi_create_adapter_handshaker(tsi_hs), &sc->base)); } static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) { diff --git a/src/core/lib/security/transport/security_handshaker.c b/src/core/lib/security/transport/security_handshaker.c index 509b4b556d6..16c3c6e14d4 100644 --- a/src/core/lib/security/transport/security_handshaker.c +++ b/src/core/lib/security/transport/security_handshaker.c @@ -77,6 +77,7 @@ typedef struct { grpc_closure on_handshake_data_received_from_peer; grpc_closure on_peer_checked; grpc_auth_context *auth_context; + tsi_handshaker_result *handshaker_result; } security_handshaker; static void security_handshaker_unref(grpc_exec_ctx *exec_ctx, @@ -84,6 +85,7 @@ static void security_handshaker_unref(grpc_exec_ctx *exec_ctx, if (gpr_unref(&h->refs)) { gpr_mu_destroy(&h->mu); tsi_handshaker_destroy(h->handshaker); + tsi_handshaker_result_destroy(h->handshaker_result); if (h->endpoint_to_destroy != NULL) { grpc_endpoint_destroy(exec_ctx, h->endpoint_to_destroy); } @@ -150,23 +152,34 @@ static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *arg, security_handshake_failed_locked(exec_ctx, h, GRPC_ERROR_REF(error)); goto done; } - // Get frame protector. + // Create frame protector. tsi_frame_protector *protector; - tsi_result result = - tsi_handshaker_create_frame_protector(h->handshaker, NULL, &protector); - if (result != TSI_OK) { + tsi_result status = tsi_handshaker_result_create_frame_protector( + h->handshaker_result, NULL, &protector); + if (status != TSI_OK) { error = grpc_set_tsi_error_result( GRPC_ERROR_CREATE_FROM_STATIC_STRING("Frame protector creation failed"), - result); + status); security_handshake_failed_locked(exec_ctx, h, error); goto done; } - // Success. + // Get unused bytes. + unsigned char *unused_bytes = NULL; + size_t unused_bytes_size = 0; + status = tsi_handshaker_result_get_unused_bytes( + h->handshaker_result, &unused_bytes, &unused_bytes_size); + if (unused_bytes_size > 0) { + gpr_slice slice = + grpc_slice_from_copied_buffer((char *)unused_bytes, unused_bytes_size); + grpc_slice_buffer_add(&h->left_overs, slice); + } // Create secure endpoint. h->args->endpoint = grpc_secure_endpoint_create( protector, h->args->endpoint, h->left_overs.slices, h->left_overs.count); h->left_overs.count = 0; h->left_overs.length = 0; + tsi_handshaker_result_destroy(h->handshaker_result); + h->handshaker_result = NULL; // Clear out the read buffer before it gets passed to the transport, // since any excess bytes were already copied to h->left_overs. grpc_slice_buffer_reset_and_unref_internal(exec_ctx, h->args->read_buffer); @@ -189,44 +202,92 @@ done: static grpc_error *check_peer_locked(grpc_exec_ctx *exec_ctx, security_handshaker *h) { tsi_peer peer; - tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer); - if (result != TSI_OK) { + tsi_result status = + tsi_handshaker_result_extract_peer(h->handshaker_result, &peer); + if (status != TSI_OK) { return grpc_set_tsi_error_result( - GRPC_ERROR_CREATE_FROM_STATIC_STRING("Peer extraction failed"), result); + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Peer extraction failed"), status); } grpc_security_connector_check_peer(exec_ctx, h->connector, peer, &h->auth_context, &h->on_peer_checked); return GRPC_ERROR_NONE; } -static grpc_error *send_handshake_bytes_to_peer_locked(grpc_exec_ctx *exec_ctx, - security_handshaker *h) { - // Get data to send. - tsi_result result = TSI_OK; - size_t offset = 0; - do { - size_t to_send_size = h->handshake_buffer_size - offset; - result = tsi_handshaker_get_bytes_to_send_to_peer( - h->handshaker, h->handshake_buffer + offset, &to_send_size); - offset += to_send_size; - if (result == TSI_INCOMPLETE_DATA) { - h->handshake_buffer_size *= 2; - h->handshake_buffer = - gpr_realloc(h->handshake_buffer, h->handshake_buffer_size); - } - } while (result == TSI_INCOMPLETE_DATA); - if (result != TSI_OK) { +static grpc_error *on_handshake_next_done_locked( + grpc_exec_ctx *exec_ctx, security_handshaker *h, tsi_result status, + const unsigned char *bytes_to_send, size_t bytes_to_send_size, + tsi_handshaker_result *result) { + grpc_error *error = GRPC_ERROR_NONE; + // Read more if we need to. + if (status == TSI_INCOMPLETE_DATA) { + GPR_ASSERT(bytes_to_send_size == 0); + grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, + &h->on_handshake_data_received_from_peer); + return error; + } + + if (status != TSI_OK) { return grpc_set_tsi_error_result( - GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake failed"), result); + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake failed"), status); } - // Send data. - grpc_slice to_send = - grpc_slice_from_copied_buffer((const char *)h->handshake_buffer, offset); - grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &h->outgoing); - grpc_slice_buffer_add(&h->outgoing, to_send); - grpc_endpoint_write(exec_ctx, h->args->endpoint, &h->outgoing, - &h->on_handshake_data_sent_to_peer); - return GRPC_ERROR_NONE; + + // If there are data to send to the peer, send data. + if (bytes_to_send_size > 0) { + grpc_slice to_send = grpc_slice_from_copied_buffer( + (const char *)bytes_to_send, bytes_to_send_size); + grpc_slice_buffer_reset_and_unref(&h->outgoing); + grpc_slice_buffer_add(&h->outgoing, to_send); + grpc_endpoint_write(exec_ctx, h->args->endpoint, &h->outgoing, + &h->on_handshake_data_sent_to_peer); + } + + // If handshake has completed, check peer and so on. + if (result != NULL) { + h->handshaker_result = result; + error = check_peer_locked(exec_ctx, h); + } + return error; +} + +static void on_handshake_next_done_grpc_wrapper( + tsi_result status, void *user_data, const unsigned char *bytes_to_send, + size_t bytes_to_send_size, tsi_handshaker_result *result) { + security_handshaker *h = user_data; + // This callback will be invoked by TSI in a non-grpc thread, so it's + // safe to create our own exec_ctx here. + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + gpr_mu_lock(&h->mu); + grpc_error *error = on_handshake_next_done_locked( + &exec_ctx, h, status, bytes_to_send, bytes_to_send_size, result); + if (error != GRPC_ERROR_NONE) { + security_handshake_failed_locked(&exec_ctx, h, error); + gpr_mu_unlock(&h->mu); + security_handshaker_unref(&exec_ctx, h); + } else { + gpr_mu_unlock(&h->mu); + } + grpc_exec_ctx_finish(&exec_ctx); +} + +static grpc_error *do_handshaker_next_locked( + grpc_exec_ctx *exec_ctx, security_handshaker *h, + const unsigned char *bytes_received, size_t bytes_received_size) { + // Invoke TSI handshaker. + unsigned char *bytes_to_send = NULL; + size_t bytes_to_send_size = 0; + tsi_handshaker_result *result = NULL; + tsi_result status = tsi_handshaker_next( + h->handshaker, bytes_received, bytes_received_size, &bytes_to_send, + &bytes_to_send_size, &result, &on_handshake_next_done_grpc_wrapper, h); + if (status == TSI_ASYNC) { + // Handshaker operating asynchronously. Nothing else to do here; + // callback will be invoked in a TSI thread. + return GRPC_ERROR_NONE; + } + // Handshaker returned synchronously. Invoke callback directly in + // this thread with our existing exec_ctx. + return on_handshake_next_done_locked(exec_ctx, h, status, bytes_to_send, + bytes_to_send_size, result); } static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, @@ -241,72 +302,34 @@ static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, security_handshaker_unref(exec_ctx, h); return; } - // Process received data. - tsi_result result = TSI_OK; - size_t consumed_slice_size = 0; + // Copy all slides received. size_t i; + size_t bytes_received_size = 0; for (i = 0; i < h->args->read_buffer->count; i++) { - consumed_slice_size = GRPC_SLICE_LENGTH(h->args->read_buffer->slices[i]); - result = tsi_handshaker_process_bytes_from_peer( - h->handshaker, GRPC_SLICE_START_PTR(h->args->read_buffer->slices[i]), - &consumed_slice_size); - if (!tsi_handshaker_is_in_progress(h->handshaker)) break; + bytes_received_size += GRPC_SLICE_LENGTH(h->args->read_buffer->slices[i]); } - if (tsi_handshaker_is_in_progress(h->handshaker)) { - /* We may need more data. */ - if (result == TSI_INCOMPLETE_DATA) { - grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, - &h->on_handshake_data_received_from_peer); - goto done; - } else { - error = send_handshake_bytes_to_peer_locked(exec_ctx, h); - if (error != GRPC_ERROR_NONE) { - security_handshake_failed_locked(exec_ctx, h, error); - gpr_mu_unlock(&h->mu); - security_handshaker_unref(exec_ctx, h); - return; - } - goto done; - } + if (bytes_received_size > h->handshake_buffer_size) { + h->handshake_buffer = gpr_realloc(h->handshake_buffer, bytes_received_size); + h->handshake_buffer_size = bytes_received_size; } - if (result != TSI_OK) { - security_handshake_failed_locked( - exec_ctx, h, - grpc_set_tsi_error_result( - GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake failed"), result)); - gpr_mu_unlock(&h->mu); - security_handshaker_unref(exec_ctx, h); - return; - } - /* Handshake is done and successful this point. */ - bool has_left_overs_in_current_slice = - (consumed_slice_size < - GRPC_SLICE_LENGTH(h->args->read_buffer->slices[i])); - size_t num_left_overs = (has_left_overs_in_current_slice ? 1 : 0) + - h->args->read_buffer->count - i - 1; - if (num_left_overs > 0) { - /* Put the leftovers in our buffer (ownership transfered). */ - if (has_left_overs_in_current_slice) { - grpc_slice tail = grpc_slice_split_tail(&h->args->read_buffer->slices[i], - consumed_slice_size); - grpc_slice_buffer_add(&h->left_overs, tail); - /* split_tail above increments refcount. */ - grpc_slice_unref_internal(exec_ctx, tail); - } - grpc_slice_buffer_addn( - &h->left_overs, &h->args->read_buffer->slices[i + 1], - num_left_overs - (size_t)has_left_overs_in_current_slice); + size_t offset = 0; + for (i = 0; i < h->args->read_buffer->count; i++) { + size_t slice_size = GPR_SLICE_LENGTH(h->args->read_buffer->slices[i]); + memcpy(h->handshake_buffer + offset, + GRPC_SLICE_START_PTR(h->args->read_buffer->slices[i]), slice_size); + offset += slice_size; } - // Check peer. - error = check_peer_locked(exec_ctx, h); + // Call TSI handshaker. + error = do_handshaker_next_locked(exec_ctx, h, h->handshake_buffer, + bytes_received_size); + if (error != GRPC_ERROR_NONE) { security_handshake_failed_locked(exec_ctx, h, error); gpr_mu_unlock(&h->mu); security_handshaker_unref(exec_ctx, h); - return; + } else { + gpr_mu_unlock(&h->mu); } -done: - gpr_mu_unlock(&h->mu); } static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *arg, @@ -321,18 +344,11 @@ static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *arg, security_handshaker_unref(exec_ctx, h); return; } - /* We may be done. */ - if (tsi_handshaker_is_in_progress(h->handshaker)) { + if (h->handshaker_result != NULL) { + check_peer_locked(exec_ctx, h); + } else { grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, &h->on_handshake_data_received_from_peer); - } else { - error = check_peer_locked(exec_ctx, h); - if (error != GRPC_ERROR_NONE) { - security_handshake_failed_locked(exec_ctx, h, error); - gpr_mu_unlock(&h->mu); - security_handshaker_unref(exec_ctx, h); - return; - } } gpr_mu_unlock(&h->mu); } @@ -371,7 +387,7 @@ static void security_handshaker_do_handshake(grpc_exec_ctx *exec_ctx, h->args = args; h->on_handshake_done = on_handshake_done; gpr_ref(&h->refs); - grpc_error *error = send_handshake_bytes_to_peer_locked(exec_ctx, h); + grpc_error *error = do_handshaker_next_locked(exec_ctx, h, NULL, 0); if (error != GRPC_ERROR_NONE) { security_handshake_failed_locked(exec_ctx, h, error); gpr_mu_unlock(&h->mu); From 0359e1260f99387c79d1ef67de0447b1208fb785 Mon Sep 17 00:00:00 2001 From: Vizerai Date: Fri, 28 Apr 2017 20:06:58 -0700 Subject: [PATCH 02/65] initial commit --- BUILD | 2 + CMakeLists.txt | 38 ++++ Makefile | 39 ++++ binding.gyp | 1 + build.yaml | 12 ++ config.m4 | 1 + gRPC-Core.podspec | 3 + grpc.gemspec | 2 + package.xml | 2 + src/core/ext/census/intrusive_hash_map.c | 1 + src/core/ext/census/intrusive_hash_map.h | 1 + src/python/grpcio/grpc_core_dependencies.py | 1 + test/core/census/intrusive_hash_map_test.c | 1 + tools/doxygen/Doxyfile.core.internal | 2 + .../generated/sources_and_headers.json | 20 ++ tools/run_tests/generated/tests.json | 22 ++ vsprojects/buildtests_c.sln | 27 +++ vsprojects/vcxproj/grpc/grpc.vcxproj | 3 + vsprojects/vcxproj/grpc/grpc.vcxproj.filters | 6 + .../grpc_unsecure/grpc_unsecure.vcxproj | 3 + .../grpc_unsecure.vcxproj.filters | 6 + .../census_intrusive_hash_map_test.vcxproj | 199 ++++++++++++++++++ ...us_intrusive_hash_map_test.vcxproj.filters | 21 ++ 23 files changed, 413 insertions(+) create mode 120000 src/core/ext/census/intrusive_hash_map.c create mode 120000 src/core/ext/census/intrusive_hash_map.h create mode 120000 test/core/census/intrusive_hash_map_test.c create mode 100644 vsprojects/vcxproj/test/census_intrusive_hash_map_test/census_intrusive_hash_map_test.vcxproj create mode 100644 vsprojects/vcxproj/test/census_intrusive_hash_map_test/census_intrusive_hash_map_test.vcxproj.filters diff --git a/BUILD b/BUILD index 0339c87c1c0..eac5e622f0b 100644 --- a/BUILD +++ b/BUILD @@ -282,6 +282,7 @@ grpc_cc_library( "src/core/ext/census/grpc_filter.c", "src/core/ext/census/grpc_plugin.c", "src/core/ext/census/initialize.c", + "src/core/ext/census/intrusive_hash_map.c", "src/core/ext/census/mlog.c", "src/core/ext/census/operation.c", "src/core/ext/census/placeholders.c", @@ -297,6 +298,7 @@ grpc_cc_library( "src/core/ext/census/gen/census.pb.h", "src/core/ext/census/gen/trace_context.pb.h", "src/core/ext/census/grpc_filter.h", + "src/core/ext/census/intrusive_hash_map.c", "src/core/ext/census/mlog.h", "src/core/ext/census/resource.h", "src/core/ext/census/rpc_metric_id.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index a179a0f4a35..e41b1b3232b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -374,6 +374,7 @@ add_dependencies(buildtests_c bdp_estimator_test) add_dependencies(buildtests_c bin_decoder_test) add_dependencies(buildtests_c bin_encoder_test) add_dependencies(buildtests_c census_context_test) +add_dependencies(buildtests_c census_intrusive_hash_map_test) add_dependencies(buildtests_c census_resource_test) add_dependencies(buildtests_c census_trace_context_test) add_dependencies(buildtests_c channel_create_test) @@ -1144,6 +1145,7 @@ add_library(grpc src/core/ext/census/grpc_filter.c src/core/ext/census/grpc_plugin.c src/core/ext/census/initialize.c + src/core/ext/census/intrusive_hash_map.c src/core/ext/census/mlog.c src/core/ext/census/operation.c src/core/ext/census/placeholders.c @@ -2007,6 +2009,7 @@ add_library(grpc_unsecure src/core/ext/census/grpc_filter.c src/core/ext/census/grpc_plugin.c src/core/ext/census/initialize.c + src/core/ext/census/intrusive_hash_map.c src/core/ext/census/mlog.c src/core/ext/census/operation.c src/core/ext/census/placeholders.c @@ -2739,6 +2742,7 @@ add_library(grpc++_cronet src/core/ext/census/grpc_filter.c src/core/ext/census/grpc_plugin.c src/core/ext/census/initialize.c + src/core/ext/census/intrusive_hash_map.c src/core/ext/census/mlog.c src/core/ext/census/operation.c src/core/ext/census/placeholders.c @@ -4976,6 +4980,37 @@ target_link_libraries(census_context_test endif (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS) +add_executable(census_intrusive_hash_map_test + test/core/census/intrusive_hash_map_test.c +) + + +target_include_directories(census_intrusive_hash_map_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(census_intrusive_hash_map_test + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc_test_util + grpc + gpr_test_util + gpr +) + +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) + add_executable(census_resource_test test/core/census/resource_test.c ) @@ -11108,6 +11143,7 @@ if (gRPC_BUILD_TESTS) add_executable(memory_test test/core/support/memory_test.cc third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc ) @@ -11126,6 +11162,8 @@ target_include_directories(memory_test PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include PRIVATE third_party/googletest/googletest/include PRIVATE third_party/googletest/googletest + PRIVATE third_party/googletest/googlemock/include + PRIVATE third_party/googletest/googlemock PRIVATE ${_gRPC_PROTO_GENS_DIR} ) diff --git a/Makefile b/Makefile index dd35d8c435d..2600394a864 100644 --- a/Makefile +++ b/Makefile @@ -975,6 +975,7 @@ bdp_estimator_test: $(BINDIR)/$(CONFIG)/bdp_estimator_test bin_decoder_test: $(BINDIR)/$(CONFIG)/bin_decoder_test bin_encoder_test: $(BINDIR)/$(CONFIG)/bin_encoder_test census_context_test: $(BINDIR)/$(CONFIG)/census_context_test +census_intrusive_hash_map_test: $(BINDIR)/$(CONFIG)/census_intrusive_hash_map_test census_resource_test: $(BINDIR)/$(CONFIG)/census_resource_test census_trace_context_test: $(BINDIR)/$(CONFIG)/census_trace_context_test channel_create_test: $(BINDIR)/$(CONFIG)/channel_create_test @@ -1364,6 +1365,7 @@ buildtests_c: privatelibs_c \ $(BINDIR)/$(CONFIG)/bin_decoder_test \ $(BINDIR)/$(CONFIG)/bin_encoder_test \ $(BINDIR)/$(CONFIG)/census_context_test \ + $(BINDIR)/$(CONFIG)/census_intrusive_hash_map_test \ $(BINDIR)/$(CONFIG)/census_resource_test \ $(BINDIR)/$(CONFIG)/census_trace_context_test \ $(BINDIR)/$(CONFIG)/channel_create_test \ @@ -1763,6 +1765,8 @@ test_c: buildtests_c $(Q) $(BINDIR)/$(CONFIG)/bin_encoder_test || ( echo test bin_encoder_test failed ; exit 1 ) $(E) "[RUN] Testing census_context_test" $(Q) $(BINDIR)/$(CONFIG)/census_context_test || ( echo test census_context_test failed ; exit 1 ) + $(E) "[RUN] Testing census_intrusive_hash_map_test" + $(Q) $(BINDIR)/$(CONFIG)/census_intrusive_hash_map_test || ( echo test census_intrusive_hash_map_test failed ; exit 1 ) $(E) "[RUN] Testing census_resource_test" $(Q) $(BINDIR)/$(CONFIG)/census_resource_test || ( echo test census_resource_test failed ; exit 1 ) $(E) "[RUN] Testing census_trace_context_test" @@ -3123,6 +3127,7 @@ LIBGRPC_SRC = \ src/core/ext/census/grpc_filter.c \ src/core/ext/census/grpc_plugin.c \ src/core/ext/census/initialize.c \ + src/core/ext/census/intrusive_hash_map.c \ src/core/ext/census/mlog.c \ src/core/ext/census/operation.c \ src/core/ext/census/placeholders.c \ @@ -3955,6 +3960,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/ext/census/grpc_filter.c \ src/core/ext/census/grpc_plugin.c \ src/core/ext/census/initialize.c \ + src/core/ext/census/intrusive_hash_map.c \ src/core/ext/census/mlog.c \ src/core/ext/census/operation.c \ src/core/ext/census/placeholders.c \ @@ -4672,6 +4678,7 @@ LIBGRPC++_CRONET_SRC = \ src/core/ext/census/grpc_filter.c \ src/core/ext/census/grpc_plugin.c \ src/core/ext/census/initialize.c \ + src/core/ext/census/intrusive_hash_map.c \ src/core/ext/census/mlog.c \ src/core/ext/census/operation.c \ src/core/ext/census/placeholders.c \ @@ -8897,6 +8904,38 @@ endif endif +CENSUS_INTRUSIVE_HASH_MAP_TEST_SRC = \ + test/core/census/intrusive_hash_map_test.c \ + +CENSUS_INTRUSIVE_HASH_MAP_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CENSUS_INTRUSIVE_HASH_MAP_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/census_intrusive_hash_map_test: openssl_dep_error + +else + + + +$(BINDIR)/$(CONFIG)/census_intrusive_hash_map_test: $(CENSUS_INTRUSIVE_HASH_MAP_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) $(CENSUS_INTRUSIVE_HASH_MAP_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)/census_intrusive_hash_map_test + +endif + +$(OBJDIR)/$(CONFIG)/test/core/census/intrusive_hash_map_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_census_intrusive_hash_map_test: $(CENSUS_INTRUSIVE_HASH_MAP_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(CENSUS_INTRUSIVE_HASH_MAP_TEST_OBJS:.o=.dep) +endif +endif + + CENSUS_RESOURCE_TEST_SRC = \ test/core/census/resource_test.c \ diff --git a/binding.gyp b/binding.gyp index 582c61282f9..1c2ff5642a7 100644 --- a/binding.gyp +++ b/binding.gyp @@ -879,6 +879,7 @@ 'src/core/ext/census/grpc_filter.c', 'src/core/ext/census/grpc_plugin.c', 'src/core/ext/census/initialize.c', + 'src/core/ext/census/intrusive_hash_map.c', 'src/core/ext/census/mlog.c', 'src/core/ext/census/operation.c', 'src/core/ext/census/placeholders.c', diff --git a/build.yaml b/build.yaml index 7b60612742b..3267b7578ae 100644 --- a/build.yaml +++ b/build.yaml @@ -27,6 +27,7 @@ filegroups: - src/core/ext/census/gen/census.pb.h - src/core/ext/census/gen/trace_context.pb.h - src/core/ext/census/grpc_filter.h + - src/core/ext/census/intrusive_hash_map.h - src/core/ext/census/mlog.h - src/core/ext/census/resource.h - src/core/ext/census/rpc_metric_id.h @@ -45,6 +46,7 @@ filegroups: - src/core/ext/census/grpc_filter.c - src/core/ext/census/grpc_plugin.c - src/core/ext/census/initialize.c + - src/core/ext/census/intrusive_hash_map.c - src/core/ext/census/mlog.c - src/core/ext/census/operation.c - src/core/ext/census/placeholders.c @@ -1632,6 +1634,16 @@ targets: - grpc - gpr_test_util - gpr +- name: census_intrusive_hash_map_test + build: test + language: c + src: + - test/core/census/intrusive_hash_map_test.c + deps: + - grpc_test_util + - grpc + - gpr_test_util + - gpr - name: census_resource_test build: test language: c diff --git a/config.m4 b/config.m4 index bbd667c9ec4..c0873d7bde7 100644 --- a/config.m4 +++ b/config.m4 @@ -315,6 +315,7 @@ if test "$PHP_GRPC" != "no"; then src/core/ext/census/grpc_filter.c \ src/core/ext/census/grpc_plugin.c \ src/core/ext/census/initialize.c \ + src/core/ext/census/intrusive_hash_map.c \ src/core/ext/census/mlog.c \ src/core/ext/census/operation.c \ src/core/ext/census/placeholders.c \ diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 07755ac7279..ecf0f515e1f 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -453,6 +453,7 @@ Pod::Spec.new do |s| 'src/core/ext/census/gen/census.pb.h', 'src/core/ext/census/gen/trace_context.pb.h', 'src/core/ext/census/grpc_filter.h', + 'src/core/ext/census/intrusive_hash_map.h', 'src/core/ext/census/mlog.h', 'src/core/ext/census/resource.h', 'src/core/ext/census/rpc_metric_id.h', @@ -692,6 +693,7 @@ Pod::Spec.new do |s| 'src/core/ext/census/grpc_filter.c', 'src/core/ext/census/grpc_plugin.c', 'src/core/ext/census/initialize.c', + 'src/core/ext/census/intrusive_hash_map.c', 'src/core/ext/census/mlog.c', 'src/core/ext/census/operation.c', 'src/core/ext/census/placeholders.c', @@ -914,6 +916,7 @@ Pod::Spec.new do |s| 'src/core/ext/census/gen/census.pb.h', 'src/core/ext/census/gen/trace_context.pb.h', 'src/core/ext/census/grpc_filter.h', + 'src/core/ext/census/intrusive_hash_map.h', 'src/core/ext/census/mlog.h', 'src/core/ext/census/resource.h', 'src/core/ext/census/rpc_metric_id.h', diff --git a/grpc.gemspec b/grpc.gemspec index 1cd6d66335e..9d086591669 100755 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -369,6 +369,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/census/gen/census.pb.h ) s.files += %w( src/core/ext/census/gen/trace_context.pb.h ) s.files += %w( src/core/ext/census/grpc_filter.h ) + s.files += %w( src/core/ext/census/intrusive_hash_map.h ) s.files += %w( src/core/ext/census/mlog.h ) s.files += %w( src/core/ext/census/resource.h ) s.files += %w( src/core/ext/census/rpc_metric_id.h ) @@ -608,6 +609,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/census/grpc_filter.c ) s.files += %w( src/core/ext/census/grpc_plugin.c ) s.files += %w( src/core/ext/census/initialize.c ) + s.files += %w( src/core/ext/census/intrusive_hash_map.c ) s.files += %w( src/core/ext/census/mlog.c ) s.files += %w( src/core/ext/census/operation.c ) s.files += %w( src/core/ext/census/placeholders.c ) diff --git a/package.xml b/package.xml index e7d67eca180..a7695015244 100644 --- a/package.xml +++ b/package.xml @@ -378,6 +378,7 @@ + @@ -617,6 +618,7 @@ + diff --git a/src/core/ext/census/intrusive_hash_map.c b/src/core/ext/census/intrusive_hash_map.c new file mode 120000 index 00000000000..55490cd9f90 --- /dev/null +++ b/src/core/ext/census/intrusive_hash_map.c @@ -0,0 +1 @@ +/google/src/cloud/jsking/cppTraceImpl/google3/experimental/users/jsking/intrusive_hash_map.c \ No newline at end of file diff --git a/src/core/ext/census/intrusive_hash_map.h b/src/core/ext/census/intrusive_hash_map.h new file mode 120000 index 00000000000..641ec396ddc --- /dev/null +++ b/src/core/ext/census/intrusive_hash_map.h @@ -0,0 +1 @@ +/google/src/cloud/jsking/cppTraceImpl/google3/experimental/users/jsking/intrusive_hash_map.h \ No newline at end of file diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index d2a570cc87e..940c36b6ea2 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -304,6 +304,7 @@ CORE_SOURCE_FILES = [ 'src/core/ext/census/grpc_filter.c', 'src/core/ext/census/grpc_plugin.c', 'src/core/ext/census/initialize.c', + 'src/core/ext/census/intrusive_hash_map.c', 'src/core/ext/census/mlog.c', 'src/core/ext/census/operation.c', 'src/core/ext/census/placeholders.c', diff --git a/test/core/census/intrusive_hash_map_test.c b/test/core/census/intrusive_hash_map_test.c new file mode 120000 index 00000000000..a790afe1975 --- /dev/null +++ b/test/core/census/intrusive_hash_map_test.c @@ -0,0 +1 @@ +/google/src/cloud/jsking/cppTraceImpl/google3/experimental/users/jsking/intrusive_hash_map_test.c \ No newline at end of file diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index f49c2de76c9..3a672dc6508 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -880,6 +880,8 @@ src/core/ext/census/grpc_filter.c \ src/core/ext/census/grpc_filter.h \ src/core/ext/census/grpc_plugin.c \ src/core/ext/census/initialize.c \ +src/core/ext/census/intrusive_hash_map.c \ +src/core/ext/census/intrusive_hash_map.h \ src/core/ext/census/mlog.c \ src/core/ext/census/mlog.h \ src/core/ext/census/operation.c \ diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 5eba7fbb697..51b5d0dfcf0 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -181,6 +181,23 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "gpr", + "gpr_test_util", + "grpc", + "grpc_test_util" + ], + "headers": [], + "is_filegroup": false, + "language": "c", + "name": "census_intrusive_hash_map_test", + "src": [ + "test/core/census/intrusive_hash_map_test.c" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "gpr", @@ -7461,6 +7478,7 @@ "src/core/ext/census/gen/census.pb.h", "src/core/ext/census/gen/trace_context.pb.h", "src/core/ext/census/grpc_filter.h", + "src/core/ext/census/intrusive_hash_map.h", "src/core/ext/census/mlog.h", "src/core/ext/census/resource.h", "src/core/ext/census/rpc_metric_id.h", @@ -7491,6 +7509,8 @@ "src/core/ext/census/grpc_filter.h", "src/core/ext/census/grpc_plugin.c", "src/core/ext/census/initialize.c", + "src/core/ext/census/intrusive_hash_map.c", + "src/core/ext/census/intrusive_hash_map.h", "src/core/ext/census/mlog.c", "src/core/ext/census/mlog.h", "src/core/ext/census/operation.c", diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 17f7c4b454e..0d5993134a7 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -223,6 +223,28 @@ "windows" ] }, + { + "args": [], + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": false, + "language": "c", + "name": "census_intrusive_hash_map_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ] + }, { "args": [], "ci_platforms": [ diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln index 539f474f9ec..a7fdb6d06e1 100644 --- a/vsprojects/buildtests_c.sln +++ b/vsprojects/buildtests_c.sln @@ -129,6 +129,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "census_context_test", "vcxp {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "census_intrusive_hash_map_test", "vcxproj\test\census_intrusive_hash_map_test\census_intrusive_hash_map_test.vcxproj", "{BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}" + ProjectSection(myProperties) = preProject + lib = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} + {29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9} + {EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037} + {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} + EndProjectSection +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "census_resource_test", "vcxproj\test\census_resource_test\census_resource_test.vcxproj", "{18CF99B5-3C61-EC3D-9509-3C95334C3B88}" ProjectSection(myProperties) = preProject lib = "False" @@ -1866,6 +1877,22 @@ Global {5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Release-DLL|Win32.Build.0 = Release|Win32 {5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Release-DLL|x64.ActiveCfg = Release|x64 {5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Release-DLL|x64.Build.0 = Release|x64 + {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Debug|Win32.ActiveCfg = Debug|Win32 + {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Debug|x64.ActiveCfg = Debug|x64 + {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Release|Win32.ActiveCfg = Release|Win32 + {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Release|x64.ActiveCfg = Release|x64 + {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Debug|Win32.Build.0 = Debug|Win32 + {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Debug|x64.Build.0 = Debug|x64 + {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Release|Win32.Build.0 = Release|Win32 + {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Release|x64.Build.0 = Release|x64 + {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Debug-DLL|Win32.ActiveCfg = Debug|Win32 + {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Debug-DLL|Win32.Build.0 = Debug|Win32 + {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Debug-DLL|x64.ActiveCfg = Debug|x64 + {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Debug-DLL|x64.Build.0 = Debug|x64 + {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Release-DLL|Win32.ActiveCfg = Release|Win32 + {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Release-DLL|Win32.Build.0 = Release|Win32 + {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Release-DLL|x64.ActiveCfg = Release|x64 + {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Release-DLL|x64.Build.0 = Release|x64 {18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Debug|Win32.ActiveCfg = Debug|Win32 {18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Debug|x64.ActiveCfg = Debug|x64 {18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Release|Win32.ActiveCfg = Release|Win32 diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj index 71520098a6d..c196f693084 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj @@ -494,6 +494,7 @@ + @@ -963,6 +964,8 @@ + + diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters index de2dfe67e6a..eb909d21f86 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters @@ -685,6 +685,9 @@ src\core\ext\census + + src\core\ext\census + src\core\ext\census @@ -1391,6 +1394,9 @@ src\core\ext\census + + src\core\ext\census + src\core\ext\census diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj index 0bfda72e815..b55e1f7cdd6 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj @@ -459,6 +459,7 @@ + @@ -870,6 +871,8 @@ + + diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters index 63c8d7f2542..febfc87d397 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters @@ -598,6 +598,9 @@ src\core\ext\census + + src\core\ext\census + src\core\ext\census @@ -1226,6 +1229,9 @@ src\core\ext\census + + src\core\ext\census + src\core\ext\census diff --git a/vsprojects/vcxproj/test/census_intrusive_hash_map_test/census_intrusive_hash_map_test.vcxproj b/vsprojects/vcxproj/test/census_intrusive_hash_map_test/census_intrusive_hash_map_test.vcxproj new file mode 100644 index 00000000000..46ea06b2a0f --- /dev/null +++ b/vsprojects/vcxproj/test/census_intrusive_hash_map_test/census_intrusive_hash_map_test.vcxproj @@ -0,0 +1,199 @@ + + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60} + true + $(SolutionDir)IntDir\$(MSBuildProjectName)\ + + + + v100 + + + v110 + + + v120 + + + v140 + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + census_intrusive_hash_map_test + static + Debug + static + Debug + + + census_intrusive_hash_map_test + static + Release + static + Release + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDebug + true + None + false + + + Console + true + false + + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDebug + true + None + false + + + Console + true + false + + + + + + NotUsing + Level3 + MaxSpeed + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + true + MultiThreaded + true + None + false + + + Console + true + false + true + true + + + + + + NotUsing + Level3 + MaxSpeed + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + true + MultiThreaded + true + None + false + + + Console + true + false + true + true + + + + + + + + + + {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} + + + {29D16885-7228-4C31-81ED-5F9187C7F2A9} + + + {EAB0A629-17A9-44DB-B5FF-E91A721FE037} + + + {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + diff --git a/vsprojects/vcxproj/test/census_intrusive_hash_map_test/census_intrusive_hash_map_test.vcxproj.filters b/vsprojects/vcxproj/test/census_intrusive_hash_map_test/census_intrusive_hash_map_test.vcxproj.filters new file mode 100644 index 00000000000..2dfa300e976 --- /dev/null +++ b/vsprojects/vcxproj/test/census_intrusive_hash_map_test/census_intrusive_hash_map_test.vcxproj.filters @@ -0,0 +1,21 @@ + + + + + test\core\census + + + + + + {24bfacc6-bd89-4cdf-4183-3ff53180fa48} + + + {71b1debf-71c7-c1e9-9e01-21330ede0d7f} + + + {0228063a-a601-967e-27ed-9f6197cb3629} + + + + From 26e85fe0d79f4b9df9fdfde2923c61b87f91088c Mon Sep 17 00:00:00 2001 From: Vizerai Date: Fri, 28 Apr 2017 21:20:34 -0700 Subject: [PATCH 03/65] update --- BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD b/BUILD index eac5e622f0b..5620965aa45 100644 --- a/BUILD +++ b/BUILD @@ -298,7 +298,7 @@ grpc_cc_library( "src/core/ext/census/gen/census.pb.h", "src/core/ext/census/gen/trace_context.pb.h", "src/core/ext/census/grpc_filter.h", - "src/core/ext/census/intrusive_hash_map.c", + "src/core/ext/census/intrusive_hash_map.h", "src/core/ext/census/mlog.h", "src/core/ext/census/resource.h", "src/core/ext/census/rpc_metric_id.h", From 6903d7423808dfdb4011ae8d603402f6def1430a Mon Sep 17 00:00:00 2001 From: Vizerai Date: Fri, 28 Apr 2017 21:28:37 -0700 Subject: [PATCH 04/65] changed from symbolic links to actual files --- src/core/ext/census/intrusive_hash_map.c | 304 ++++++++++++++++++++- src/core/ext/census/intrusive_hash_map.h | 170 +++++++++++- test/core/census/intrusive_hash_map_test.c | 273 +++++++++++++++++- 3 files changed, 744 insertions(+), 3 deletions(-) mode change 120000 => 100644 src/core/ext/census/intrusive_hash_map.c mode change 120000 => 100644 src/core/ext/census/intrusive_hash_map.h mode change 120000 => 100644 test/core/census/intrusive_hash_map_test.c diff --git a/src/core/ext/census/intrusive_hash_map.c b/src/core/ext/census/intrusive_hash_map.c deleted file mode 120000 index 55490cd9f90..00000000000 --- a/src/core/ext/census/intrusive_hash_map.c +++ /dev/null @@ -1 +0,0 @@ -/google/src/cloud/jsking/cppTraceImpl/google3/experimental/users/jsking/intrusive_hash_map.c \ No newline at end of file diff --git a/src/core/ext/census/intrusive_hash_map.c b/src/core/ext/census/intrusive_hash_map.c new file mode 100644 index 00000000000..4a747c91374 --- /dev/null +++ b/src/core/ext/census/intrusive_hash_map.c @@ -0,0 +1,303 @@ +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "src/core/ext/census/intrusive_hash_map.h" +#include + +extern bool hm_index_compare(const hm_index *A, const hm_index *B); + +/* Simple hashing function that takes lower 32 bits. */ +static inline uint32_t chunked_vector_hasher(uint64_t key) { + return (uint32_t)key; +} + +/* Vector chunks are 1MiB divided by pointer size. */ +static const size_t VECTOR_CHUNK_SIZE = (1 << 20) / sizeof(void *); + +/* Helper functions which return buckets from the chunked vector. These are + meant for internal use only within the intrusive_hash_map data structure. */ +static inline void **get_mutable_bucket(const chunked_vector *buckets, + uint32_t index) { + if (index < VECTOR_CHUNK_SIZE) { + return &buckets->first_[index]; + } + size_t rest_index = (index - VECTOR_CHUNK_SIZE) / VECTOR_CHUNK_SIZE; + return &buckets->rest_[rest_index][index % VECTOR_CHUNK_SIZE]; +} + +static inline void *get_bucket(const chunked_vector *buckets, uint32_t index) { + if (index < VECTOR_CHUNK_SIZE) { + return buckets->first_[index]; + } + size_t rest_index = (index - VECTOR_CHUNK_SIZE) / VECTOR_CHUNK_SIZE; + return buckets->rest_[rest_index][index % VECTOR_CHUNK_SIZE]; +} + +/* Helper function. */ +static inline size_t RestSize(const chunked_vector *vec) { + return (vec->size_ <= VECTOR_CHUNK_SIZE) + ? 0 + : (vec->size_ - VECTOR_CHUNK_SIZE - 1) / VECTOR_CHUNK_SIZE + 1; +} + +/* Initialize chunked vector to size of 0. */ +static void chunked_vector_init(chunked_vector *vec) { + vec->size_ = 0; + vec->first_ = NULL; + vec->rest_ = NULL; +} + +/* Clear chunked vector and free all memory that has been allocated then + initialize chunked vector. */ +static void chunked_vector_clear(chunked_vector *vec) { + if (vec->first_ != NULL) { + gpr_free(vec->first_); + } + if (vec->rest_ != NULL) { + size_t rest_size = RestSize(vec); + for (uint32_t i = 0; i < rest_size; ++i) { + if (vec->rest_[i] != NULL) { + gpr_free(vec->rest_[i]); + } + } + gpr_free(vec->rest_); + } + chunked_vector_init(vec); +} + +/* Clear chunked vector and then resize it to n entries. Allow the first 1MB to + be read w/o an extra cache miss. The rest of the elements are stored in an + array of arrays to avoid large mallocs. */ +static void chunked_vector_reset(chunked_vector *vec, size_t n) { + chunked_vector_clear(vec); + vec->size_ = n; + if (n <= VECTOR_CHUNK_SIZE) { + vec->first_ = (void **)gpr_malloc(sizeof(void *) * n); + memset(vec->first_, 0, sizeof(void *) * n); + } else { + vec->first_ = (void **)gpr_malloc(sizeof(void *) * VECTOR_CHUNK_SIZE); + memset(vec->first_, 0, sizeof(void *) * VECTOR_CHUNK_SIZE); + size_t rest_size = RestSize(vec); + vec->rest_ = (void ***)gpr_malloc(sizeof(void **) * rest_size); + memset(vec->rest_, 0, sizeof(void **) * rest_size); + int i = 0; + n -= VECTOR_CHUNK_SIZE; + while (n > 0) { + size_t this_size = GPR_MIN(n, VECTOR_CHUNK_SIZE); + vec->rest_[i] = (void **)gpr_malloc(sizeof(void *) * this_size); + memset(vec->rest_[i], 0, sizeof(void *) * this_size); + n -= this_size; + ++i; + } + } +} + +void intrusive_hash_map_init(intrusive_hash_map *hash_map, + uint32_t initial_log2_table_size) { + hash_map->log2_num_buckets = initial_log2_table_size; + hash_map->num_items = 0; + uint32_t num_buckets = (uint32_t)1 << hash_map->log2_num_buckets; + hash_map->extend_threshold = num_buckets >> 1; + chunked_vector_init(&hash_map->buckets); + chunked_vector_reset(&hash_map->buckets, num_buckets); + hash_map->hash_mask = num_buckets - 1; +} + +bool intrusive_hash_map_empty(const intrusive_hash_map *hash_map) { + return hash_map->num_items == 0; +} + +size_t intrusive_hash_map_size(const intrusive_hash_map *hash_map) { + return hash_map->num_items; +} + +void intrusive_hash_map_end(const intrusive_hash_map *hash_map, hm_index *idx) { + idx->bucket_index = (uint32_t)hash_map->buckets.size_; + GPR_ASSERT(idx->bucket_index <= UINT32_MAX); + idx->item = NULL; +} + +void intrusive_hash_map_next(const intrusive_hash_map *hash_map, + hm_index *idx) { + idx->item = idx->item->hash_link; + while (idx->item == NULL) { + idx->bucket_index++; + if (idx->bucket_index >= hash_map->buckets.size_) { + /* Reached end of table. */ + idx->item = NULL; + return; + } + idx->item = (hm_item *)get_bucket(&hash_map->buckets, idx->bucket_index); + } +} + +void intrusive_hash_map_begin(const intrusive_hash_map *hash_map, + hm_index *idx) { + for (uint32_t i = 0; i < hash_map->buckets.size_; ++i) { + if (get_bucket(&hash_map->buckets, i) != NULL) { + idx->bucket_index = i; + idx->item = (hm_item *)get_bucket(&hash_map->buckets, i); + return; + } + } + intrusive_hash_map_end(hash_map, idx); +} + +hm_item *intrusive_hash_map_find(const intrusive_hash_map *hash_map, + uint64_t key) { + uint32_t index = chunked_vector_hasher(key) & hash_map->hash_mask; + + hm_item *p = (hm_item *)get_bucket(&hash_map->buckets, index); + while (p != NULL) { + if (key == p->key) { + return p; + } + p = p->hash_link; + } + return NULL; +} + +hm_item *intrusive_hash_map_erase(intrusive_hash_map *hash_map, uint64_t key) { + uint32_t index = chunked_vector_hasher(key) & hash_map->hash_mask; + + hm_item **slot = (hm_item **)get_mutable_bucket(&hash_map->buckets, index); + hm_item *p = *slot; + if (p == NULL) { + return NULL; + } + + if (key == p->key) { + *slot = p->hash_link; + p->hash_link = NULL; + hash_map->num_items--; + return p; + } + + hm_item *prev = p; + p = p->hash_link; + + while (p) { + if (key == p->key) { + prev->hash_link = p->hash_link; + p->hash_link = NULL; + hash_map->num_items--; + return p; + } + prev = p; + p = p->hash_link; + } + return NULL; +} + +/* Insert an hm_item* into the underlying chunked vector. hash_mask is + * array_size-1. Returns true if it is a new hm_item and false if the hm_item + * already existed. + */ +static inline bool intrusive_hash_map_internal_insert(chunked_vector *buckets, + uint32_t hash_mask, + hm_item *item) { + const uint64_t key = item->key; + uint32_t index = chunked_vector_hasher(key) & hash_mask; + hm_item **slot = (hm_item **)get_mutable_bucket(buckets, index); + hm_item *p = *slot; + item->hash_link = p; + + /* Check to see if key already exists. */ + while (p) { + if (p->key == key) { + return false; + } + p = p->hash_link; + } + + /* Otherwise add new entry. */ + *slot = item; + return true; +} + +/* Extend the allocated number of elements in the hash map by a factor of 2. */ +void intrusive_hash_map_extend(intrusive_hash_map *hash_map) { + uint32_t new_log2_num_buckets = 1 + hash_map->log2_num_buckets; + uint32_t new_num_buckets = (uint32_t)1 << new_log2_num_buckets; + GPR_ASSERT(new_num_buckets <= UINT32_MAX && new_num_buckets > 0); + chunked_vector new_buckets; + chunked_vector_init(&new_buckets); + chunked_vector_reset(&new_buckets, new_num_buckets); + uint32_t new_hash_mask = new_num_buckets - 1; + + hm_index cur_idx; + hm_index end_idx; + intrusive_hash_map_end(hash_map, &end_idx); + intrusive_hash_map_begin(hash_map, &cur_idx); + while (!hm_index_compare(&cur_idx, &end_idx)) { + hm_item *new_item = cur_idx.item; + intrusive_hash_map_next(hash_map, &cur_idx); + intrusive_hash_map_internal_insert(&new_buckets, new_hash_mask, new_item); + } + + /* Set values for new chunked_vector. extend_threshold is set to half of + * new_num_buckets. */ + hash_map->log2_num_buckets = new_log2_num_buckets; + chunked_vector_clear(&hash_map->buckets); + hash_map->buckets = new_buckets; + hash_map->hash_mask = new_hash_mask; + hash_map->extend_threshold = new_num_buckets >> 1; +} + +/* Insert a hm_item. The hm_item must remain live until it is removed from the + table. This object does not take the ownership of hm_item. The caller must + remove this hm_item from the table and delete it before this table is + deleted. If hm_item exists already num_items is not changed. */ +bool intrusive_hash_map_insert(intrusive_hash_map *hash_map, hm_item *item) { + if (hash_map->num_items >= hash_map->extend_threshold) { + intrusive_hash_map_extend(hash_map); + } + if (intrusive_hash_map_internal_insert(&hash_map->buckets, + hash_map->hash_mask, item)) { + hash_map->num_items++; + return true; + } + return false; +} + +void intrusive_hash_map_clear(intrusive_hash_map *hash_map, + void (*free_object)(void *)) { + hm_index cur; + hm_index end; + intrusive_hash_map_end(hash_map, &end); + intrusive_hash_map_begin(hash_map, &cur); + + while (!hm_index_compare(&cur, &end)) { + hm_index next = cur; + intrusive_hash_map_next(hash_map, &next); + if (cur.item != NULL) { + hm_item *item = intrusive_hash_map_erase(hash_map, cur.item->key); + (*free_object)((void *)item); + gpr_free(item); + } + cur = next; + } +} + +void intrusive_hash_map_free(intrusive_hash_map *hash_map, + void (*free_object)(void *)) { + intrusive_hash_map_clear(hash_map, (*free_object)); + hash_map->num_items = 0; + hash_map->extend_threshold = 0; + hash_map->log2_num_buckets = 0; + hash_map->hash_mask = 0; + chunked_vector_clear(&hash_map->buckets); +} diff --git a/src/core/ext/census/intrusive_hash_map.h b/src/core/ext/census/intrusive_hash_map.h deleted file mode 120000 index 641ec396ddc..00000000000 --- a/src/core/ext/census/intrusive_hash_map.h +++ /dev/null @@ -1 +0,0 @@ -/google/src/cloud/jsking/cppTraceImpl/google3/experimental/users/jsking/intrusive_hash_map.h \ No newline at end of file diff --git a/src/core/ext/census/intrusive_hash_map.h b/src/core/ext/census/intrusive_hash_map.h new file mode 100644 index 00000000000..900e4368c96 --- /dev/null +++ b/src/core/ext/census/intrusive_hash_map.h @@ -0,0 +1,169 @@ +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H +#define GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H + +#include +#include +#include +#include + +/* intrusive_hash_map is a fast chained hash table. It is almost always faster + * than STL hash_map, since this hash map avoids malloc and free during insert + * and erase. This hash map is faster than a dense hash map when the application + * calls insert and erase more often than find. When the workload is dominated + * by find() a dense hash map may be faster. + * + * intrusive_hash_map uses an intrusive header placed within a user defined + * struct. IHM_key MUST be set to a valid value before insertion into the hash + * map or undefined behavior may occur. IHM_hash_link needs to be set to NULL + * initially. + * + * EXAMPLE USAGE: + * + * typedef struct string_item { + * INTRUSIVE_HASH_MAP_HEADER; + * // User data. + * char *str_buf; + * uint16_t len; + * } string_item; + * + * static string_item *make_string_item(uint64_t key, const char *buf, + * uint16_t len) { + * string_item *item = (string_item *)gpr_malloc(sizeof(string_item)); + * item->IHM_key = key; + * item->IHM_hash_link = NULL; + * item->len = len; + * item->str_buf = (char *)malloc(len); + * memcpy(item->str_buf, buf, len); + * return item; + * } + * + * string_item *new_item1 = make_string_item(10, "test1", 5); + * bool ok = intrusive_hash_map_insert(&hash_map, (hm_item *)new_item1); + * + * string_item *item1 = + * (string_item *)intrusive_hash_map_find(&hash_map, 10); + */ + +/* Hash map item. Stores key and a pointer to the actual object. A user defined + * version of this can be passed in as long as the first 2 entries (key and + * hash_link) are the same. Pointer to struct will need to be cast as + * (hm_item *) when passed to hash map. This allows it to be intrusive. */ +typedef struct hm_item { + uint64_t key; + struct hm_item *hash_link; + /* Optional user defined data after this. */ +} hm_item; + +/* Macro provided for ease of use. This must be first in the user defined + * struct. */ +#define INTRUSIVE_HASH_MAP_HEADER \ + uint64_t IHM_key; \ + struct hm_item *IHM_hash_link + +/* The chunked vector is a data structure that allocates buckets for use in the + * hash map. ChunkedVector is logically equivalent to T*[N] (cast void* as + * T*). It's internally implemented as an array of 1MB arrays to avoid + * allocating large consecutive memory chunks. This is an internal data + * structure that should never be accessed directly. */ +typedef struct chunked_vector { + size_t size_; + void **first_; + void ***rest_; +} chunked_vector; + +/* Core intrusive hash map data structure. All internal elements are managed by + * functions and should not be altered manually. intrusive_hash_map_init() + * must first be called before an intrusive_hash_map can be used. */ +typedef struct intrusive_hash_map { + uint32_t num_items; + uint32_t extend_threshold; + uint32_t log2_num_buckets; + uint32_t hash_mask; + chunked_vector buckets; +} intrusive_hash_map; + +/* Index struct which acts as a pseudo-iterator within the hash map. */ +typedef struct hm_index { + uint32_t bucket_index; // hash map bucket index. + hm_item *item; // Pointer to hm_item within the hash map. +} hm_index; + +/* Returns true if two hm_indices point to the same object within the hash map + * and false otherwise. */ +inline bool hm_index_compare(const hm_index *A, const hm_index *B) { + return (A->item == B->item && A->bucket_index == B->bucket_index); +} + +/* Helper functions for iterating over the hash map. */ +/* On return idx will contain an invalid index which is always equal to + * hash_map->buckets.size_ */ +void intrusive_hash_map_end(const intrusive_hash_map *hash_map, hm_index *idx); + +/* Iterates index to the next valid entry in the hash map and stores the + * index within idx. If end of table is reached, idx will contain the same + * values as if intrusive_hash_map_end() was called. */ +void intrusive_hash_map_next(const intrusive_hash_map *hash_map, hm_index *idx); + +/* On return, idx will contain the index of the first non-null entry in the hash + * map. If the hash map is empty, idx will contain the same values as if + * intrusive_hash_map_end() was called. */ +void intrusive_hash_map_begin(const intrusive_hash_map *hash_map, + hm_index *idx); + +/* Initialize intrusive hash map data structure. This must be called before + * the hash map can be used. The initial size of an intrusive hash map will be + * 2^initial_log2_map_size (valid range is [0, 31]). */ +void intrusive_hash_map_init(intrusive_hash_map *hash_map, + uint32_t initial_log2_map_size); + +/* Returns true if the hash map is empty and false otherwise. */ +bool intrusive_hash_map_empty(const intrusive_hash_map *hash_map); + +/* Returns the number of elements currently in the hash map. */ +size_t intrusive_hash_map_size(const intrusive_hash_map *hash_map); + +/* Find a hm_item within the hash map by key. Returns NULL if item was not + * found. */ +hm_item *intrusive_hash_map_find(const intrusive_hash_map *hash_map, + uint64_t key); + +/* Erase the hm_item that corresponds with key. If the hm_item is found, return + * the pointer to the hm_item. Else returns NULL. */ +hm_item *intrusive_hash_map_erase(intrusive_hash_map *hash_map, uint64_t key); + +/* Attempts to insert a new hm_item into the hash map. If an element with the + * same key already exists, it will not insert the new item and return false. + * Otherwise, it will insert the new item and return true. */ +bool intrusive_hash_map_insert(intrusive_hash_map *hash_map, hm_item *item); + +/* Clear entire contents of the hash map, but leaves internal data structure + * untouched. Second argument takes a function pointer to a method that will + * free the object designated by the user and pointed to by hash_map->value. */ +void intrusive_hash_map_clear(intrusive_hash_map *hash_map, + void (*free_object)(void *)); + +/* Erase all contents of hash map and free the memory. Hash map is invalid + * after calling this function and cannot be used until it has been + * reinitialized (intrusive_hash_map_init()). takes a function pointer to a + * method that will free the object designated by the user and pointed to by + * hash_map->value.*/ +void intrusive_hash_map_free(intrusive_hash_map *hash_map, + void (*free_object)(void *)); + +#endif diff --git a/test/core/census/intrusive_hash_map_test.c b/test/core/census/intrusive_hash_map_test.c deleted file mode 120000 index a790afe1975..00000000000 --- a/test/core/census/intrusive_hash_map_test.c +++ /dev/null @@ -1 +0,0 @@ -/google/src/cloud/jsking/cppTraceImpl/google3/experimental/users/jsking/intrusive_hash_map_test.c \ No newline at end of file diff --git a/test/core/census/intrusive_hash_map_test.c b/test/core/census/intrusive_hash_map_test.c new file mode 100644 index 00000000000..87d514a08cb --- /dev/null +++ b/test/core/census/intrusive_hash_map_test.c @@ -0,0 +1,272 @@ +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "src/core/ext/census/intrusive_hash_map.h" + +#include +#include +#include "test/core/util/test_config.h" + +#include +#include +#include +#include + +/* The initial size of an intrusive hash map will be 2 to this power. */ +static const uint32_t kInitialLog2Size = 4; + +typedef struct object { uint64_t val; } object; + +inline object *make_new_object(uint64_t val) { + object *obj = (object *)gpr_malloc(sizeof(object)); + obj->val = val; + return obj; +} + +typedef struct ptr_item { + INTRUSIVE_HASH_MAP_HEADER; + object *obj; +} ptr_item; + +/* Helper function that creates a new hash map item. It is up to the user to + * free the item that was allocated. */ +inline ptr_item *make_ptr_item(uint64_t key, uint64_t value) { + ptr_item *new_item = (ptr_item *)gpr_malloc(sizeof(ptr_item)); + new_item->IHM_key = key; + new_item->IHM_hash_link = NULL; + new_item->obj = make_new_object(value); + return new_item; +} + +static void free_ptr_item(void *ptr) { gpr_free(((ptr_item *)ptr)->obj); } + +typedef struct string_item { + INTRUSIVE_HASH_MAP_HEADER; + // User data. + char buf[32]; + uint16_t len; +} string_item; + +static string_item *make_string_item(uint64_t key, const char *buf, + uint16_t len) { + string_item *item = (string_item *)gpr_malloc(sizeof(string_item)); + item->IHM_key = key; + item->IHM_hash_link = NULL; + item->len = len; + memcpy(item->buf, buf, sizeof(char) * len); + return item; +} + +static bool compare_string_item(const string_item *A, const string_item *B) { + if (A->IHM_key != B->IHM_key || A->len != B->len) + return false; + else { + for (int i = 0; i < A->len; ++i) { + if (A->buf[i] != B->buf[i]) return false; + } + } + + return true; +} + +void test_empty() { + intrusive_hash_map hash_map; + intrusive_hash_map_init(&hash_map, kInitialLog2Size); + GPR_ASSERT(0 == intrusive_hash_map_size(&hash_map)); + GPR_ASSERT(intrusive_hash_map_empty(&hash_map)); + intrusive_hash_map_free(&hash_map, NULL); +} + +void test_basic() { + intrusive_hash_map hash_map; + intrusive_hash_map_init(&hash_map, kInitialLog2Size); + + ptr_item *new_item = make_ptr_item(10, 20); + bool ok = intrusive_hash_map_insert(&hash_map, (hm_item *)new_item); + GPR_ASSERT(ok); + + ptr_item *item1 = + (ptr_item *)intrusive_hash_map_find(&hash_map, (uint64_t)10); + GPR_ASSERT(item1->obj->val == 20); + GPR_ASSERT(item1 == new_item); + + ptr_item *item2 = + (ptr_item *)intrusive_hash_map_erase(&hash_map, (uint64_t)10); + GPR_ASSERT(item2 == new_item); + + gpr_free(new_item->obj); + gpr_free(new_item); + GPR_ASSERT(0 == intrusive_hash_map_size(&hash_map)); + intrusive_hash_map_free(&hash_map, &free_ptr_item); +} + +void test_basic2() { + intrusive_hash_map hash_map; + intrusive_hash_map_init(&hash_map, kInitialLog2Size); + + string_item *new_item1 = make_string_item(10, "test1", 5); + bool ok = intrusive_hash_map_insert(&hash_map, (hm_item *)new_item1); + GPR_ASSERT(ok); + string_item *new_item2 = make_string_item(20, "test2", 5); + ok = intrusive_hash_map_insert(&hash_map, (hm_item *)new_item2); + GPR_ASSERT(ok); + + string_item *item1 = + (string_item *)intrusive_hash_map_find(&hash_map, (uint64_t)10); + GPR_ASSERT(compare_string_item(new_item1, item1)); + GPR_ASSERT(item1 == new_item1); + string_item *item2 = + (string_item *)intrusive_hash_map_find(&hash_map, (uint64_t)20); + GPR_ASSERT(compare_string_item(new_item2, item2)); + GPR_ASSERT(item2 == new_item2); + + item1 = (string_item *)intrusive_hash_map_erase(&hash_map, (uint64_t)10); + GPR_ASSERT(item1 == new_item1); + item2 = (string_item *)intrusive_hash_map_erase(&hash_map, (uint64_t)20); + GPR_ASSERT(item2 == new_item2); + + gpr_free(new_item1); + gpr_free(new_item2); + GPR_ASSERT(0 == intrusive_hash_map_size(&hash_map)); + intrusive_hash_map_free(&hash_map, NULL); +} + +// Test resetting and clearing the hash map. +void test_reset_clear() { + intrusive_hash_map hash_map; + intrusive_hash_map_init(&hash_map, kInitialLog2Size); + + // Add some data to the hash_map. + for (uint64_t i = 0; i < 3; ++i) { + intrusive_hash_map_insert(&hash_map, (hm_item *)make_ptr_item(i, i)); + } + GPR_ASSERT(3 == intrusive_hash_map_size(&hash_map)); + + // Test find. + for (uint64_t i = 0; i < 3; ++i) { + ptr_item *item = (ptr_item *)intrusive_hash_map_find(&hash_map, i); + GPR_ASSERT(item != NULL); + GPR_ASSERT(item->IHM_key == i && item->obj->val == i); + } + + intrusive_hash_map_clear(&hash_map, &free_ptr_item); + GPR_ASSERT(intrusive_hash_map_empty(&hash_map)); + intrusive_hash_map_free(&hash_map, &free_ptr_item); +} + +// Check that the hash_map contains every key between [min_value, max_value] +// (inclusive). +void check_hash_map_values(intrusive_hash_map *hash_map, uint64_t min_value, + uint64_t max_value) { + GPR_ASSERT(intrusive_hash_map_size(hash_map) == max_value - min_value + 1); + + for (uint64_t i = min_value; i <= max_value; ++i) { + ptr_item *item = (ptr_item *)intrusive_hash_map_find(hash_map, i); + GPR_ASSERT(item != NULL); + GPR_ASSERT(item->obj->val == i); + } +} + +// Add many items and cause the hash_map to extend. +void test_extend() { + intrusive_hash_map hash_map; + intrusive_hash_map_init(&hash_map, kInitialLog2Size); + + const uint64_t kNumValues = (1 << 16); + + for (uint64_t i = 0; i < kNumValues; ++i) { + ptr_item *item = make_ptr_item(i, i); + bool ok = intrusive_hash_map_insert(&hash_map, (hm_item *)item); + GPR_ASSERT(ok); + if (i % 1000 == 0) { + check_hash_map_values(&hash_map, 0, i); + } + } + + for (uint64_t i = 0; i < kNumValues; ++i) { + ptr_item *item = (ptr_item *)intrusive_hash_map_find(&hash_map, i); + GPR_ASSERT(item != NULL); + GPR_ASSERT(item->IHM_key == i && item->obj->val == i); + ptr_item *item2 = (ptr_item *)intrusive_hash_map_erase(&hash_map, i); + GPR_ASSERT(item == item2); + gpr_free(item->obj); + gpr_free(item); + } + + GPR_ASSERT(intrusive_hash_map_empty(&hash_map)); + intrusive_hash_map_free(&hash_map, &free_ptr_item); +} + +void test_stress() { + intrusive_hash_map hash_map; + intrusive_hash_map_init(&hash_map, kInitialLog2Size); + size_t n = 0; + + for (uint64_t i = 0; i < 1000000; ++i) { + int op = rand() & 0x1; + + switch (op) { + case 0: { + uint64_t key = (uint64_t)(rand() % 10000); + ptr_item *item = make_ptr_item(key, key); + bool ok = intrusive_hash_map_insert(&hash_map, (hm_item *)item); + if (ok) { + n++; + } else { + gpr_free(item->obj); + gpr_free(item); + } + break; + } + case 1: { + uint64_t key = (uint64_t)(rand() % 10000); + ptr_item *item = (ptr_item *)intrusive_hash_map_find(&hash_map, key); + if (item != NULL) { + n--; + GPR_ASSERT(key == item->obj->val); + ptr_item *item2 = + (ptr_item *)intrusive_hash_map_erase(&hash_map, key); + GPR_ASSERT(item == item2); + gpr_free(item->obj); + gpr_free(item); + } + break; + } + } + } + // Check size + GPR_ASSERT(n == intrusive_hash_map_size(&hash_map)); + + // Clean the hash_map up. + intrusive_hash_map_clear(&hash_map, &free_ptr_item); + GPR_ASSERT(intrusive_hash_map_empty(&hash_map)); + intrusive_hash_map_free(&hash_map, &free_ptr_item); +} + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + gpr_time_init(); + srand((unsigned)gpr_now(GPR_CLOCK_REALTIME).tv_nsec); + + test_empty(); + test_basic(); + test_basic2(); + test_reset_clear(); + test_extend(); + test_stress(); + + return 0; +} From 22cc52aa9b1db9514abcaf88345938f543c1fca3 Mon Sep 17 00:00:00 2001 From: jiangtaoli2016 Date: Fri, 28 Apr 2017 17:35:35 -0700 Subject: [PATCH 05/65] Bug fix --- .../lib/http/httpcli_security_connector.c | 4 +- .../security/transport/security_handshaker.c | 71 +++++++++---------- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/core/lib/http/httpcli_security_connector.c b/src/core/lib/http/httpcli_security_connector.c index 76946434f06..ea7c1122c17 100644 --- a/src/core/lib/http/httpcli_security_connector.c +++ b/src/core/lib/http/httpcli_security_connector.c @@ -44,6 +44,7 @@ #include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/support/string.h" #include "src/core/tsi/ssl_transport_security.h" +#include "src/core/tsi/transport_security_adapter.h" typedef struct { grpc_channel_security_connector base; @@ -78,7 +79,8 @@ static void httpcli_ssl_add_handshakers(grpc_exec_ctx *exec_ctx, } grpc_handshake_manager_add( handshake_mgr, - grpc_security_handshaker_create(exec_ctx, handshaker, &sc->base)); + grpc_security_handshaker_create( + exec_ctx, tsi_create_adapter_handshaker(handshaker), &sc->base)); } static void httpcli_ssl_check_peer(grpc_exec_ctx *exec_ctx, diff --git a/src/core/lib/security/transport/security_handshaker.c b/src/core/lib/security/transport/security_handshaker.c index 16c3c6e14d4..ea1fb304977 100644 --- a/src/core/lib/security/transport/security_handshaker.c +++ b/src/core/lib/security/transport/security_handshaker.c @@ -154,19 +154,19 @@ static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *arg, } // Create frame protector. tsi_frame_protector *protector; - tsi_result status = tsi_handshaker_result_create_frame_protector( + tsi_result result = tsi_handshaker_result_create_frame_protector( h->handshaker_result, NULL, &protector); - if (status != TSI_OK) { + if (result != TSI_OK) { error = grpc_set_tsi_error_result( GRPC_ERROR_CREATE_FROM_STATIC_STRING("Frame protector creation failed"), - status); + result); security_handshake_failed_locked(exec_ctx, h, error); goto done; } // Get unused bytes. unsigned char *unused_bytes = NULL; size_t unused_bytes_size = 0; - status = tsi_handshaker_result_get_unused_bytes( + result = tsi_handshaker_result_get_unused_bytes( h->handshaker_result, &unused_bytes, &unused_bytes_size); if (unused_bytes_size > 0) { gpr_slice slice = @@ -202,11 +202,11 @@ done: static grpc_error *check_peer_locked(grpc_exec_ctx *exec_ctx, security_handshaker *h) { tsi_peer peer; - tsi_result status = + tsi_result result = tsi_handshaker_result_extract_peer(h->handshaker_result, &peer); - if (status != TSI_OK) { + if (result != TSI_OK) { return grpc_set_tsi_error_result( - GRPC_ERROR_CREATE_FROM_STATIC_STRING("Peer extraction failed"), status); + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Peer extraction failed"), result); } grpc_security_connector_check_peer(exec_ctx, h->connector, peer, &h->auth_context, &h->on_peer_checked); @@ -214,51 +214,49 @@ static grpc_error *check_peer_locked(grpc_exec_ctx *exec_ctx, } static grpc_error *on_handshake_next_done_locked( - grpc_exec_ctx *exec_ctx, security_handshaker *h, tsi_result status, + grpc_exec_ctx *exec_ctx, security_handshaker *h, tsi_result result, const unsigned char *bytes_to_send, size_t bytes_to_send_size, - tsi_handshaker_result *result) { + tsi_handshaker_result *handshaker_result) { grpc_error *error = GRPC_ERROR_NONE; // Read more if we need to. - if (status == TSI_INCOMPLETE_DATA) { + if (result == TSI_INCOMPLETE_DATA) { GPR_ASSERT(bytes_to_send_size == 0); grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, &h->on_handshake_data_received_from_peer); return error; } - - if (status != TSI_OK) { + if (result != TSI_OK) { return grpc_set_tsi_error_result( - GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake failed"), status); + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake failed"), result); } - // If there are data to send to the peer, send data. - if (bytes_to_send_size > 0) { - grpc_slice to_send = grpc_slice_from_copied_buffer( - (const char *)bytes_to_send, bytes_to_send_size); - grpc_slice_buffer_reset_and_unref(&h->outgoing); - grpc_slice_buffer_add(&h->outgoing, to_send); - grpc_endpoint_write(exec_ctx, h->args->endpoint, &h->outgoing, - &h->on_handshake_data_sent_to_peer); - } + // Send data to peer. + grpc_slice to_send = grpc_slice_from_copied_buffer( + (const char *)bytes_to_send, bytes_to_send_size); + grpc_slice_buffer_reset_and_unref(&h->outgoing); + grpc_slice_buffer_add(&h->outgoing, to_send); + grpc_endpoint_write(exec_ctx, h->args->endpoint, &h->outgoing, + &h->on_handshake_data_sent_to_peer); // If handshake has completed, check peer and so on. - if (result != NULL) { - h->handshaker_result = result; + if (handshaker_result != NULL) { + h->handshaker_result = handshaker_result; error = check_peer_locked(exec_ctx, h); } return error; } static void on_handshake_next_done_grpc_wrapper( - tsi_result status, void *user_data, const unsigned char *bytes_to_send, - size_t bytes_to_send_size, tsi_handshaker_result *result) { + tsi_result result, void *user_data, const unsigned char *bytes_to_send, + size_t bytes_to_send_size, tsi_handshaker_result *handshaker_result) { security_handshaker *h = user_data; // This callback will be invoked by TSI in a non-grpc thread, so it's // safe to create our own exec_ctx here. grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; gpr_mu_lock(&h->mu); - grpc_error *error = on_handshake_next_done_locked( - &exec_ctx, h, status, bytes_to_send, bytes_to_send_size, result); + grpc_error *error = + on_handshake_next_done_locked(&exec_ctx, h, result, bytes_to_send, + bytes_to_send_size, handshaker_result); if (error != GRPC_ERROR_NONE) { security_handshake_failed_locked(&exec_ctx, h, error); gpr_mu_unlock(&h->mu); @@ -275,19 +273,20 @@ static grpc_error *do_handshaker_next_locked( // Invoke TSI handshaker. unsigned char *bytes_to_send = NULL; size_t bytes_to_send_size = 0; - tsi_handshaker_result *result = NULL; - tsi_result status = tsi_handshaker_next( + tsi_handshaker_result *handshaker_result = NULL; + tsi_result result = tsi_handshaker_next( h->handshaker, bytes_received, bytes_received_size, &bytes_to_send, - &bytes_to_send_size, &result, &on_handshake_next_done_grpc_wrapper, h); - if (status == TSI_ASYNC) { + &bytes_to_send_size, &handshaker_result, + &on_handshake_next_done_grpc_wrapper, h); + if (result == TSI_ASYNC) { // Handshaker operating asynchronously. Nothing else to do here; // callback will be invoked in a TSI thread. return GRPC_ERROR_NONE; } // Handshaker returned synchronously. Invoke callback directly in // this thread with our existing exec_ctx. - return on_handshake_next_done_locked(exec_ctx, h, status, bytes_to_send, - bytes_to_send_size, result); + return on_handshake_next_done_locked(exec_ctx, h, result, bytes_to_send, + bytes_to_send_size, handshaker_result); } static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, @@ -344,9 +343,7 @@ static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *arg, security_handshaker_unref(exec_ctx, h); return; } - if (h->handshaker_result != NULL) { - check_peer_locked(exec_ctx, h); - } else { + if (h->handshaker_result == NULL) { grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, &h->on_handshake_data_received_from_peer); } From 30f2a40f1012a8c7b5311e914b915b947b9f8f9b Mon Sep 17 00:00:00 2001 From: jiangtaoli2016 Date: Fri, 5 May 2017 09:50:52 -0700 Subject: [PATCH 06/65] Address Julien's comment and clang format --- .../security/transport/security_connector.c | 20 +++++++++---------- .../security/transport/security_handshaker.c | 5 +++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/core/lib/security/transport/security_connector.c b/src/core/lib/security/transport/security_connector.c index 7dbed1c1e8e..416a3bdb358 100644 --- a/src/core/lib/security/transport/security_connector.c +++ b/src/core/lib/security/transport/security_connector.c @@ -389,22 +389,22 @@ static void fake_channel_add_handshakers( grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, grpc_handshake_manager *handshake_mgr) { grpc_handshake_manager_add( - handshake_mgr, grpc_security_handshaker_create( - exec_ctx, - tsi_create_adapter_handshaker( - tsi_create_fake_handshaker(true /* is_client */)), - &sc->base)); + handshake_mgr, + grpc_security_handshaker_create( + exec_ctx, tsi_create_adapter_handshaker( + tsi_create_fake_handshaker(true /* is_client */)), + &sc->base)); } static void fake_server_add_handshakers(grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc, grpc_handshake_manager *handshake_mgr) { grpc_handshake_manager_add( - handshake_mgr, grpc_security_handshaker_create( - exec_ctx, - tsi_create_adapter_handshaker( - tsi_create_fake_handshaker(false /* is_client */)), - &sc->base)); + handshake_mgr, + grpc_security_handshaker_create( + exec_ctx, tsi_create_adapter_handshaker( + tsi_create_fake_handshaker(false /* is_client */)), + &sc->base)); } static grpc_security_connector_vtable fake_channel_vtable = { diff --git a/src/core/lib/security/transport/security_handshaker.c b/src/core/lib/security/transport/security_handshaker.c index ea1fb304977..7a4dc6475e4 100644 --- a/src/core/lib/security/transport/security_handshaker.c +++ b/src/core/lib/security/transport/security_handshaker.c @@ -233,13 +233,14 @@ static grpc_error *on_handshake_next_done_locked( // Send data to peer. grpc_slice to_send = grpc_slice_from_copied_buffer( (const char *)bytes_to_send, bytes_to_send_size); - grpc_slice_buffer_reset_and_unref(&h->outgoing); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &h->outgoing); grpc_slice_buffer_add(&h->outgoing, to_send); grpc_endpoint_write(exec_ctx, h->args->endpoint, &h->outgoing, &h->on_handshake_data_sent_to_peer); // If handshake has completed, check peer and so on. if (handshaker_result != NULL) { + GPR_ASSERT(h->handshaker_result == NULL); h->handshaker_result = handshaker_result; error = check_peer_locked(exec_ctx, h); } @@ -301,7 +302,7 @@ static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, security_handshaker_unref(exec_ctx, h); return; } - // Copy all slides received. + // Copy all slices received. size_t i; size_t bytes_received_size = 0; for (i = 0; i < h->args->read_buffer->count; i++) { From 8a507811ff14502131474eb3bf799c14419579a6 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Mon, 8 May 2017 16:30:12 +0200 Subject: [PATCH 07/65] C# workaround for unavailable on idle channels --- src/csharp/Grpc.Core/Channel.cs | 41 ++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs index 4f29c35b321..51ae11fbdec 100644 --- a/src/csharp/Grpc.Core/Channel.cs +++ b/src/csharp/Grpc.Core/Channel.cs @@ -59,6 +59,8 @@ namespace Grpc.Core readonly ChannelSafeHandle handle; readonly Dictionary options; + readonly Task connectivityWatcherTask; + bool shutdownRequested; /// @@ -99,6 +101,9 @@ namespace Grpc.Core this.handle = ChannelSafeHandle.CreateInsecure(target, nativeChannelArgs); } } + // TODO(jtattermusch): Workaround for https://github.com/GoogleCloudPlatform/google-cloud-dotnet/issues/822. + // Remove once retries are supported in C core + this.connectivityWatcherTask = RunConnectivityWatcherAsync(); GrpcEnvironment.RegisterChannel(this); } @@ -244,7 +249,7 @@ namespace Grpc.Core handle.Dispose(); - await GrpcEnvironment.ReleaseAsync().ConfigureAwait(false); + await Task.WhenAll(GrpcEnvironment.ReleaseAsync(), connectivityWatcherTask).ConfigureAwait(false); } internal ChannelSafeHandle Handle @@ -299,6 +304,40 @@ namespace Grpc.Core } } + /// + /// Constantly Watches channel connectivity status to work around https://github.com/GoogleCloudPlatform/google-cloud-dotnet/issues/822 + /// + private async Task RunConnectivityWatcherAsync() + { + try + { + var lastState = State; + while (lastState != ChannelState.Shutdown) + { + lock (myLock) + { + if (shutdownRequested) + { + break; + } + } + + try + { + await WaitForStateChangedAsync(lastState, DateTime.UtcNow.AddSeconds(1)).ConfigureAwait(false); + } + catch (TaskCanceledException) + { + // ignore timeout + } + lastState = State; + } + } + catch (ObjectDisposedException) { + // during shutdown, channel is going to be disposed. + } + } + private static void EnsureUserAgentChannelOption(Dictionary options) { var key = ChannelOptions.PrimaryUserAgentString; From a194aab223af6558713b6482976a407b816ce15a Mon Sep 17 00:00:00 2001 From: Vizerai Date: Mon, 8 May 2017 19:43:25 -0700 Subject: [PATCH 08/65] update --- test/core/census/intrusive_hash_map_test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/core/census/intrusive_hash_map_test.c b/test/core/census/intrusive_hash_map_test.c index 87d514a08cb..d35a01e1032 100644 --- a/test/core/census/intrusive_hash_map_test.c +++ b/test/core/census/intrusive_hash_map_test.c @@ -30,7 +30,7 @@ static const uint32_t kInitialLog2Size = 4; typedef struct object { uint64_t val; } object; -inline object *make_new_object(uint64_t val) { +static inline object *make_new_object(uint64_t val) { object *obj = (object *)gpr_malloc(sizeof(object)); obj->val = val; return obj; @@ -43,7 +43,7 @@ typedef struct ptr_item { /* Helper function that creates a new hash map item. It is up to the user to * free the item that was allocated. */ -inline ptr_item *make_ptr_item(uint64_t key, uint64_t value) { +static inline ptr_item *make_ptr_item(uint64_t key, uint64_t value) { ptr_item *new_item = (ptr_item *)gpr_malloc(sizeof(ptr_item)); new_item->IHM_key = key; new_item->IHM_hash_link = NULL; From b2c0b7bc7411c0914e2f65d56096ecde1a207b53 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Thu, 27 Apr 2017 00:26:25 -0700 Subject: [PATCH 09/65] constant state watch without timeouts --- src/ruby/end2end/channel_closing_driver.rb | 5 + src/ruby/end2end/channel_state_driver.rb | 3 + src/ruby/end2end/grpc_class_init_client.rb | 65 ++- src/ruby/end2end/grpc_class_init_driver.rb | 51 +- .../sig_int_during_channel_watch_client.rb | 2 + .../sig_int_during_channel_watch_driver.rb | 5 + src/ruby/ext/grpc/rb_call.c | 2 +- src/ruby/ext/grpc/rb_channel.c | 494 ++++++++++++------ src/ruby/ext/grpc/rb_completion_queue.c | 14 +- src/ruby/ext/grpc/rb_completion_queue.h | 2 +- src/ruby/ext/grpc/rb_event_thread.c | 12 +- src/ruby/ext/grpc/rb_server.c | 2 +- src/ruby/spec/channel_connection_spec.rb | 35 +- 13 files changed, 472 insertions(+), 220 deletions(-) diff --git a/src/ruby/end2end/channel_closing_driver.rb b/src/ruby/end2end/channel_closing_driver.rb index d3e5373b0bb..bed8c434058 100755 --- a/src/ruby/end2end/channel_closing_driver.rb +++ b/src/ruby/end2end/channel_closing_driver.rb @@ -61,6 +61,11 @@ def main 'channel is closed while connectivity is watched' end + client_exit_code = $CHILD_STATUS + if client_exit_code != 0 + fail "channel closing client failed, exit code #{client_exit_code}" + end + server_runner.stop end diff --git a/src/ruby/end2end/channel_state_driver.rb b/src/ruby/end2end/channel_state_driver.rb index 80fb62899e5..9910076dba1 100755 --- a/src/ruby/end2end/channel_state_driver.rb +++ b/src/ruby/end2end/channel_state_driver.rb @@ -58,6 +58,9 @@ def main 'It likely hangs when ended abruptly' end + # The interrupt in the child process should cause it to + # exit a non-zero status, so don't check it here. + # This test mainly tries to catch deadlock. server_runner.stop end diff --git a/src/ruby/end2end/grpc_class_init_client.rb b/src/ruby/end2end/grpc_class_init_client.rb index ee79292119a..8e46907368f 100755 --- a/src/ruby/end2end/grpc_class_init_client.rb +++ b/src/ruby/end2end/grpc_class_init_client.rb @@ -34,44 +34,81 @@ require_relative './end2end_common' -def main - grpc_class = '' - OptionParser.new do |opts| - opts.on('--grpc_class=P', String) do |p| - grpc_class = p +def construct_many(test_proc) + thds = [] + 4.times do + thds << Thread.new do + 20.times do + test_proc.call + end end - end.parse! + end + 20.times do + test_proc.call + end + thds.each(&:join) +end + +def run_gc_stress_test(test_proc) + GC.disable + construct_many(test_proc) - test_proc = nil + GC.enable + construct_many(test_proc) + GC.start(full_mark: true, immediate_sweep: true) + construct_many(test_proc) +end + +def get_test_proc(grpc_class) case grpc_class when 'channel' - test_proc = proc do + return proc do GRPC::Core::Channel.new('dummy_host', nil, :this_channel_is_insecure) end when 'server' - test_proc = proc do + return proc do GRPC::Core::Server.new({}) end when 'channel_credentials' - test_proc = proc do + return proc do GRPC::Core::ChannelCredentials.new end when 'call_credentials' - test_proc = proc do + return proc do GRPC::Core::CallCredentials.new(proc { |noop| noop }) end when 'compression_options' - test_proc = proc do + return proc do GRPC::Core::CompressionOptions.new end else fail "bad --grpc_class=#{grpc_class} param" end +end + +def main + grpc_class = '' + gc_stress = false + OptionParser.new do |opts| + opts.on('--grpc_class=P', String) do |p| + grpc_class = p + end + opts.on('--gc_stress=P') do |p| + gc_stress = p + end + end.parse! + + test_proc = get_test_proc(grpc_class) + + if gc_stress == 'true' + run_gc_stress_test(test_proc) + return + end - th = Thread.new { test_proc.call } + thd = Thread.new { test_proc.call } test_proc.call - th.join + thd.join end main diff --git a/src/ruby/end2end/grpc_class_init_driver.rb b/src/ruby/end2end/grpc_class_init_driver.rb index 764d029f149..0e330a493f5 100755 --- a/src/ruby/end2end/grpc_class_init_driver.rb +++ b/src/ruby/end2end/grpc_class_init_driver.rb @@ -38,29 +38,38 @@ def main call_credentials compression_options ) - native_grpc_classes.each do |grpc_class| - STDERR.puts 'start client' - this_dir = File.expand_path(File.dirname(__FILE__)) - client_path = File.join(this_dir, 'grpc_class_init_client.rb') - client_pid = Process.spawn(RbConfig.ruby, - client_path, - "--grpc_class=#{grpc_class}") - begin - Timeout.timeout(10) do - Process.wait(client_pid) + # there is room for false positives in this test, + # do 10 runs for each config to reduce these. + [true, false].each do |gc_stress| + 10.times do + native_grpc_classes.each do |grpc_class| + STDERR.puts 'start client' + this_dir = File.expand_path(File.dirname(__FILE__)) + client_path = File.join(this_dir, 'grpc_class_init_client.rb') + client_pid = Process.spawn(RbConfig.ruby, + client_path, + "--grpc_class=#{grpc_class}", + "--gc_stress=#{gc_stress}") + begin + Timeout.timeout(10) do + Process.wait(client_pid) + end + rescue Timeout::Error + STDERR.puts "timeout waiting for client pid #{client_pid}" + Process.kill('SIGKILL', client_pid) + Process.wait(client_pid) + STDERR.puts 'killed client child' + raise 'Timed out waiting for client process. ' \ + 'It likely hangs when the first constructed gRPC object has ' \ + "type: #{grpc_class}" + end + + client_exit_code = $CHILD_STATUS + if client_exit_code != 0 + fail "client failed, exit code #{client_exit_code}" + end end - rescue Timeout::Error - STDERR.puts "timeout waiting for client pid #{client_pid}" - Process.kill('SIGKILL', client_pid) - Process.wait(client_pid) - STDERR.puts 'killed client child' - raise 'Timed out waiting for client process. ' \ - 'It likely hangs when the first constructed gRPC object has ' \ - "type: #{grpc_class}" end - - client_exit_code = $CHILD_STATUS - fail "client failed, exit code #{client_exit_code}" if client_exit_code != 0 end end diff --git a/src/ruby/end2end/sig_int_during_channel_watch_client.rb b/src/ruby/end2end/sig_int_during_channel_watch_client.rb index 389fc5ba332..0c6a3749254 100755 --- a/src/ruby/end2end/sig_int_during_channel_watch_client.rb +++ b/src/ruby/end2end/sig_int_during_channel_watch_client.rb @@ -46,6 +46,8 @@ def main end end.parse! + trap('SIGINT') { exit 0 } + thd = Thread.new do child_thread_channel = GRPC::Core::Channel.new("localhost:#{server_port}", {}, diff --git a/src/ruby/end2end/sig_int_during_channel_watch_driver.rb b/src/ruby/end2end/sig_int_during_channel_watch_driver.rb index 670cda0919f..79a8c133fa8 100755 --- a/src/ruby/end2end/sig_int_during_channel_watch_driver.rb +++ b/src/ruby/end2end/sig_int_during_channel_watch_driver.rb @@ -63,6 +63,11 @@ def main 'SIGINT is sent while there is an active connectivity_state call' end + client_exit_code = $CHILD_STATUS + if client_exit_code != 0 + fail "sig_int_during_channel_watch_client failed: #{client_exit_code}" + end + server_runner.stop end diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c index 344cb941ffb..6cb71870f55 100644 --- a/src/ruby/ext/grpc/rb_call.c +++ b/src/ruby/ext/grpc/rb_call.c @@ -103,7 +103,7 @@ static void destroy_call(grpc_rb_call *call) { if (call->wrapped != NULL) { grpc_call_destroy(call->wrapped); call->wrapped = NULL; - grpc_rb_completion_queue_destroy(call->queue); + grpc_rb_completion_queue_safe_destroy(call->queue); call->queue = NULL; } } diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index fb610f548eb..973a45adf57 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -52,75 +52,131 @@ /* id_channel is the name of the hidden ivar that preserves a reference to the * channel on a call, so that calls are not GCed before their channel. */ -static ID id_channel; +ID id_channel; /* id_target is the name of the hidden ivar that preserves a reference to the * target string used to create the call, preserved so that it does not get * GCed before the channel */ -static ID id_target; +ID id_target; /* id_insecure_channel is used to indicate that a channel is insecure */ -static VALUE id_insecure_channel; +VALUE id_insecure_channel; /* grpc_rb_cChannel is the ruby class that proxies grpc_channel. */ -static VALUE grpc_rb_cChannel = Qnil; +VALUE grpc_rb_cChannel = Qnil; /* Used during the conversion of a hash to channel args during channel setup */ -static VALUE grpc_rb_cChannelArgs; +VALUE grpc_rb_cChannelArgs; + +typedef struct bg_watched_channel { + grpc_channel *channel; + struct bg_watched_channel *next; + int channel_destroyed; + int refcount; // must only be accessed under global_connection_polling_mu +} bg_watched_channel; /* grpc_rb_channel wraps a grpc_channel. */ typedef struct grpc_rb_channel { VALUE credentials; - /* The actual channel */ - grpc_channel *wrapped; - int request_safe_destroy; - int safe_to_destroy; - grpc_connectivity_state current_connectivity_state; - - int mu_init_done; - int abort_watch_connectivity_state; - gpr_mu channel_mu; - gpr_cv channel_cv; + /* The actual channel (protected in a wrapper to tell when it's safe to destroy) */ + bg_watched_channel *bg_wrapped; } grpc_rb_channel; -/* Forward declarations of functions involved in temporary fix to - * https://github.com/grpc/grpc/issues/9941 */ -static void grpc_rb_channel_try_register_connection_polling( - grpc_rb_channel *wrapper); -static void grpc_rb_channel_safe_destroy(grpc_rb_channel *wrapper); -static void *wait_until_channel_polling_thread_started_no_gil(void*); -static void wait_until_channel_polling_thread_started_unblocking_func(void*); +typedef enum { + CONTINUOUS_WATCH, + WATCH_STATE_API +} watch_state_op_type; + +typedef struct watch_state_op { + watch_state_op_type op_type; + // from event.success + union { + struct { + int success; + // has been called back due to a cq next call + int called_back; + } api_callback_args; + struct { + bg_watched_channel *bg; + } continuous_watch_callback_args; + } op; +} watch_state_op; + +bg_watched_channel *bg_watched_channel_list_head = NULL; + +void grpc_rb_channel_try_register_connection_polling(bg_watched_channel *bg); +void *wait_until_channel_polling_thread_started_no_gil(void*); +void wait_until_channel_polling_thread_started_unblocking_func(void*); +void *channel_init_try_register_connection_polling_without_gil(void *arg); + +typedef struct channel_init_try_register_stack { + grpc_channel *channel; + grpc_rb_channel *wrapper; +} channel_init_try_register_stack; + +grpc_completion_queue *channel_polling_cq; +gpr_mu global_connection_polling_mu; +gpr_cv global_connection_polling_cv; +int abort_channel_polling = 0; +int channel_polling_thread_started = 0; + +int bg_watched_channel_list_lookup(bg_watched_channel *bg); +bg_watched_channel *bg_watched_channel_list_create_and_add(grpc_channel *channel); +void bg_watched_channel_list_free_and_remove(bg_watched_channel *bg); +void run_poll_channels_loop_unblocking_func(void* arg); + +// Needs to be called under global_connection_polling_mu +void grpc_rb_channel_watch_connection_state_op_complete(watch_state_op* op, int success) { + GPR_ASSERT(!op->op.api_callback_args.called_back); + op->op.api_callback_args.called_back = 1; + op->op.api_callback_args.success = success; + // wake up the watch API call thats waiting on this op + gpr_cv_broadcast(&global_connection_polling_cv); +} + +/* Avoids destroying a channel twice. */ +void grpc_rb_channel_safe_destroy(bg_watched_channel *bg) { + gpr_mu_lock(&global_connection_polling_mu); + GPR_ASSERT(bg_watched_channel_list_lookup(bg)); + if (!bg->channel_destroyed) { + grpc_channel_destroy(bg->channel); + bg->channel_destroyed = 1; + } + bg->refcount--; + if (bg->refcount == 0) { + bg_watched_channel_list_free_and_remove(bg); + } + gpr_mu_unlock(&global_connection_polling_mu); +} -static grpc_completion_queue *channel_polling_cq; -static gpr_mu global_connection_polling_mu; -static gpr_cv global_connection_polling_cv; -static int abort_channel_polling = 0; -static int channel_polling_thread_started = 0; +void *channel_safe_destroy_without_gil(void *arg) { + grpc_rb_channel_safe_destroy((bg_watched_channel*)arg); + return NULL; +} /* Destroys Channel instances. */ -static void grpc_rb_channel_free(void *p) { +void grpc_rb_channel_free(void *p) { grpc_rb_channel *ch = NULL; if (p == NULL) { return; }; + gpr_log(GPR_DEBUG, "channel GC function called!"); ch = (grpc_rb_channel *)p; - if (ch->wrapped != NULL) { - grpc_rb_channel_safe_destroy(ch); - ch->wrapped = NULL; - } - - if (ch->mu_init_done) { - gpr_mu_destroy(&ch->channel_mu); - gpr_cv_destroy(&ch->channel_cv); + if (ch->bg_wrapped != NULL) { + /* assumption made here: it's ok to directly gpr_mu_lock the global + * connection polling mutex becuse we're in a finalizer, + * and we can count on this thread to not be interrupted. */ + grpc_rb_channel_safe_destroy(ch->bg_wrapped); + ch->bg_wrapped = NULL; } xfree(p); } /* Protects the mark object from GC */ -static void grpc_rb_channel_mark(void *p) { +void grpc_rb_channel_mark(void *p) { grpc_rb_channel *channel = NULL; if (p == NULL) { return; @@ -131,7 +187,7 @@ static void grpc_rb_channel_mark(void *p) { } } -static rb_data_type_t grpc_channel_data_type = {"grpc_channel", +rb_data_type_t grpc_channel_data_type = {"grpc_channel", {grpc_rb_channel_mark, grpc_rb_channel_free, GRPC_RB_MEMSIZE_UNAVAILABLE, @@ -144,9 +200,9 @@ static rb_data_type_t grpc_channel_data_type = {"grpc_channel", }; /* Allocates grpc_rb_channel instances. */ -static VALUE grpc_rb_channel_alloc(VALUE cls) { +VALUE grpc_rb_channel_alloc(VALUE cls) { grpc_rb_channel *wrapper = ALLOC(grpc_rb_channel); - wrapper->wrapped = NULL; + wrapper->bg_wrapped = NULL; wrapper->credentials = Qnil; return TypedData_Wrap_Struct(cls, &grpc_channel_data_type, wrapper); } @@ -159,7 +215,7 @@ static VALUE grpc_rb_channel_alloc(VALUE cls) { secure_channel = Channel:new("myhost:443", {'arg1': 'value1'}, creds) Creates channel instances. */ -static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { +VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { VALUE channel_args = Qnil; VALUE credentials = Qnil; VALUE target = Qnil; @@ -168,6 +224,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { grpc_channel_credentials *creds = NULL; char *target_chars = NULL; grpc_channel_args args; + channel_init_try_register_stack stack; MEMZERO(&args, grpc_channel_args, 1); grpc_ruby_once_init(); @@ -178,7 +235,6 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { rb_scan_args(argc, argv, "3", &target, &channel_args, &credentials); TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); - wrapper->mu_init_done = 0; target_chars = StringValueCStr(target); grpc_rb_hash_convert_to_channel_args(channel_args, &args); if (TYPE(credentials) == T_SYMBOL) { @@ -195,24 +251,10 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { } GPR_ASSERT(ch); - - wrapper->wrapped = ch; - - gpr_mu_init(&wrapper->channel_mu); - gpr_cv_init(&wrapper->channel_cv); - wrapper->mu_init_done = 1; - - gpr_mu_lock(&wrapper->channel_mu); - wrapper->abort_watch_connectivity_state = 0; - wrapper->current_connectivity_state = grpc_channel_check_connectivity_state(wrapper->wrapped, 0); - wrapper->safe_to_destroy = 0; - wrapper->request_safe_destroy = 0; - - gpr_cv_broadcast(&wrapper->channel_cv); - gpr_mu_unlock(&wrapper->channel_mu); - - - grpc_rb_channel_try_register_connection_polling(wrapper); + stack.channel = ch; + stack.wrapper = wrapper; + rb_thread_call_without_gvl( + channel_init_try_register_connection_polling_without_gil, &stack, NULL, NULL); if (args.args != NULL) { xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */ @@ -223,10 +265,32 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { return Qnil; } rb_ivar_set(self, id_target, target); - wrapper->wrapped = ch; return self; } +typedef struct get_state_stack { + grpc_channel *channel; + int try_to_connect; + int out; +} get_state_stack; + +void *get_state_without_gil(void *arg) { + get_state_stack *stack = (get_state_stack*)arg; + + gpr_mu_lock(&global_connection_polling_mu); + GPR_ASSERT(abort_channel_polling || channel_polling_thread_started); + if (abort_channel_polling) { + // the case in which the channel polling thread + // failed to start just always shows shutdown state. + stack->out = GRPC_CHANNEL_SHUTDOWN; + } else { + stack->out = grpc_channel_check_connectivity_state(stack->channel, stack->try_to_connect); + } + gpr_mu_unlock(&global_connection_polling_mu); + + return NULL; +} + /* call-seq: ch.connectivity_state -> state @@ -236,62 +300,66 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { constants defined in GRPC::Core::ConnectivityStates. It also tries to connect if the chennel is idle in the second form. */ -static VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv, +VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv, VALUE self) { VALUE try_to_connect_param = Qfalse; int grpc_try_to_connect = 0; grpc_rb_channel *wrapper = NULL; - grpc_channel *ch = NULL; + get_state_stack stack; /* "01" == 0 mandatory args, 1 (try_to_connect) is optional */ rb_scan_args(argc, argv, "01", &try_to_connect_param); grpc_try_to_connect = RTEST(try_to_connect_param) ? 1 : 0; TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); - ch = wrapper->wrapped; - if (ch == NULL) { + if (wrapper->bg_wrapped == NULL) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; } - return LONG2NUM(grpc_channel_check_connectivity_state(wrapper->wrapped, grpc_try_to_connect)); + + stack.channel = wrapper->bg_wrapped->channel; + stack.try_to_connect = grpc_try_to_connect; + rb_thread_call_without_gvl(get_state_without_gil, &stack, NULL, NULL); + + return LONG2NUM(stack.out); } typedef struct watch_state_stack { - grpc_rb_channel *wrapper; + grpc_channel *channel; gpr_timespec deadline; int last_state; } watch_state_stack; -static void *watch_channel_state_without_gvl(void *arg) { +void *wait_for_watch_state_op_complete_without_gvl(void *arg) { watch_state_stack *stack = (watch_state_stack*)arg; - gpr_timespec deadline = stack->deadline; - grpc_rb_channel *wrapper = stack->wrapper; - int last_state = stack->last_state; - void *return_value = (void*)0; + watch_state_op *op = NULL; + void *success = (void*)0; - gpr_mu_lock(&wrapper->channel_mu); - while(wrapper->current_connectivity_state == last_state && - !wrapper->request_safe_destroy && - !wrapper->safe_to_destroy && - !wrapper->abort_watch_connectivity_state && - gpr_time_cmp(deadline, gpr_now(GPR_CLOCK_REALTIME)) > 0) { - gpr_cv_wait(&wrapper->channel_cv, &wrapper->channel_mu, deadline); + gpr_mu_lock(&global_connection_polling_mu); + // its unsafe to do a "watch" after "channel polling abort" because the cq has + // been shut down. + if (abort_channel_polling) { + gpr_mu_unlock(&global_connection_polling_mu); + return (void*)0; + } + op = gpr_zalloc(sizeof(watch_state_op)); + op->op_type = WATCH_STATE_API; + // one ref for this thread and another for the callback-running thread + grpc_channel_watch_connectivity_state( + stack->channel, stack->last_state, stack->deadline, channel_polling_cq, op); + + while(!op->op.api_callback_args.called_back) { + gpr_cv_wait(&global_connection_polling_cv, + &global_connection_polling_mu, + gpr_inf_future(GPR_CLOCK_REALTIME)); } - if (wrapper->current_connectivity_state != last_state) { - return_value = (void*)1; + if (op->op.api_callback_args.success) { + success = (void*)1; } - gpr_mu_unlock(&wrapper->channel_mu); - - return return_value; -} + gpr_free(op); + gpr_mu_unlock(&global_connection_polling_mu); -static void watch_channel_state_unblocking_func(void *arg) { - grpc_rb_channel *wrapper = (grpc_rb_channel*)arg; - gpr_log(GPR_DEBUG, "GRPC_RUBY: watch channel state unblocking func called"); - gpr_mu_lock(&wrapper->channel_mu); - wrapper->abort_watch_connectivity_state = 1; - gpr_cv_broadcast(&wrapper->channel_cv); - gpr_mu_unlock(&wrapper->channel_mu); + return success; } /* Wait until the channel's connectivity state becomes different from @@ -301,16 +369,16 @@ static void watch_channel_state_unblocking_func(void *arg) { * Returns false if "deadline" expires before the channel's connectivity * state changes from "last_state". * */ -static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, +VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, VALUE last_state, VALUE deadline) { grpc_rb_channel *wrapper = NULL; watch_state_stack stack; - void* out; + void* op_success = 0; TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); - if (wrapper->wrapped == NULL) { + if (wrapper->bg_wrapped == NULL) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; } @@ -320,26 +388,25 @@ static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, return Qnil; } - stack.wrapper = wrapper; - stack.deadline = grpc_rb_time_timeval(deadline, 0); + stack.channel = wrapper->bg_wrapped->channel; + stack.deadline = grpc_rb_time_timeval(deadline, 0), stack.last_state = NUM2LONG(last_state); - out = rb_thread_call_without_gvl(watch_channel_state_without_gvl, &stack, watch_channel_state_unblocking_func, wrapper); - if (out) { - return Qtrue; - } - return Qfalse; + + op_success = rb_thread_call_without_gvl( + wait_for_watch_state_op_complete_without_gvl, &stack, run_poll_channels_loop_unblocking_func, NULL); + + return op_success ? Qtrue : Qfalse; } /* Create a call given a grpc_channel, in order to call method. The request is not sent until grpc_call_invoke is called. */ -static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, +VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, VALUE method, VALUE host, VALUE deadline) { VALUE res = Qnil; grpc_rb_channel *wrapper = NULL; grpc_call *call = NULL; grpc_call *parent_call = NULL; - grpc_channel *ch = NULL; grpc_completion_queue *cq = NULL; int flags = GRPC_PROPAGATE_DEFAULTS; grpc_slice method_slice; @@ -361,8 +428,7 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, cq = grpc_completion_queue_create(NULL); TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); - ch = wrapper->wrapped; - if (ch == NULL) { + if (wrapper->bg_wrapped == NULL) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; } @@ -370,7 +436,7 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, method_slice = grpc_slice_from_copied_buffer(RSTRING_PTR(method), RSTRING_LEN(method)); - call = grpc_channel_create_call(ch, parent_call, flags, cq, method_slice, + call = grpc_channel_create_call(wrapper->bg_wrapped->channel, parent_call, flags, cq, method_slice, host_slice_ptr, grpc_rb_time_timeval(deadline, /* absolute time */ 0), @@ -396,85 +462,132 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, } /* Closes the channel, calling it's destroy method */ -static VALUE grpc_rb_channel_destroy(VALUE self) { +/* Note this is an API-level call; a wrapped channel's finalizer doesn't call + * this */ +VALUE grpc_rb_channel_destroy(VALUE self) { grpc_rb_channel *wrapper = NULL; - grpc_channel *ch = NULL; TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); - ch = wrapper->wrapped; - if (ch != NULL) { - grpc_rb_channel_safe_destroy(wrapper); - wrapper->wrapped = NULL; + if (wrapper->bg_wrapped != NULL) { + rb_thread_call_without_gvl( + channel_safe_destroy_without_gil, wrapper->bg_wrapped, NULL, NULL); + wrapper->bg_wrapped = NULL; } return Qnil; } /* Called to obtain the target that this channel accesses. */ -static VALUE grpc_rb_channel_get_target(VALUE self) { +VALUE grpc_rb_channel_get_target(VALUE self) { grpc_rb_channel *wrapper = NULL; VALUE res = Qnil; char *target = NULL; TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); - target = grpc_channel_get_target(wrapper->wrapped); + target = grpc_channel_get_target(wrapper->bg_wrapped->channel); res = rb_str_new2(target); gpr_free(target); return res; } -// Either start polling channel connection state or signal that it's free to -// destroy. -// Not safe to call while a channel's connection state is polled. -static void grpc_rb_channel_try_register_connection_polling( - grpc_rb_channel *wrapper) { - grpc_connectivity_state conn_state; - gpr_timespec sleep_time = gpr_time_add( - gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(20, GPR_TIMESPAN)); - - GPR_ASSERT(wrapper); - GPR_ASSERT(wrapper->wrapped); - gpr_mu_lock(&wrapper->channel_mu); - if (wrapper->request_safe_destroy) { - wrapper->safe_to_destroy = 1; - gpr_cv_broadcast(&wrapper->channel_cv); - gpr_mu_unlock(&wrapper->channel_mu); - return; +/* Needs to be called under global_connection_polling_mu */ +int bg_watched_channel_list_lookup(bg_watched_channel *target) { + bg_watched_channel *cur = bg_watched_channel_list_head; + + gpr_log(GPR_DEBUG, "check contains"); + while (cur != NULL) { + if (cur == target) { + return 1; + } + cur = cur->next; } - gpr_mu_lock(&global_connection_polling_mu); - GPR_ASSERT(channel_polling_thread_started || abort_channel_polling); - conn_state = grpc_channel_check_connectivity_state(wrapper->wrapped, 0); - if (conn_state != wrapper->current_connectivity_state) { - wrapper->current_connectivity_state = conn_state; - gpr_cv_broadcast(&wrapper->channel_cv); - } - // avoid posting work to the channel polling cq if it's been shutdown - if (!abort_channel_polling && conn_state != GRPC_CHANNEL_SHUTDOWN) { - grpc_channel_watch_connectivity_state( - wrapper->wrapped, conn_state, sleep_time, channel_polling_cq, wrapper); - } else { - wrapper->safe_to_destroy = 1; - gpr_cv_broadcast(&wrapper->channel_cv); + return 0; +} + +/* Needs to be called under global_connection_polling_mu */ +bg_watched_channel *bg_watched_channel_list_create_and_add(grpc_channel *channel) { + bg_watched_channel *watched = gpr_zalloc(sizeof(bg_watched_channel)); + + gpr_log(GPR_DEBUG, "add bg"); + watched->channel = channel; + watched->next = bg_watched_channel_list_head; + watched->refcount = 1; + bg_watched_channel_list_head = watched; + return watched; +} + +/* Needs to be called under global_connection_polling_mu */ +void bg_watched_channel_list_free_and_remove(bg_watched_channel *target) { + bg_watched_channel *bg = NULL; + + gpr_log(GPR_DEBUG, "remove bg"); + GPR_ASSERT(bg_watched_channel_list_lookup(target)); + GPR_ASSERT(target->channel_destroyed && target->refcount == 0); + if (bg_watched_channel_list_head == target) { + bg_watched_channel_list_head = target->next; + gpr_free(target); + return; + } + bg = bg_watched_channel_list_head; + while (bg != NULL && bg->next != NULL) { + if (bg->next == target) { + bg->next = bg->next->next; + gpr_free(target); + return; + } + bg = bg->next; } + GPR_ASSERT(0); +} + +/* Initialize a grpc_rb_channel's "protected grpc_channel" and try to push + * it onto the background thread for constant watches. */ +void *channel_init_try_register_connection_polling_without_gil(void *arg) { + channel_init_try_register_stack *stack = (channel_init_try_register_stack*)arg; + + gpr_mu_lock(&global_connection_polling_mu); + stack->wrapper->bg_wrapped = bg_watched_channel_list_create_and_add(stack->channel); + grpc_rb_channel_try_register_connection_polling(stack->wrapper->bg_wrapped); gpr_mu_unlock(&global_connection_polling_mu); - gpr_mu_unlock(&wrapper->channel_mu); + return NULL; } -// Note requires wrapper->wrapped, wrapper->channel_mu/cv initialized -static void grpc_rb_channel_safe_destroy(grpc_rb_channel *wrapper) { - gpr_mu_lock(&wrapper->channel_mu); - wrapper->request_safe_destroy = 1; +// Needs to be called under global_connection_poolling_mu +void grpc_rb_channel_try_register_connection_polling(bg_watched_channel *bg) { + grpc_connectivity_state conn_state; + watch_state_op *op = NULL; - while (!wrapper->safe_to_destroy) { - gpr_cv_wait(&wrapper->channel_cv, &wrapper->channel_mu, - gpr_inf_future(GPR_CLOCK_REALTIME)); + GPR_ASSERT(channel_polling_thread_started || abort_channel_polling); + + if (bg->refcount == 0) { + GPR_ASSERT(bg->channel_destroyed); + bg_watched_channel_list_free_and_remove(bg); + return; + } + GPR_ASSERT(bg->refcount == 1); + if (bg->channel_destroyed) { + GPR_ASSERT(abort_channel_polling); + return; + } + if (abort_channel_polling) { + return; } - GPR_ASSERT(wrapper->safe_to_destroy); - gpr_mu_unlock(&wrapper->channel_mu); - grpc_channel_destroy(wrapper->wrapped); + conn_state = grpc_channel_check_connectivity_state(bg->channel, 0); + if (conn_state == GRPC_CHANNEL_SHUTDOWN) { + return; + } + GPR_ASSERT(bg_watched_channel_list_lookup(bg)); + // prevent bg from being free'd by GC while background thread is watching it + bg->refcount++; + + op = gpr_zalloc(sizeof(watch_state_op)); + op->op_type = CONTINUOUS_WATCH; + op->op.continuous_watch_callback_args.bg = bg; + grpc_channel_watch_connectivity_state( + bg->channel, conn_state, gpr_inf_future(GPR_CLOCK_REALTIME), channel_polling_cq, op); } // Note this loop breaks out with a single call of @@ -483,8 +596,10 @@ static void grpc_rb_channel_safe_destroy(grpc_rb_channel *wrapper) { // indicates process shutdown. // In the worst case, this stops polling channel connectivity // early and falls back to current behavior. -static void *run_poll_channels_loop_no_gil(void *arg) { +void *run_poll_channels_loop_no_gil(void *arg) { grpc_event event; + watch_state_op *op = NULL; + bg_watched_channel *bg = NULL; (void)arg; gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop_no_gil - begin"); @@ -500,9 +615,21 @@ static void *run_poll_channels_loop_no_gil(void *arg) { if (event.type == GRPC_QUEUE_SHUTDOWN) { break; } + gpr_mu_lock(&global_connection_polling_mu); if (event.type == GRPC_OP_COMPLETE) { - grpc_rb_channel_try_register_connection_polling((grpc_rb_channel *)event.tag); + op = (watch_state_op*)event.tag; + if (op->op_type == CONTINUOUS_WATCH) { + bg = (bg_watched_channel*)op->op.continuous_watch_callback_args.bg; + bg->refcount--; + grpc_rb_channel_try_register_connection_polling(bg); + gpr_free(op); + } else if(op->op_type == WATCH_STATE_API) { + grpc_rb_channel_watch_connection_state_op_complete((watch_state_op*)event.tag, event.success); + } else { + GPR_ASSERT(0); + } } + gpr_mu_unlock(&global_connection_polling_mu); } grpc_completion_queue_destroy(channel_polling_cq); gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop_no_gil - exit connection polling loop"); @@ -510,17 +637,37 @@ static void *run_poll_channels_loop_no_gil(void *arg) { } // Notify the channel polling loop to cleanup and shutdown. -static void run_poll_channels_loop_unblocking_func(void *arg) { +void run_poll_channels_loop_unblocking_func(void *arg) { + bg_watched_channel *bg = NULL; (void)arg; + gpr_mu_lock(&global_connection_polling_mu); gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop_unblocking_func - begin aborting connection polling"); + // early out after first time through + if (abort_channel_polling) { + gpr_mu_unlock(&global_connection_polling_mu); + return; + } abort_channel_polling = 1; + + // force pending watches to end by switching to shutdown state + bg = bg_watched_channel_list_head; + while(bg != NULL) { + if (!bg->channel_destroyed) { + grpc_channel_destroy(bg->channel); + bg->channel_destroyed = 1; + } + bg = bg->next; + } + grpc_completion_queue_shutdown(channel_polling_cq); + gpr_cv_broadcast(&global_connection_polling_cv); gpr_mu_unlock(&global_connection_polling_mu); + gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop_unblocking_func - begin aborting connection polling 22222"); } // Poll channel connectivity states in background thread without the GIL. -static VALUE run_poll_channels_loop(VALUE arg) { +VALUE run_poll_channels_loop(VALUE arg) { (void)arg; gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop - create connection polling thread"); rb_thread_call_without_gvl(run_poll_channels_loop_no_gil, NULL, @@ -529,7 +676,7 @@ static VALUE run_poll_channels_loop(VALUE arg) { return Qnil; } -static void *wait_until_channel_polling_thread_started_no_gil(void *arg) { +void *wait_until_channel_polling_thread_started_no_gil(void *arg) { (void)arg; gpr_log(GPR_DEBUG, "GRPC_RUBY: wait for channel polling thread to start"); gpr_mu_lock(&global_connection_polling_mu); @@ -542,7 +689,7 @@ static void *wait_until_channel_polling_thread_started_no_gil(void *arg) { return NULL; } -static void wait_until_channel_polling_thread_started_unblocking_func(void* arg) { +void wait_until_channel_polling_thread_started_unblocking_func(void* arg) { (void)arg; gpr_mu_lock(&global_connection_polling_mu); gpr_log(GPR_DEBUG, "GRPC_RUBY: wait_until_channel_polling_thread_started_unblocking_func - begin aborting connection polling"); @@ -551,6 +698,16 @@ static void wait_until_channel_polling_thread_started_unblocking_func(void* arg) gpr_mu_unlock(&global_connection_polling_mu); } +static void *set_abort_channel_polling_without_gil(void *arg) { + (void)arg; + gpr_mu_lock(&global_connection_polling_mu); + abort_channel_polling = 1; + gpr_cv_broadcast(&global_connection_polling_cv); + gpr_mu_unlock(&global_connection_polling_mu); + return NULL; +} + + /* Temporary fix for * https://github.com/GoogleCloudPlatform/google-cloud-ruby/issues/899. * Transports in idle channels can get destroyed. Normally c-core re-connects, @@ -576,14 +733,11 @@ void grpc_rb_channel_polling_thread_start() { if (!RTEST(background_thread)) { gpr_log(GPR_DEBUG, "GRPC_RUBY: failed to spawn channel polling thread"); - gpr_mu_lock(&global_connection_polling_mu); - abort_channel_polling = 1; - gpr_cv_broadcast(&global_connection_polling_cv); - gpr_mu_unlock(&global_connection_polling_mu); + rb_thread_call_without_gvl(set_abort_channel_polling_without_gil, NULL, NULL, NULL); } } -static void Init_grpc_propagate_masks() { +void Init_grpc_propagate_masks() { /* Constants representing call propagation masks in grpc.h */ VALUE grpc_rb_mPropagateMasks = rb_define_module_under(grpc_rb_mGrpcCore, "PropagateMasks"); @@ -599,7 +753,7 @@ static void Init_grpc_propagate_masks() { UINT2NUM(GRPC_PROPAGATE_DEFAULTS)); } -static void Init_grpc_connectivity_states() { +void Init_grpc_connectivity_states() { /* Constants representing call propagation masks in grpc.h */ VALUE grpc_rb_mConnectivityStates = rb_define_module_under(grpc_rb_mGrpcCore, "ConnectivityStates"); @@ -658,5 +812,5 @@ void Init_grpc_channel() { grpc_channel *grpc_rb_get_wrapped_channel(VALUE v) { grpc_rb_channel *wrapper = NULL; TypedData_Get_Struct(v, grpc_rb_channel, &grpc_channel_data_type, wrapper); - return wrapper->wrapped; + return wrapper->bg_wrapped->channel; } diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c index fd75d2f691f..9f3a81b1a8b 100644 --- a/src/ruby/ext/grpc/rb_completion_queue.c +++ b/src/ruby/ext/grpc/rb_completion_queue.c @@ -71,12 +71,16 @@ static void *grpc_rb_completion_queue_pluck_no_gil(void *param) { } /* Helper function to free a completion queue. */ -void grpc_rb_completion_queue_destroy(grpc_completion_queue *cq) { - /* Every function that adds an event to a queue also synchronously plucks - that event from the queue, and holds a reference to the Ruby object that - holds the queue, so we only get to this point if all of those functions - have completed, and the queue is empty */ +void grpc_rb_completion_queue_safe_destroy(grpc_completion_queue *cq) { + grpc_event ev; + grpc_completion_queue_shutdown(cq); + for(;;) { + ev = grpc_completion_queue_pluck(cq, NULL, gpr_inf_future(GPR_CLOCK_REALTIME), NULL); + if (ev.type == GRPC_QUEUE_SHUTDOWN) { + break; + } + } grpc_completion_queue_destroy(cq); } diff --git a/src/ruby/ext/grpc/rb_completion_queue.h b/src/ruby/ext/grpc/rb_completion_queue.h index aa9dc6416af..eb041b28dfc 100644 --- a/src/ruby/ext/grpc/rb_completion_queue.h +++ b/src/ruby/ext/grpc/rb_completion_queue.h @@ -38,7 +38,7 @@ #include -void grpc_rb_completion_queue_destroy(grpc_completion_queue *cq); +void grpc_rb_completion_queue_safe_destroy(grpc_completion_queue *cq); /** * Makes the implementation of CompletionQueue#pluck available in other files diff --git a/src/ruby/ext/grpc/rb_event_thread.c b/src/ruby/ext/grpc/rb_event_thread.c index 9e85bbcfbf2..f1a08a7b23d 100644 --- a/src/ruby/ext/grpc/rb_event_thread.c +++ b/src/ruby/ext/grpc/rb_event_thread.c @@ -106,17 +106,17 @@ static void *grpc_rb_wait_for_event_no_gil(void *param) { grpc_rb_event *event = NULL; (void)param; gpr_mu_lock(&event_queue.mu); - while ((event = grpc_rb_event_queue_dequeue()) == NULL) { + while (!event_queue.abort) { + if ((event = grpc_rb_event_queue_dequeue()) != NULL) { + gpr_mu_unlock(&event_queue.mu); + return event; + } gpr_cv_wait(&event_queue.cv, &event_queue.mu, gpr_inf_future(GPR_CLOCK_REALTIME)); - if (event_queue.abort) { - gpr_mu_unlock(&event_queue.mu); - return NULL; - } } gpr_mu_unlock(&event_queue.mu); - return event; + return NULL; } static void grpc_rb_event_unblocking_func(void *arg) { diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c index 2286a99f249..2b0858c247e 100644 --- a/src/ruby/ext/grpc/rb_server.c +++ b/src/ruby/ext/grpc/rb_server.c @@ -77,7 +77,7 @@ static void destroy_server(grpc_rb_server *server, gpr_timespec deadline) { gpr_inf_future(GPR_CLOCK_REALTIME), NULL); } grpc_server_destroy(server->wrapped); - grpc_rb_completion_queue_destroy(server->queue); + grpc_rb_completion_queue_safe_destroy(server->queue); server->wrapped = NULL; server->queue = NULL; } diff --git a/src/ruby/spec/channel_connection_spec.rb b/src/ruby/spec/channel_connection_spec.rb index 940d68b9b04..b3edec8f938 100644 --- a/src/ruby/spec/channel_connection_spec.rb +++ b/src/ruby/spec/channel_connection_spec.rb @@ -28,6 +28,10 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc' +require 'timeout' + +include Timeout +include GRPC::Core # A test message class EchoMsg @@ -62,7 +66,7 @@ end EchoStub = EchoService.rpc_stub_class def start_server(port = 0) - @srv = GRPC::RpcServer.new + @srv = GRPC::RpcServer.new(pool_size: 1) server_port = @srv.add_http2_port("localhost:#{port}", :this_port_is_insecure) @srv.handle(EchoService) @server_thd = Thread.new { @srv.run } @@ -138,4 +142,33 @@ describe 'channel connection behavior' do stop_server end + + it 'observably connects and reconnects to transient server' \ + ' when using the channel state API' do + timeout(180) do + port = start_server + ch = GRPC::Core::Channel.new("localhost:#{port}", {}, + :this_channel_is_insecure) + stop_server + + thds = [] + 50.times do + thds << Thread.new do + while ch.connectivity_state(true) != ConnectivityStates::READY + ch.watch_connectivity_state( + ConnectivityStates::READY, Time.now + 60) + break + end + end + end + + sleep 0.01 + + start_server(port) + + thds.each(&:join) + + stop_server + end + end end From 08823874868e627c80e45d6c8d9466798803fe1c Mon Sep 17 00:00:00 2001 From: jiangtaoli2016 Date: Thu, 11 May 2017 09:41:02 -0700 Subject: [PATCH 10/65] fix memory leak in left_overs slice --- src/core/lib/security/transport/security_handshaker.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/core/lib/security/transport/security_handshaker.c b/src/core/lib/security/transport/security_handshaker.c index 7a4dc6475e4..9b158201fc6 100644 --- a/src/core/lib/security/transport/security_handshaker.c +++ b/src/core/lib/security/transport/security_handshaker.c @@ -169,19 +169,16 @@ static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *arg, result = tsi_handshaker_result_get_unused_bytes( h->handshaker_result, &unused_bytes, &unused_bytes_size); if (unused_bytes_size > 0) { - gpr_slice slice = + grpc_slice slice = grpc_slice_from_copied_buffer((char *)unused_bytes, unused_bytes_size); grpc_slice_buffer_add(&h->left_overs, slice); } // Create secure endpoint. h->args->endpoint = grpc_secure_endpoint_create( protector, h->args->endpoint, h->left_overs.slices, h->left_overs.count); - h->left_overs.count = 0; - h->left_overs.length = 0; tsi_handshaker_result_destroy(h->handshaker_result); h->handshaker_result = NULL; - // Clear out the read buffer before it gets passed to the transport, - // since any excess bytes were already copied to h->left_overs. + // Clear out the read buffer before it gets passed to the transport. grpc_slice_buffer_reset_and_unref_internal(exec_ctx, h->args->read_buffer); // Add auth context to channel args. grpc_arg auth_context_arg = grpc_auth_context_to_arg(h->auth_context); From 8d18c6edfbe675cbee6c425690c2e32b7dccba9d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 15 May 2017 14:39:05 -0700 Subject: [PATCH 11/65] Fix race between destroying call after status and handling write failure --- src/node/ext/call.cc | 8 ++++++++ src/node/src/client.js | 12 ++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc index 8877995f8f2..2cc9f63b659 100644 --- a/src/node/ext/call.cc +++ b/src/node/ext/call.cc @@ -721,6 +721,14 @@ NAN_METHOD(Call::StartBatch) { } Local callback_func = info[1].As(); Call *call = ObjectWrap::Unwrap(info.This()); + if (call->wrapped_call == NULL) { + /* This implies that the call has completed and has been destroyed. To emulate + * previous behavior, we should call the callback immediately with an error, + * as though the batch had failed in core */ + Local argv[] = {Nan::Error("The async function failed because the call has completed")}; + Nan::Call(callback_func, Nan::New(), 1, argv); + return; + } Local obj = Nan::To(info[0]).ToLocalChecked(); Local keys = Nan::GetOwnPropertyNames(obj).ToLocalChecked(); size_t nops = keys->Length(); diff --git a/src/node/src/client.js b/src/node/src/client.js index 1aaf35c16cb..aa818349daa 100644 --- a/src/node/src/client.js +++ b/src/node/src/client.js @@ -100,6 +100,12 @@ function _write(chunk, encoding, callback) { /* jshint validthis: true */ var batch = {}; var message; + var self = this; + if (this.writeFailed) { + /* Once a write fails, just call the callback immediately to let the caller + flush any pending writes. */ + callback(); + } try { message = this.serialize(chunk); } catch (e) { @@ -119,8 +125,10 @@ function _write(chunk, encoding, callback) { batch[grpc.opType.SEND_MESSAGE] = message; this.call.startBatch(batch, function(err, event) { if (err) { - // Something has gone wrong. Stop writing by failing to call callback - return; + /* Assume that the call is complete and that writing failed because a + status was received. In that case, set a flag to discard all future + writes */ + self.writeFailed = true; } callback(); }); From d822e2f5cf8d32efd0008c967551e994046b2d73 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 16 May 2017 12:53:57 -0700 Subject: [PATCH 12/65] Change write callback to asynchronous to avoid recursion --- src/node/src/client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/src/client.js b/src/node/src/client.js index aa818349daa..2073d3eea8d 100644 --- a/src/node/src/client.js +++ b/src/node/src/client.js @@ -104,7 +104,7 @@ function _write(chunk, encoding, callback) { if (this.writeFailed) { /* Once a write fails, just call the callback immediately to let the caller flush any pending writes. */ - callback(); + setImmediate(callback); } try { message = this.serialize(chunk); From 0e2b6a2109fdb53884094de6c2395bd49fbf13e1 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Tue, 16 May 2017 17:16:05 -0700 Subject: [PATCH 13/65] remove debug prints --- src/ruby/ext/grpc/rb_channel.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 973a45adf57..c96dc672ce2 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -161,7 +161,6 @@ void grpc_rb_channel_free(void *p) { if (p == NULL) { return; }; - gpr_log(GPR_DEBUG, "channel GC function called!"); ch = (grpc_rb_channel *)p; if (ch->bg_wrapped != NULL) { @@ -495,7 +494,6 @@ VALUE grpc_rb_channel_get_target(VALUE self) { int bg_watched_channel_list_lookup(bg_watched_channel *target) { bg_watched_channel *cur = bg_watched_channel_list_head; - gpr_log(GPR_DEBUG, "check contains"); while (cur != NULL) { if (cur == target) { return 1; @@ -510,7 +508,6 @@ int bg_watched_channel_list_lookup(bg_watched_channel *target) { bg_watched_channel *bg_watched_channel_list_create_and_add(grpc_channel *channel) { bg_watched_channel *watched = gpr_zalloc(sizeof(bg_watched_channel)); - gpr_log(GPR_DEBUG, "add bg"); watched->channel = channel; watched->next = bg_watched_channel_list_head; watched->refcount = 1; @@ -522,7 +519,6 @@ bg_watched_channel *bg_watched_channel_list_create_and_add(grpc_channel *channel void bg_watched_channel_list_free_and_remove(bg_watched_channel *target) { bg_watched_channel *bg = NULL; - gpr_log(GPR_DEBUG, "remove bg"); GPR_ASSERT(bg_watched_channel_list_lookup(target)); GPR_ASSERT(target->channel_destroyed && target->refcount == 0); if (bg_watched_channel_list_head == target) { From 7b3629e6c2570686701b4bdb6b171b219cbad06e Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 17 May 2017 00:29:10 -0700 Subject: [PATCH 14/65] fix lack-of-abort bug --- src/ruby/end2end/grpc_class_init_client.rb | 16 +++++++++++++--- src/ruby/ext/grpc/rb_channel.c | 12 +----------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/ruby/end2end/grpc_class_init_client.rb b/src/ruby/end2end/grpc_class_init_client.rb index 8e46907368f..62afc85b1d0 100755 --- a/src/ruby/end2end/grpc_class_init_client.rb +++ b/src/ruby/end2end/grpc_class_init_client.rb @@ -106,9 +106,19 @@ def main return end - thd = Thread.new { test_proc.call } - test_proc.call - thd.join +# test_proc.call + + thds = [] + 100.times do + thds << Thread.new do + test_proc.call + sleep 10 + end + end + + #test_proc.call + raise "something" + thds.each(&:join) end main diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index c96dc672ce2..748fe663ed9 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -107,7 +107,6 @@ bg_watched_channel *bg_watched_channel_list_head = NULL; void grpc_rb_channel_try_register_connection_polling(bg_watched_channel *bg); void *wait_until_channel_polling_thread_started_no_gil(void*); -void wait_until_channel_polling_thread_started_unblocking_func(void*); void *channel_init_try_register_connection_polling_without_gil(void *arg); typedef struct channel_init_try_register_stack { @@ -228,7 +227,7 @@ VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { grpc_ruby_once_init(); rb_thread_call_without_gvl(wait_until_channel_polling_thread_started_no_gil, NULL, - wait_until_channel_polling_thread_started_unblocking_func, NULL); + run_poll_channels_loop_unblocking_func, NULL); /* "3" == 3 mandatory args */ rb_scan_args(argc, argv, "3", &target, &channel_args, &credentials); @@ -685,15 +684,6 @@ void *wait_until_channel_polling_thread_started_no_gil(void *arg) { return NULL; } -void wait_until_channel_polling_thread_started_unblocking_func(void* arg) { - (void)arg; - gpr_mu_lock(&global_connection_polling_mu); - gpr_log(GPR_DEBUG, "GRPC_RUBY: wait_until_channel_polling_thread_started_unblocking_func - begin aborting connection polling"); - abort_channel_polling = 1; - gpr_cv_broadcast(&global_connection_polling_cv); - gpr_mu_unlock(&global_connection_polling_mu); -} - static void *set_abort_channel_polling_without_gil(void *arg) { (void)arg; gpr_mu_lock(&global_connection_polling_mu); From fd4cbb70774a943a790459c8ec54d8bb112a3ef2 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 17 May 2017 09:57:25 -0700 Subject: [PATCH 15/65] cleanup test --- src/ruby/end2end/grpc_class_init_client.rb | 57 ++++++++++++++-------- src/ruby/end2end/grpc_class_init_driver.rb | 14 +++--- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/ruby/end2end/grpc_class_init_client.rb b/src/ruby/end2end/grpc_class_init_client.rb index 62afc85b1d0..d9c23c38359 100755 --- a/src/ruby/end2end/grpc_class_init_client.rb +++ b/src/ruby/end2end/grpc_class_init_client.rb @@ -60,6 +60,27 @@ def run_gc_stress_test(test_proc) construct_many(test_proc) end +def run_concurrency_stress_test(test_proc) + test_proc.call + + thds = [] + 100.times do + thds << Thread.new do + test_proc.call + end + end + + raise "something" +end + +# default (no gc_stress and no concurrency_stress) +def run_default_test(test_proc) + thd = Thread.new do + test_proc.call + end + test_proc.call +end + def get_test_proc(grpc_class) case grpc_class when 'channel' @@ -89,36 +110,34 @@ end def main grpc_class = '' - gc_stress = false + stress_test = '' OptionParser.new do |opts| opts.on('--grpc_class=P', String) do |p| grpc_class = p end - opts.on('--gc_stress=P') do |p| - gc_stress = p + opts.on('--stress_test=P') do |p| + stress_test = p end end.parse! test_proc = get_test_proc(grpc_class) - if gc_stress == 'true' + # the different test configs need to be ran + # in separate processes, since each one tests + # clean shutdown in a different way + case stress_test + when 'gc' + p 'run gc stress' run_gc_stress_test(test_proc) - return - end - -# test_proc.call - - thds = [] - 100.times do - thds << Thread.new do - test_proc.call - sleep 10 - end + when 'concurrency' + p 'run concurrency stress' + run_concurrency_stress_test(test_proc) + when '' + p 'run default' + run_default_test(test_proc) + else + fail "bad --stress_test=#{stress_test} param" end - - #test_proc.call - raise "something" - thds.each(&:join) end main diff --git a/src/ruby/end2end/grpc_class_init_driver.rb b/src/ruby/end2end/grpc_class_init_driver.rb index 0e330a493f5..195da3cf9f8 100755 --- a/src/ruby/end2end/grpc_class_init_driver.rb +++ b/src/ruby/end2end/grpc_class_init_driver.rb @@ -39,17 +39,17 @@ def main compression_options ) # there is room for false positives in this test, - # do 10 runs for each config to reduce these. - [true, false].each do |gc_stress| - 10.times do - native_grpc_classes.each do |grpc_class| + # do a few runs for each config + 4.times do + native_grpc_classes.each do |grpc_class| + ['', 'gc', 'concurrency'].each do |stress_test_type| STDERR.puts 'start client' this_dir = File.expand_path(File.dirname(__FILE__)) client_path = File.join(this_dir, 'grpc_class_init_client.rb') client_pid = Process.spawn(RbConfig.ruby, client_path, "--grpc_class=#{grpc_class}", - "--gc_stress=#{gc_stress}") + "--stress_test=#{stress_test_type}") begin Timeout.timeout(10) do Process.wait(client_pid) @@ -65,7 +65,9 @@ def main end client_exit_code = $CHILD_STATUS - if client_exit_code != 0 + # concurrency stress test type is expected to exit with a + # non-zero status due to an exception being raised + if client_exit_code != 0 and stress_test_type != 'concurrency' fail "client failed, exit code #{client_exit_code}" end end From 916893b618d602fef2ec1dbf9821611f67a7a1d3 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 17 May 2017 10:05:39 -0700 Subject: [PATCH 16/65] fix up the test --- src/ruby/end2end/grpc_class_init_client.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/ruby/end2end/grpc_class_init_client.rb b/src/ruby/end2end/grpc_class_init_client.rb index d9c23c38359..464c42d07a8 100755 --- a/src/ruby/end2end/grpc_class_init_client.rb +++ b/src/ruby/end2end/grpc_class_init_client.rb @@ -61,16 +61,15 @@ def run_gc_stress_test(test_proc) end def run_concurrency_stress_test(test_proc) - test_proc.call - - thds = [] 100.times do - thds << Thread.new do + Thread.new do test_proc.call end end - raise "something" + test_proc.call + + raise 'exception thrown while child thread initing class' end # default (no gc_stress and no concurrency_stress) From 5c6dda8639bd390565e794192ddfb15af0837c92 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 17 May 2017 13:08:34 -0700 Subject: [PATCH 17/65] fix tentative startup bug --- src/ruby/end2end/grpc_class_init_client.rb | 3 ++- src/ruby/end2end/grpc_class_init_driver.rb | 6 +++--- src/ruby/ext/grpc/rb_channel.c | 5 ++--- src/ruby/ext/grpc/rb_grpc.c | 21 +++++++++++++++++++-- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/ruby/end2end/grpc_class_init_client.rb b/src/ruby/end2end/grpc_class_init_client.rb index 464c42d07a8..e73ca76850f 100755 --- a/src/ruby/end2end/grpc_class_init_client.rb +++ b/src/ruby/end2end/grpc_class_init_client.rb @@ -69,7 +69,7 @@ def run_concurrency_stress_test(test_proc) test_proc.call - raise 'exception thrown while child thread initing class' + fail 'exception thrown while child thread initing class' end # default (no gc_stress and no concurrency_stress) @@ -78,6 +78,7 @@ def run_default_test(test_proc) test_proc.call end test_proc.call + thd.join end def get_test_proc(grpc_class) diff --git a/src/ruby/end2end/grpc_class_init_driver.rb b/src/ruby/end2end/grpc_class_init_driver.rb index 195da3cf9f8..c65ed547c54 100755 --- a/src/ruby/end2end/grpc_class_init_driver.rb +++ b/src/ruby/end2end/grpc_class_init_driver.rb @@ -65,9 +65,9 @@ def main end client_exit_code = $CHILD_STATUS - # concurrency stress test type is expected to exit with a - # non-zero status due to an exception being raised - if client_exit_code != 0 and stress_test_type != 'concurrency' + # concurrency stress test type is expected to exit with a + # non-zero status due to an exception being raised + if client_exit_code != 0 && stress_test_type != 'concurrency' fail "client failed, exit code #{client_exit_code}" end end diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 748fe663ed9..4e59174c3b3 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -368,8 +368,8 @@ void *wait_for_watch_state_op_complete_without_gvl(void *arg) { * state changes from "last_state". * */ VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, - VALUE last_state, - VALUE deadline) { + VALUE last_state, + VALUE deadline) { grpc_rb_channel *wrapper = NULL; watch_state_stack stack; void* op_success = 0; @@ -693,7 +693,6 @@ static void *set_abort_channel_polling_without_gil(void *arg) { return NULL; } - /* Temporary fix for * https://github.com/GoogleCloudPlatform/google-cloud-ruby/issues/899. * Transports in idle channels can get destroyed. Normally c-core re-connects, diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c index 584b5dbc63d..2a3b3391027 100644 --- a/src/ruby/ext/grpc/rb_grpc.c +++ b/src/ruby/ext/grpc/rb_grpc.c @@ -42,6 +42,7 @@ #include #include +#include #include "rb_call.h" #include "rb_call_credentials.h" #include "rb_channel.h" @@ -295,11 +296,12 @@ static gpr_once g_once_init = GPR_ONCE_INIT; static void grpc_ruby_once_init_internal() { grpc_init(); - grpc_rb_event_queue_thread_start(); - grpc_rb_channel_polling_thread_start(); atexit(grpc_rb_shutdown); } +static VALUE bg_thread_init_rb_mu = Qundef; +static int bg_thread_init_done = 0; + void grpc_ruby_once_init() { /* ruby_vm_at_exit doesn't seem to be working. It would crash once every * blue moon, and some users are getting it repeatedly. See the discussions @@ -312,6 +314,18 @@ void grpc_ruby_once_init() { * schedule our initialization and destruction only once. */ gpr_once_init(&g_once_init, grpc_ruby_once_init_internal); + + // Avoid calling calling into ruby library (when creating threads here) + // in gpr_once_init. In general, it appears to be unsafe to call + // into the ruby library while holding a non-ruby mutex, because a gil yield + // could end up trying to lock onto that same mutex and deadlocking. + rb_mutex_lock(bg_thread_init_rb_mu); + if (!bg_thread_init_done) { + grpc_rb_event_queue_thread_start(); + grpc_rb_channel_polling_thread_start(); + bg_thread_init_done = 1; + } + rb_mutex_unlock(bg_thread_init_rb_mu); } void Init_grpc_c() { @@ -320,6 +334,9 @@ void Init_grpc_c() { return; } + bg_thread_init_rb_mu = rb_mutex_new(); + rb_global_variable(&bg_thread_init_rb_mu); + grpc_rb_mGRPC = rb_define_module("GRPC"); grpc_rb_mGrpcCore = rb_define_module_under(grpc_rb_mGRPC, "Core"); grpc_rb_sNewServerRpc = From 7e44480614e2615821dabbece98989721d0cf6f4 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 17 May 2017 13:13:55 -0700 Subject: [PATCH 18/65] clang format --- src/ruby/ext/grpc/rb_channel.c | 138 +++++++++++++++++++-------------- 1 file changed, 78 insertions(+), 60 deletions(-) diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 4e59174c3b3..449c91a0f98 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -34,9 +34,9 @@ #include #include -#include "rb_grpc_imports.generated.h" #include "rb_byte_buffer.h" #include "rb_channel.h" +#include "rb_grpc_imports.generated.h" #include #include @@ -72,21 +72,19 @@ typedef struct bg_watched_channel { grpc_channel *channel; struct bg_watched_channel *next; int channel_destroyed; - int refcount; // must only be accessed under global_connection_polling_mu + int refcount; // must only be accessed under global_connection_polling_mu } bg_watched_channel; /* grpc_rb_channel wraps a grpc_channel. */ typedef struct grpc_rb_channel { VALUE credentials; - /* The actual channel (protected in a wrapper to tell when it's safe to destroy) */ + /* The actual channel (protected in a wrapper to tell when it's safe to + * destroy) */ bg_watched_channel *bg_wrapped; } grpc_rb_channel; -typedef enum { - CONTINUOUS_WATCH, - WATCH_STATE_API -} watch_state_op_type; +typedef enum { CONTINUOUS_WATCH, WATCH_STATE_API } watch_state_op_type; typedef struct watch_state_op { watch_state_op_type op_type; @@ -106,7 +104,7 @@ typedef struct watch_state_op { bg_watched_channel *bg_watched_channel_list_head = NULL; void grpc_rb_channel_try_register_connection_polling(bg_watched_channel *bg); -void *wait_until_channel_polling_thread_started_no_gil(void*); +void *wait_until_channel_polling_thread_started_no_gil(void *); void *channel_init_try_register_connection_polling_without_gil(void *arg); typedef struct channel_init_try_register_stack { @@ -121,12 +119,14 @@ int abort_channel_polling = 0; int channel_polling_thread_started = 0; int bg_watched_channel_list_lookup(bg_watched_channel *bg); -bg_watched_channel *bg_watched_channel_list_create_and_add(grpc_channel *channel); +bg_watched_channel *bg_watched_channel_list_create_and_add( + grpc_channel *channel); void bg_watched_channel_list_free_and_remove(bg_watched_channel *bg); -void run_poll_channels_loop_unblocking_func(void* arg); +void run_poll_channels_loop_unblocking_func(void *arg); // Needs to be called under global_connection_polling_mu -void grpc_rb_channel_watch_connection_state_op_complete(watch_state_op* op, int success) { +void grpc_rb_channel_watch_connection_state_op_complete(watch_state_op *op, + int success) { GPR_ASSERT(!op->op.api_callback_args.called_back); op->op.api_callback_args.called_back = 1; op->op.api_callback_args.success = success; @@ -150,7 +150,7 @@ void grpc_rb_channel_safe_destroy(bg_watched_channel *bg) { } void *channel_safe_destroy_without_gil(void *arg) { - grpc_rb_channel_safe_destroy((bg_watched_channel*)arg); + grpc_rb_channel_safe_destroy((bg_watched_channel *)arg); return NULL; } @@ -186,14 +186,14 @@ void grpc_rb_channel_mark(void *p) { } rb_data_type_t grpc_channel_data_type = {"grpc_channel", - {grpc_rb_channel_mark, - grpc_rb_channel_free, - GRPC_RB_MEMSIZE_UNAVAILABLE, - {NULL, NULL}}, - NULL, - NULL, + {grpc_rb_channel_mark, + grpc_rb_channel_free, + GRPC_RB_MEMSIZE_UNAVAILABLE, + {NULL, NULL}}, + NULL, + NULL, #ifdef RUBY_TYPED_FREE_IMMEDIATELY - RUBY_TYPED_FREE_IMMEDIATELY + RUBY_TYPED_FREE_IMMEDIATELY #endif }; @@ -226,8 +226,9 @@ VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { MEMZERO(&args, grpc_channel_args, 1); grpc_ruby_once_init(); - rb_thread_call_without_gvl(wait_until_channel_polling_thread_started_no_gil, NULL, - run_poll_channels_loop_unblocking_func, NULL); + rb_thread_call_without_gvl(wait_until_channel_polling_thread_started_no_gil, + NULL, run_poll_channels_loop_unblocking_func, + NULL); /* "3" == 3 mandatory args */ rb_scan_args(argc, argv, "3", &target, &channel_args, &credentials); @@ -252,7 +253,8 @@ VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { stack.channel = ch; stack.wrapper = wrapper; rb_thread_call_without_gvl( - channel_init_try_register_connection_polling_without_gil, &stack, NULL, NULL); + channel_init_try_register_connection_polling_without_gil, &stack, NULL, + NULL); if (args.args != NULL) { xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */ @@ -273,7 +275,7 @@ typedef struct get_state_stack { } get_state_stack; void *get_state_without_gil(void *arg) { - get_state_stack *stack = (get_state_stack*)arg; + get_state_stack *stack = (get_state_stack *)arg; gpr_mu_lock(&global_connection_polling_mu); GPR_ASSERT(abort_channel_polling || channel_polling_thread_started); @@ -282,7 +284,8 @@ void *get_state_without_gil(void *arg) { // failed to start just always shows shutdown state. stack->out = GRPC_CHANNEL_SHUTDOWN; } else { - stack->out = grpc_channel_check_connectivity_state(stack->channel, stack->try_to_connect); + stack->out = grpc_channel_check_connectivity_state(stack->channel, + stack->try_to_connect); } gpr_mu_unlock(&global_connection_polling_mu); @@ -299,7 +302,7 @@ void *get_state_without_gil(void *arg) { It also tries to connect if the chennel is idle in the second form. */ VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv, - VALUE self) { + VALUE self) { VALUE try_to_connect_param = Qfalse; int grpc_try_to_connect = 0; grpc_rb_channel *wrapper = NULL; @@ -329,30 +332,30 @@ typedef struct watch_state_stack { } watch_state_stack; void *wait_for_watch_state_op_complete_without_gvl(void *arg) { - watch_state_stack *stack = (watch_state_stack*)arg; + watch_state_stack *stack = (watch_state_stack *)arg; watch_state_op *op = NULL; - void *success = (void*)0; + void *success = (void *)0; gpr_mu_lock(&global_connection_polling_mu); // its unsafe to do a "watch" after "channel polling abort" because the cq has // been shut down. if (abort_channel_polling) { gpr_mu_unlock(&global_connection_polling_mu); - return (void*)0; + return (void *)0; } op = gpr_zalloc(sizeof(watch_state_op)); op->op_type = WATCH_STATE_API; // one ref for this thread and another for the callback-running thread - grpc_channel_watch_connectivity_state( - stack->channel, stack->last_state, stack->deadline, channel_polling_cq, op); + grpc_channel_watch_connectivity_state(stack->channel, stack->last_state, + stack->deadline, channel_polling_cq, + op); - while(!op->op.api_callback_args.called_back) { - gpr_cv_wait(&global_connection_polling_cv, - &global_connection_polling_mu, + while (!op->op.api_callback_args.called_back) { + gpr_cv_wait(&global_connection_polling_cv, &global_connection_polling_mu, gpr_inf_future(GPR_CLOCK_REALTIME)); } if (op->op.api_callback_args.success) { - success = (void*)1; + success = (void *)1; } gpr_free(op); gpr_mu_unlock(&global_connection_polling_mu); @@ -367,12 +370,11 @@ void *wait_for_watch_state_op_complete_without_gvl(void *arg) { * Returns false if "deadline" expires before the channel's connectivity * state changes from "last_state". * */ -VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, - VALUE last_state, +VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, VALUE last_state, VALUE deadline) { grpc_rb_channel *wrapper = NULL; watch_state_stack stack; - void* op_success = 0; + void *op_success = 0; TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); @@ -382,7 +384,9 @@ VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, } if (!FIXNUM_P(last_state)) { - rb_raise(rb_eTypeError, "bad type for last_state. want a GRPC::Core::ChannelState constant"); + rb_raise( + rb_eTypeError, + "bad type for last_state. want a GRPC::Core::ChannelState constant"); return Qnil; } @@ -391,7 +395,8 @@ VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, stack.last_state = NUM2LONG(last_state); op_success = rb_thread_call_without_gvl( - wait_for_watch_state_op_complete_without_gvl, &stack, run_poll_channels_loop_unblocking_func, NULL); + wait_for_watch_state_op_complete_without_gvl, &stack, + run_poll_channels_loop_unblocking_func, NULL); return op_success ? Qtrue : Qfalse; } @@ -399,8 +404,7 @@ VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, /* Create a call given a grpc_channel, in order to call method. The request is not sent until grpc_call_invoke is called. */ VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, - VALUE method, VALUE host, - VALUE deadline) { + VALUE method, VALUE host, VALUE deadline) { VALUE res = Qnil; grpc_rb_channel *wrapper = NULL; grpc_call *call = NULL; @@ -434,8 +438,8 @@ VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, method_slice = grpc_slice_from_copied_buffer(RSTRING_PTR(method), RSTRING_LEN(method)); - call = grpc_channel_create_call(wrapper->bg_wrapped->channel, parent_call, flags, cq, method_slice, - host_slice_ptr, + call = grpc_channel_create_call(wrapper->bg_wrapped->channel, parent_call, + flags, cq, method_slice, host_slice_ptr, grpc_rb_time_timeval(deadline, /* absolute time */ 0), NULL); @@ -467,8 +471,8 @@ VALUE grpc_rb_channel_destroy(VALUE self) { TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); if (wrapper->bg_wrapped != NULL) { - rb_thread_call_without_gvl( - channel_safe_destroy_without_gil, wrapper->bg_wrapped, NULL, NULL); + rb_thread_call_without_gvl(channel_safe_destroy_without_gil, + wrapper->bg_wrapped, NULL, NULL); wrapper->bg_wrapped = NULL; } @@ -504,7 +508,8 @@ int bg_watched_channel_list_lookup(bg_watched_channel *target) { } /* Needs to be called under global_connection_polling_mu */ -bg_watched_channel *bg_watched_channel_list_create_and_add(grpc_channel *channel) { +bg_watched_channel *bg_watched_channel_list_create_and_add( + grpc_channel *channel) { bg_watched_channel *watched = gpr_zalloc(sizeof(bg_watched_channel)); watched->channel = channel; @@ -540,10 +545,12 @@ void bg_watched_channel_list_free_and_remove(bg_watched_channel *target) { /* Initialize a grpc_rb_channel's "protected grpc_channel" and try to push * it onto the background thread for constant watches. */ void *channel_init_try_register_connection_polling_without_gil(void *arg) { - channel_init_try_register_stack *stack = (channel_init_try_register_stack*)arg; + channel_init_try_register_stack *stack = + (channel_init_try_register_stack *)arg; gpr_mu_lock(&global_connection_polling_mu); - stack->wrapper->bg_wrapped = bg_watched_channel_list_create_and_add(stack->channel); + stack->wrapper->bg_wrapped = + bg_watched_channel_list_create_and_add(stack->channel); grpc_rb_channel_try_register_connection_polling(stack->wrapper->bg_wrapped); gpr_mu_unlock(&global_connection_polling_mu); return NULL; @@ -581,8 +588,9 @@ void grpc_rb_channel_try_register_connection_polling(bg_watched_channel *bg) { op = gpr_zalloc(sizeof(watch_state_op)); op->op_type = CONTINUOUS_WATCH; op->op.continuous_watch_callback_args.bg = bg; - grpc_channel_watch_connectivity_state( - bg->channel, conn_state, gpr_inf_future(GPR_CLOCK_REALTIME), channel_polling_cq, op); + grpc_channel_watch_connectivity_state(bg->channel, conn_state, + gpr_inf_future(GPR_CLOCK_REALTIME), + channel_polling_cq, op); } // Note this loop breaks out with a single call of @@ -612,14 +620,15 @@ void *run_poll_channels_loop_no_gil(void *arg) { } gpr_mu_lock(&global_connection_polling_mu); if (event.type == GRPC_OP_COMPLETE) { - op = (watch_state_op*)event.tag; + op = (watch_state_op *)event.tag; if (op->op_type == CONTINUOUS_WATCH) { - bg = (bg_watched_channel*)op->op.continuous_watch_callback_args.bg; + bg = (bg_watched_channel *)op->op.continuous_watch_callback_args.bg; bg->refcount--; grpc_rb_channel_try_register_connection_polling(bg); gpr_free(op); - } else if(op->op_type == WATCH_STATE_API) { - grpc_rb_channel_watch_connection_state_op_complete((watch_state_op*)event.tag, event.success); + } else if (op->op_type == WATCH_STATE_API) { + grpc_rb_channel_watch_connection_state_op_complete( + (watch_state_op *)event.tag, event.success); } else { GPR_ASSERT(0); } @@ -627,7 +636,9 @@ void *run_poll_channels_loop_no_gil(void *arg) { gpr_mu_unlock(&global_connection_polling_mu); } grpc_completion_queue_destroy(channel_polling_cq); - gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop_no_gil - exit connection polling loop"); + gpr_log(GPR_DEBUG, + "GRPC_RUBY: run_poll_channels_loop_no_gil - exit connection polling " + "loop"); return NULL; } @@ -637,7 +648,9 @@ void run_poll_channels_loop_unblocking_func(void *arg) { (void)arg; gpr_mu_lock(&global_connection_polling_mu); - gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop_unblocking_func - begin aborting connection polling"); + gpr_log(GPR_DEBUG, + "GRPC_RUBY: run_poll_channels_loop_unblocking_func - begin aborting " + "connection polling"); // early out after first time through if (abort_channel_polling) { gpr_mu_unlock(&global_connection_polling_mu); @@ -647,7 +660,7 @@ void run_poll_channels_loop_unblocking_func(void *arg) { // force pending watches to end by switching to shutdown state bg = bg_watched_channel_list_head; - while(bg != NULL) { + while (bg != NULL) { if (!bg->channel_destroyed) { grpc_channel_destroy(bg->channel); bg->channel_destroyed = 1; @@ -658,13 +671,17 @@ void run_poll_channels_loop_unblocking_func(void *arg) { grpc_completion_queue_shutdown(channel_polling_cq); gpr_cv_broadcast(&global_connection_polling_cv); gpr_mu_unlock(&global_connection_polling_mu); - gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop_unblocking_func - begin aborting connection polling 22222"); + gpr_log(GPR_DEBUG, + "GRPC_RUBY: run_poll_channels_loop_unblocking_func - end aborting " + "connection polling"); } // Poll channel connectivity states in background thread without the GIL. VALUE run_poll_channels_loop(VALUE arg) { (void)arg; - gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop - create connection polling thread"); + gpr_log( + GPR_DEBUG, + "GRPC_RUBY: run_poll_channels_loop - create connection polling thread"); rb_thread_call_without_gvl(run_poll_channels_loop_no_gil, NULL, run_poll_channels_loop_unblocking_func, NULL); @@ -718,7 +735,8 @@ void grpc_rb_channel_polling_thread_start() { if (!RTEST(background_thread)) { gpr_log(GPR_DEBUG, "GRPC_RUBY: failed to spawn channel polling thread"); - rb_thread_call_without_gvl(set_abort_channel_polling_without_gil, NULL, NULL, NULL); + rb_thread_call_without_gvl(set_abort_channel_polling_without_gil, NULL, + NULL, NULL); } } From 032f398543676818b3e0761f8bdd899c8c3616eb Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 17 May 2017 13:22:55 -0700 Subject: [PATCH 19/65] cleanup --- src/ruby/ext/grpc/rb_call.c | 2 +- src/ruby/ext/grpc/rb_channel.c | 132 ++++++++++++----------- src/ruby/ext/grpc/rb_completion_queue.c | 14 +-- src/ruby/ext/grpc/rb_completion_queue.h | 2 +- src/ruby/ext/grpc/rb_grpc.c | 1 - src/ruby/ext/grpc/rb_server.c | 2 +- src/ruby/spec/channel_connection_spec.rb | 3 +- 7 files changed, 79 insertions(+), 77 deletions(-) diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c index 6cb71870f55..344cb941ffb 100644 --- a/src/ruby/ext/grpc/rb_call.c +++ b/src/ruby/ext/grpc/rb_call.c @@ -103,7 +103,7 @@ static void destroy_call(grpc_rb_call *call) { if (call->wrapped != NULL) { grpc_call_destroy(call->wrapped); call->wrapped = NULL; - grpc_rb_completion_queue_safe_destroy(call->queue); + grpc_rb_completion_queue_destroy(call->queue); call->queue = NULL; } } diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 449c91a0f98..e02dd0805d3 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -52,27 +52,28 @@ /* id_channel is the name of the hidden ivar that preserves a reference to the * channel on a call, so that calls are not GCed before their channel. */ -ID id_channel; +static ID id_channel; /* id_target is the name of the hidden ivar that preserves a reference to the * target string used to create the call, preserved so that it does not get * GCed before the channel */ -ID id_target; +static ID id_target; /* id_insecure_channel is used to indicate that a channel is insecure */ -VALUE id_insecure_channel; +static VALUE id_insecure_channel; /* grpc_rb_cChannel is the ruby class that proxies grpc_channel. */ -VALUE grpc_rb_cChannel = Qnil; +static VALUE grpc_rb_cChannel = Qnil; /* Used during the conversion of a hash to channel args during channel setup */ -VALUE grpc_rb_cChannelArgs; +static VALUE grpc_rb_cChannelArgs; typedef struct bg_watched_channel { grpc_channel *channel; + // these fields must only be accessed under global_connection_polling_mu struct bg_watched_channel *next; int channel_destroyed; - int refcount; // must only be accessed under global_connection_polling_mu + int refcount; } bg_watched_channel; /* grpc_rb_channel wraps a grpc_channel. */ @@ -101,32 +102,34 @@ typedef struct watch_state_op { } op; } watch_state_op; -bg_watched_channel *bg_watched_channel_list_head = NULL; +static bg_watched_channel *bg_watched_channel_list_head = NULL; -void grpc_rb_channel_try_register_connection_polling(bg_watched_channel *bg); -void *wait_until_channel_polling_thread_started_no_gil(void *); -void *channel_init_try_register_connection_polling_without_gil(void *arg); +static void grpc_rb_channel_try_register_connection_polling( + bg_watched_channel *bg); +static void *wait_until_channel_polling_thread_started_no_gil(void *); +static void *channel_init_try_register_connection_polling_without_gil( + void *arg); typedef struct channel_init_try_register_stack { grpc_channel *channel; grpc_rb_channel *wrapper; } channel_init_try_register_stack; -grpc_completion_queue *channel_polling_cq; -gpr_mu global_connection_polling_mu; -gpr_cv global_connection_polling_cv; -int abort_channel_polling = 0; -int channel_polling_thread_started = 0; +static grpc_completion_queue *channel_polling_cq; +static gpr_mu global_connection_polling_mu; +static gpr_cv global_connection_polling_cv; +static int abort_channel_polling = 0; +static int channel_polling_thread_started = 0; -int bg_watched_channel_list_lookup(bg_watched_channel *bg); -bg_watched_channel *bg_watched_channel_list_create_and_add( +static int bg_watched_channel_list_lookup(bg_watched_channel *bg); +static bg_watched_channel *bg_watched_channel_list_create_and_add( grpc_channel *channel); -void bg_watched_channel_list_free_and_remove(bg_watched_channel *bg); -void run_poll_channels_loop_unblocking_func(void *arg); +static void bg_watched_channel_list_free_and_remove(bg_watched_channel *bg); +static void run_poll_channels_loop_unblocking_func(void *arg); // Needs to be called under global_connection_polling_mu -void grpc_rb_channel_watch_connection_state_op_complete(watch_state_op *op, - int success) { +static void grpc_rb_channel_watch_connection_state_op_complete( + watch_state_op *op, int success) { GPR_ASSERT(!op->op.api_callback_args.called_back); op->op.api_callback_args.called_back = 1; op->op.api_callback_args.success = success; @@ -135,7 +138,7 @@ void grpc_rb_channel_watch_connection_state_op_complete(watch_state_op *op, } /* Avoids destroying a channel twice. */ -void grpc_rb_channel_safe_destroy(bg_watched_channel *bg) { +static void grpc_rb_channel_safe_destroy(bg_watched_channel *bg) { gpr_mu_lock(&global_connection_polling_mu); GPR_ASSERT(bg_watched_channel_list_lookup(bg)); if (!bg->channel_destroyed) { @@ -149,13 +152,13 @@ void grpc_rb_channel_safe_destroy(bg_watched_channel *bg) { gpr_mu_unlock(&global_connection_polling_mu); } -void *channel_safe_destroy_without_gil(void *arg) { +static void *channel_safe_destroy_without_gil(void *arg) { grpc_rb_channel_safe_destroy((bg_watched_channel *)arg); return NULL; } /* Destroys Channel instances. */ -void grpc_rb_channel_free(void *p) { +static void grpc_rb_channel_free(void *p) { grpc_rb_channel *ch = NULL; if (p == NULL) { return; @@ -165,7 +168,8 @@ void grpc_rb_channel_free(void *p) { if (ch->bg_wrapped != NULL) { /* assumption made here: it's ok to directly gpr_mu_lock the global * connection polling mutex becuse we're in a finalizer, - * and we can count on this thread to not be interrupted. */ + * and we can count on this thread to not be interrupted or + * yield the gil. */ grpc_rb_channel_safe_destroy(ch->bg_wrapped); ch->bg_wrapped = NULL; } @@ -174,7 +178,7 @@ void grpc_rb_channel_free(void *p) { } /* Protects the mark object from GC */ -void grpc_rb_channel_mark(void *p) { +static void grpc_rb_channel_mark(void *p) { grpc_rb_channel *channel = NULL; if (p == NULL) { return; @@ -185,20 +189,20 @@ void grpc_rb_channel_mark(void *p) { } } -rb_data_type_t grpc_channel_data_type = {"grpc_channel", - {grpc_rb_channel_mark, - grpc_rb_channel_free, - GRPC_RB_MEMSIZE_UNAVAILABLE, - {NULL, NULL}}, - NULL, - NULL, +static rb_data_type_t grpc_channel_data_type = {"grpc_channel", + {grpc_rb_channel_mark, + grpc_rb_channel_free, + GRPC_RB_MEMSIZE_UNAVAILABLE, + {NULL, NULL}}, + NULL, + NULL, #ifdef RUBY_TYPED_FREE_IMMEDIATELY - RUBY_TYPED_FREE_IMMEDIATELY + RUBY_TYPED_FREE_IMMEDIATELY #endif }; /* Allocates grpc_rb_channel instances. */ -VALUE grpc_rb_channel_alloc(VALUE cls) { +static VALUE grpc_rb_channel_alloc(VALUE cls) { grpc_rb_channel *wrapper = ALLOC(grpc_rb_channel); wrapper->bg_wrapped = NULL; wrapper->credentials = Qnil; @@ -213,7 +217,7 @@ VALUE grpc_rb_channel_alloc(VALUE cls) { secure_channel = Channel:new("myhost:443", {'arg1': 'value1'}, creds) Creates channel instances. */ -VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { +static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { VALUE channel_args = Qnil; VALUE credentials = Qnil; VALUE target = Qnil; @@ -274,13 +278,15 @@ typedef struct get_state_stack { int out; } get_state_stack; -void *get_state_without_gil(void *arg) { +static void *get_state_without_gil(void *arg) { get_state_stack *stack = (get_state_stack *)arg; gpr_mu_lock(&global_connection_polling_mu); GPR_ASSERT(abort_channel_polling || channel_polling_thread_started); if (abort_channel_polling) { - // the case in which the channel polling thread + // Assume that this channel has been destroyed by the + // background thread. + // The case in which the channel polling thread // failed to start just always shows shutdown state. stack->out = GRPC_CHANNEL_SHUTDOWN; } else { @@ -301,16 +307,14 @@ void *get_state_without_gil(void *arg) { constants defined in GRPC::Core::ConnectivityStates. It also tries to connect if the chennel is idle in the second form. */ -VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv, - VALUE self) { +static VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv, + VALUE self) { VALUE try_to_connect_param = Qfalse; - int grpc_try_to_connect = 0; grpc_rb_channel *wrapper = NULL; get_state_stack stack; /* "01" == 0 mandatory args, 1 (try_to_connect) is optional */ rb_scan_args(argc, argv, "01", &try_to_connect_param); - grpc_try_to_connect = RTEST(try_to_connect_param) ? 1 : 0; TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); if (wrapper->bg_wrapped == NULL) { @@ -319,7 +323,7 @@ VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv, } stack.channel = wrapper->bg_wrapped->channel; - stack.try_to_connect = grpc_try_to_connect; + stack.try_to_connect = RTEST(try_to_connect_param) ? 1 : 0; rb_thread_call_without_gvl(get_state_without_gil, &stack, NULL, NULL); return LONG2NUM(stack.out); @@ -331,7 +335,7 @@ typedef struct watch_state_stack { int last_state; } watch_state_stack; -void *wait_for_watch_state_op_complete_without_gvl(void *arg) { +static void *wait_for_watch_state_op_complete_without_gvl(void *arg) { watch_state_stack *stack = (watch_state_stack *)arg; watch_state_op *op = NULL; void *success = (void *)0; @@ -345,7 +349,6 @@ void *wait_for_watch_state_op_complete_without_gvl(void *arg) { } op = gpr_zalloc(sizeof(watch_state_op)); op->op_type = WATCH_STATE_API; - // one ref for this thread and another for the callback-running thread grpc_channel_watch_connectivity_state(stack->channel, stack->last_state, stack->deadline, channel_polling_cq, op); @@ -370,8 +373,9 @@ void *wait_for_watch_state_op_complete_without_gvl(void *arg) { * Returns false if "deadline" expires before the channel's connectivity * state changes from "last_state". * */ -VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, VALUE last_state, - VALUE deadline) { +static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, + VALUE last_state, + VALUE deadline) { grpc_rb_channel *wrapper = NULL; watch_state_stack stack; void *op_success = 0; @@ -403,8 +407,9 @@ VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, VALUE last_state, /* Create a call given a grpc_channel, in order to call method. The request is not sent until grpc_call_invoke is called. */ -VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, - VALUE method, VALUE host, VALUE deadline) { +static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, + VALUE method, VALUE host, + VALUE deadline) { VALUE res = Qnil; grpc_rb_channel *wrapper = NULL; grpc_call *call = NULL; @@ -466,7 +471,7 @@ VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, /* Closes the channel, calling it's destroy method */ /* Note this is an API-level call; a wrapped channel's finalizer doesn't call * this */ -VALUE grpc_rb_channel_destroy(VALUE self) { +static VALUE grpc_rb_channel_destroy(VALUE self) { grpc_rb_channel *wrapper = NULL; TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); @@ -480,7 +485,7 @@ VALUE grpc_rb_channel_destroy(VALUE self) { } /* Called to obtain the target that this channel accesses. */ -VALUE grpc_rb_channel_get_target(VALUE self) { +static VALUE grpc_rb_channel_get_target(VALUE self) { grpc_rb_channel *wrapper = NULL; VALUE res = Qnil; char *target = NULL; @@ -494,7 +499,7 @@ VALUE grpc_rb_channel_get_target(VALUE self) { } /* Needs to be called under global_connection_polling_mu */ -int bg_watched_channel_list_lookup(bg_watched_channel *target) { +static int bg_watched_channel_list_lookup(bg_watched_channel *target) { bg_watched_channel *cur = bg_watched_channel_list_head; while (cur != NULL) { @@ -508,7 +513,7 @@ int bg_watched_channel_list_lookup(bg_watched_channel *target) { } /* Needs to be called under global_connection_polling_mu */ -bg_watched_channel *bg_watched_channel_list_create_and_add( +static bg_watched_channel *bg_watched_channel_list_create_and_add( grpc_channel *channel) { bg_watched_channel *watched = gpr_zalloc(sizeof(bg_watched_channel)); @@ -520,7 +525,8 @@ bg_watched_channel *bg_watched_channel_list_create_and_add( } /* Needs to be called under global_connection_polling_mu */ -void bg_watched_channel_list_free_and_remove(bg_watched_channel *target) { +static void bg_watched_channel_list_free_and_remove( + bg_watched_channel *target) { bg_watched_channel *bg = NULL; GPR_ASSERT(bg_watched_channel_list_lookup(target)); @@ -544,7 +550,8 @@ void bg_watched_channel_list_free_and_remove(bg_watched_channel *target) { /* Initialize a grpc_rb_channel's "protected grpc_channel" and try to push * it onto the background thread for constant watches. */ -void *channel_init_try_register_connection_polling_without_gil(void *arg) { +static void *channel_init_try_register_connection_polling_without_gil( + void *arg) { channel_init_try_register_stack *stack = (channel_init_try_register_stack *)arg; @@ -557,7 +564,8 @@ void *channel_init_try_register_connection_polling_without_gil(void *arg) { } // Needs to be called under global_connection_poolling_mu -void grpc_rb_channel_try_register_connection_polling(bg_watched_channel *bg) { +static void grpc_rb_channel_try_register_connection_polling( + bg_watched_channel *bg) { grpc_connectivity_state conn_state; watch_state_op *op = NULL; @@ -599,7 +607,7 @@ void grpc_rb_channel_try_register_connection_polling(bg_watched_channel *bg) { // indicates process shutdown. // In the worst case, this stops polling channel connectivity // early and falls back to current behavior. -void *run_poll_channels_loop_no_gil(void *arg) { +static void *run_poll_channels_loop_no_gil(void *arg) { grpc_event event; watch_state_op *op = NULL; bg_watched_channel *bg = NULL; @@ -643,7 +651,7 @@ void *run_poll_channels_loop_no_gil(void *arg) { } // Notify the channel polling loop to cleanup and shutdown. -void run_poll_channels_loop_unblocking_func(void *arg) { +static void run_poll_channels_loop_unblocking_func(void *arg) { bg_watched_channel *bg = NULL; (void)arg; @@ -677,7 +685,7 @@ void run_poll_channels_loop_unblocking_func(void *arg) { } // Poll channel connectivity states in background thread without the GIL. -VALUE run_poll_channels_loop(VALUE arg) { +static VALUE run_poll_channels_loop(VALUE arg) { (void)arg; gpr_log( GPR_DEBUG, @@ -688,7 +696,7 @@ VALUE run_poll_channels_loop(VALUE arg) { return Qnil; } -void *wait_until_channel_polling_thread_started_no_gil(void *arg) { +static void *wait_until_channel_polling_thread_started_no_gil(void *arg) { (void)arg; gpr_log(GPR_DEBUG, "GRPC_RUBY: wait for channel polling thread to start"); gpr_mu_lock(&global_connection_polling_mu); @@ -740,7 +748,7 @@ void grpc_rb_channel_polling_thread_start() { } } -void Init_grpc_propagate_masks() { +static void Init_grpc_propagate_masks() { /* Constants representing call propagation masks in grpc.h */ VALUE grpc_rb_mPropagateMasks = rb_define_module_under(grpc_rb_mGrpcCore, "PropagateMasks"); @@ -756,7 +764,7 @@ void Init_grpc_propagate_masks() { UINT2NUM(GRPC_PROPAGATE_DEFAULTS)); } -void Init_grpc_connectivity_states() { +static void Init_grpc_connectivity_states() { /* Constants representing call propagation masks in grpc.h */ VALUE grpc_rb_mConnectivityStates = rb_define_module_under(grpc_rb_mGrpcCore, "ConnectivityStates"); diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c index 9f3a81b1a8b..fd75d2f691f 100644 --- a/src/ruby/ext/grpc/rb_completion_queue.c +++ b/src/ruby/ext/grpc/rb_completion_queue.c @@ -71,16 +71,12 @@ static void *grpc_rb_completion_queue_pluck_no_gil(void *param) { } /* Helper function to free a completion queue. */ -void grpc_rb_completion_queue_safe_destroy(grpc_completion_queue *cq) { - grpc_event ev; - +void grpc_rb_completion_queue_destroy(grpc_completion_queue *cq) { + /* Every function that adds an event to a queue also synchronously plucks + that event from the queue, and holds a reference to the Ruby object that + holds the queue, so we only get to this point if all of those functions + have completed, and the queue is empty */ grpc_completion_queue_shutdown(cq); - for(;;) { - ev = grpc_completion_queue_pluck(cq, NULL, gpr_inf_future(GPR_CLOCK_REALTIME), NULL); - if (ev.type == GRPC_QUEUE_SHUTDOWN) { - break; - } - } grpc_completion_queue_destroy(cq); } diff --git a/src/ruby/ext/grpc/rb_completion_queue.h b/src/ruby/ext/grpc/rb_completion_queue.h index eb041b28dfc..aa9dc6416af 100644 --- a/src/ruby/ext/grpc/rb_completion_queue.h +++ b/src/ruby/ext/grpc/rb_completion_queue.h @@ -38,7 +38,7 @@ #include -void grpc_rb_completion_queue_safe_destroy(grpc_completion_queue *cq); +void grpc_rb_completion_queue_destroy(grpc_completion_queue *cq); /** * Makes the implementation of CompletionQueue#pluck available in other files diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c index 2a3b3391027..e0be5d7f087 100644 --- a/src/ruby/ext/grpc/rb_grpc.c +++ b/src/ruby/ext/grpc/rb_grpc.c @@ -42,7 +42,6 @@ #include #include -#include #include "rb_call.h" #include "rb_call_credentials.h" #include "rb_channel.h" diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c index 2b0858c247e..2286a99f249 100644 --- a/src/ruby/ext/grpc/rb_server.c +++ b/src/ruby/ext/grpc/rb_server.c @@ -77,7 +77,7 @@ static void destroy_server(grpc_rb_server *server, gpr_timespec deadline) { gpr_inf_future(GPR_CLOCK_REALTIME), NULL); } grpc_server_destroy(server->wrapped); - grpc_rb_completion_queue_safe_destroy(server->queue); + grpc_rb_completion_queue_destroy(server->queue); server->wrapped = NULL; server->queue = NULL; } diff --git a/src/ruby/spec/channel_connection_spec.rb b/src/ruby/spec/channel_connection_spec.rb index b3edec8f938..c8a7856a099 100644 --- a/src/ruby/spec/channel_connection_spec.rb +++ b/src/ruby/spec/channel_connection_spec.rb @@ -143,8 +143,7 @@ describe 'channel connection behavior' do stop_server end - it 'observably connects and reconnects to transient server' \ - ' when using the channel state API' do + it 'concurrent watches on the same channel' do timeout(180) do port = start_server ch = GRPC::Core::Channel.new("localhost:#{port}", {}, From c24d53b0cfffe2cd78d53c0c86de43346dcc7ee7 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 17 May 2017 20:25:38 -0700 Subject: [PATCH 20/65] api watch unblock func kills only its own channel --- ...multiple_killed_watching_threads_driver.rb | 56 +++++++++++++++++++ src/ruby/ext/grpc/rb_channel.c | 18 ++++-- .../helper_scripts/run_ruby_end2end_tests.sh | 1 + 3 files changed, 69 insertions(+), 6 deletions(-) create mode 100755 src/ruby/end2end/multiple_killed_watching_threads_driver.rb diff --git a/src/ruby/end2end/multiple_killed_watching_threads_driver.rb b/src/ruby/end2end/multiple_killed_watching_threads_driver.rb new file mode 100755 index 00000000000..0c98915b7ee --- /dev/null +++ b/src/ruby/end2end/multiple_killed_watching_threads_driver.rb @@ -0,0 +1,56 @@ +#!/usr/bin/env ruby + +# Copyright 2016, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +require_relative './end2end_common' + +Thread.abort_on_exception = true + +include GRPC::Core::ConnectivityStates + +def watch_state(ch) + thd = Thread.new do + state = ch.connectivity_state(false) + fail "non-idle state: #{state}" unless state == IDLE + ch.watch_connectivity_state(IDLE, Time.now + 360) + end + sleep 0.1 + thd.kill +end + +def main + 10.times do + ch = GRPC::Core::Channel.new('dummy_host', + nil, :this_channel_is_insecure) + watch_state(ch) + end +end + +main diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index e02dd0805d3..6e7baa31220 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -366,6 +366,16 @@ static void *wait_for_watch_state_op_complete_without_gvl(void *arg) { return success; } +static void wait_for_watch_state_op_complete_unblocking_func(void *arg) { + bg_watched_channel *bg = (bg_watched_channel *)arg; + gpr_mu_lock(&global_connection_polling_mu); + if (!bg->channel_destroyed) { + grpc_channel_destroy(bg->channel); + bg->channel_destroyed = 1; + } + gpr_mu_unlock(&global_connection_polling_mu); +} + /* Wait until the channel's connectivity state becomes different from * "last_state", or "deadline" expires. * Returns true if the the channel's connectivity state becomes @@ -400,7 +410,7 @@ static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, op_success = rb_thread_call_without_gvl( wait_for_watch_state_op_complete_without_gvl, &stack, - run_poll_channels_loop_unblocking_func, NULL); + wait_for_watch_state_op_complete_unblocking_func, wrapper->bg_wrapped); return op_success ? Qtrue : Qfalse; } @@ -577,11 +587,7 @@ static void grpc_rb_channel_try_register_connection_polling( return; } GPR_ASSERT(bg->refcount == 1); - if (bg->channel_destroyed) { - GPR_ASSERT(abort_channel_polling); - return; - } - if (abort_channel_polling) { + if (bg->channel_destroyed || abort_channel_polling) { return; } diff --git a/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh b/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh index 6688025260f..ab882d62bc7 100755 --- a/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh +++ b/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh @@ -41,4 +41,5 @@ ruby src/ruby/end2end/sig_int_during_channel_watch_driver.rb || EXIT_CODE=1 ruby src/ruby/end2end/killed_client_thread_driver.rb || EXIT_CODE=1 ruby src/ruby/end2end/forking_client_driver.rb || EXIT_CODE=1 ruby src/ruby/end2end/grpc_class_init_driver.rb || EXIT_CODE=1 +ruby src/ruby/end2end/multiple_killed_watching_threads_driver.rb || EXIT_CODE=1 exit $EXIT_CODE From d7455abfbd1394a6984b901a305785e9cba7b2d6 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 17 May 2017 21:39:09 -0700 Subject: [PATCH 21/65] make get conn state always safe to call --- .../multiple_killed_watching_threads_driver.rb | 7 +++++++ src/ruby/ext/grpc/rb_channel.c | 12 ++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/ruby/end2end/multiple_killed_watching_threads_driver.rb b/src/ruby/end2end/multiple_killed_watching_threads_driver.rb index 0c98915b7ee..206ec8e801f 100755 --- a/src/ruby/end2end/multiple_killed_watching_threads_driver.rb +++ b/src/ruby/end2end/multiple_killed_watching_threads_driver.rb @@ -46,10 +46,17 @@ def watch_state(ch) end def main + channels = [] 10.times do ch = GRPC::Core::Channel.new('dummy_host', nil, :this_channel_is_insecure) watch_state(ch) + channels << ch + end + + # checking state should still be safe to call + channels.each do |c| + fail unless c.connectivity_state(false) == FATAL_FAILURE end end diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 6e7baa31220..0524c497100 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -273,7 +273,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { } typedef struct get_state_stack { - grpc_channel *channel; + bg_watched_channel *bg; int try_to_connect; int out; } get_state_stack; @@ -283,14 +283,10 @@ static void *get_state_without_gil(void *arg) { gpr_mu_lock(&global_connection_polling_mu); GPR_ASSERT(abort_channel_polling || channel_polling_thread_started); - if (abort_channel_polling) { - // Assume that this channel has been destroyed by the - // background thread. - // The case in which the channel polling thread - // failed to start just always shows shutdown state. + if (stack->bg->channel_destroyed) { stack->out = GRPC_CHANNEL_SHUTDOWN; } else { - stack->out = grpc_channel_check_connectivity_state(stack->channel, + stack->out = grpc_channel_check_connectivity_state(stack->bg->channel, stack->try_to_connect); } gpr_mu_unlock(&global_connection_polling_mu); @@ -322,7 +318,7 @@ static VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv, return Qnil; } - stack.channel = wrapper->bg_wrapped->channel; + stack.bg = wrapper->bg_wrapped; stack.try_to_connect = RTEST(try_to_connect_param) ? 1 : 0; rb_thread_call_without_gvl(get_state_without_gil, &stack, NULL, NULL); From 82fef0bce75fd18fb468ad8a9363040e6c6e84fc Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 17 May 2017 23:42:38 -0700 Subject: [PATCH 22/65] tentative fix for global side effect on interrupted constructor --- src/ruby/ext/grpc/rb_channel.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 0524c497100..7aaa71eeafc 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -107,6 +107,7 @@ static bg_watched_channel *bg_watched_channel_list_head = NULL; static void grpc_rb_channel_try_register_connection_polling( bg_watched_channel *bg); static void *wait_until_channel_polling_thread_started_no_gil(void *); +static void wait_until_channel_polling_thread_started_unblocking_func(void *); static void *channel_init_try_register_connection_polling_without_gil( void *arg); @@ -227,12 +228,15 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { char *target_chars = NULL; grpc_channel_args args; channel_init_try_register_stack stack; + int stop_waiting_for_thread_start = 0; MEMZERO(&args, grpc_channel_args, 1); grpc_ruby_once_init(); - rb_thread_call_without_gvl(wait_until_channel_polling_thread_started_no_gil, - NULL, run_poll_channels_loop_unblocking_func, - NULL); + rb_thread_call_without_gvl( + wait_until_channel_polling_thread_started_no_gil, + &stop_waiting_for_thread_start, + wait_until_channel_polling_thread_started_unblocking_func, + &stop_waiting_for_thread_start); /* "3" == 3 mandatory args */ rb_scan_args(argc, argv, "3", &target, &channel_args, &credentials); @@ -699,10 +703,11 @@ static VALUE run_poll_channels_loop(VALUE arg) { } static void *wait_until_channel_polling_thread_started_no_gil(void *arg) { - (void)arg; + int *stop_waiting = (int *)arg; gpr_log(GPR_DEBUG, "GRPC_RUBY: wait for channel polling thread to start"); gpr_mu_lock(&global_connection_polling_mu); - while (!channel_polling_thread_started && !abort_channel_polling) { + while (!channel_polling_thread_started && !abort_channel_polling && + !*stop_waiting) { gpr_cv_wait(&global_connection_polling_cv, &global_connection_polling_mu, gpr_inf_future(GPR_CLOCK_REALTIME)); } @@ -711,6 +716,17 @@ static void *wait_until_channel_polling_thread_started_no_gil(void *arg) { return NULL; } +static void wait_until_channel_polling_thread_started_unblocking_func( + void *arg) { + int *stop_waiting = (int *)arg; + gpr_mu_lock(&global_connection_polling_mu); + gpr_log(GPR_DEBUG, + "GRPC_RUBY: interrupt wait for channel polling thread to start"); + *stop_waiting = 1; + gpr_cv_broadcast(&global_connection_polling_cv); + gpr_mu_unlock(&global_connection_polling_mu); +} + static void *set_abort_channel_polling_without_gil(void *arg) { (void)arg; gpr_mu_lock(&global_connection_polling_mu); From 9c156da66afde71361d07cf785a826e20ca85c9d Mon Sep 17 00:00:00 2001 From: Makarand Dharmapurikar Date: Thu, 18 May 2017 10:32:13 -0700 Subject: [PATCH 23/65] Fixes #9542 This fixes the case when a server is shutdown right after it Accept'ed a connection. The socket needs to be closed right before the endpoint is destroyed. --- src/core/ext/transport/chttp2/server/chttp2_server.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.c b/src/core/ext/transport/chttp2/server/chttp2_server.c index b9c62c376a1..2c076e821c3 100644 --- a/src/core/ext/transport/chttp2/server/chttp2_server.c +++ b/src/core/ext/transport/chttp2/server/chttp2_server.c @@ -127,6 +127,7 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *tcp, gpr_mu_lock(&state->mu); if (state->shutdown) { gpr_mu_unlock(&state->mu); + grpc_endpoint_shutdown(exec_ctx, tcp, GRPC_ERROR_NONE); grpc_endpoint_destroy(exec_ctx, tcp); gpr_free(acceptor); return; From 92eb7fbc05903def20434c110193481913c2e38a Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Thu, 18 May 2017 11:49:15 -0700 Subject: [PATCH 24/65] Bump to version 1.3.4 --- BUILD | 2 +- CMakeLists.txt | 2 +- Makefile | 4 ++-- build.yaml | 2 +- gRPC-Core.podspec | 2 +- gRPC-ProtoRPC.podspec | 2 +- gRPC-RxLibrary.podspec | 2 +- gRPC.podspec | 2 +- package.json | 2 +- package.xml | 4 ++-- src/cpp/common/version_cc.cc | 2 +- src/csharp/Grpc.Core/Version.csproj.include | 2 +- src/csharp/Grpc.Core/VersionInfo.cs | 4 ++-- src/csharp/build_packages_dotnetcli.bat | 2 +- src/csharp/build_packages_dotnetcli.sh | 4 ++-- src/node/health_check/package.json | 4 ++-- src/node/tools/package.json | 2 +- src/objective-c/!ProtoCompiler-gRPCPlugin.podspec | 2 +- src/objective-c/GRPCClient/private/version.h | 2 +- src/php/composer.json | 2 +- src/python/grpcio/grpc_version.py | 2 +- src/python/grpcio_health_checking/grpc_version.py | 2 +- src/python/grpcio_reflection/grpc_version.py | 2 +- src/python/grpcio_tests/grpc_version.py | 2 +- src/ruby/lib/grpc/version.rb | 2 +- src/ruby/tools/version.rb | 2 +- tools/distrib/python/grpcio_tools/grpc_version.py | 2 +- tools/doxygen/Doxyfile.c++ | 2 +- tools/doxygen/Doxyfile.c++.internal | 2 +- 29 files changed, 34 insertions(+), 34 deletions(-) diff --git a/BUILD b/BUILD index a0d80cd5735..51314f645c0 100644 --- a/BUILD +++ b/BUILD @@ -42,7 +42,7 @@ g_stands_for = "gentle" core_version = "3.0.0" -version = "1.3.3" +version = "1.3.4" grpc_cc_library( name = "gpr", diff --git a/CMakeLists.txt b/CMakeLists.txt index 279e12bbd0b..e344e413d15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ cmake_minimum_required(VERSION 2.8) set(PACKAGE_NAME "grpc") -set(PACKAGE_VERSION "1.3.3") +set(PACKAGE_VERSION "1.3.4") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/") diff --git a/Makefile b/Makefile index e5f23e75ad6..88bb5b5e5f9 100644 --- a/Makefile +++ b/Makefile @@ -420,8 +420,8 @@ Q = @ endif CORE_VERSION = 3.0.0 -CPP_VERSION = 1.3.3 -CSHARP_VERSION = 1.3.3 +CPP_VERSION = 1.3.4 +CSHARP_VERSION = 1.3.4 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES)) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) diff --git a/build.yaml b/build.yaml index 5d1e74b93a8..a42c9cf5500 100644 --- a/build.yaml +++ b/build.yaml @@ -14,7 +14,7 @@ settings: '#10': See the expand_version.py for all the quirks here core_version: 3.0.0 g_stands_for: gentle - version: 1.3.3 + version: 1.3.4 filegroups: - name: census public_headers: diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index a2237ac0855..c8e50b577ac 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -37,7 +37,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-Core' - version = '1.3.3' + version = '1.3.4' s.version = version s.summary = 'Core cross-platform gRPC library, written in C' s.homepage = 'http://www.grpc.io' diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec index 1af811aa558..6737e0136a8 100644 --- a/gRPC-ProtoRPC.podspec +++ b/gRPC-ProtoRPC.podspec @@ -36,7 +36,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-ProtoRPC' - version = '1.3.3' + version = '1.3.4' s.version = version s.summary = 'RPC library for Protocol Buffers, based on gRPC' s.homepage = 'http://www.grpc.io' diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec index 3f720f2393f..0b338d44aaf 100644 --- a/gRPC-RxLibrary.podspec +++ b/gRPC-RxLibrary.podspec @@ -36,7 +36,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-RxLibrary' - version = '1.3.3' + version = '1.3.4' s.version = version s.summary = 'Reactive Extensions library for iOS/OSX.' s.homepage = 'http://www.grpc.io' diff --git a/gRPC.podspec b/gRPC.podspec index b064c50ccfd..1783df67ef5 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -35,7 +35,7 @@ Pod::Spec.new do |s| s.name = 'gRPC' - version = '1.3.3' + version = '1.3.4' s.version = version s.summary = 'gRPC client library for iOS/OSX' s.homepage = 'http://www.grpc.io' diff --git a/package.json b/package.json index 2cb86a65a30..11e34416520 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.3.3", + "version": "1.3.4", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "http://www.grpc.io/", diff --git a/package.xml b/package.xml index faf36657577..6b3eddadf6d 100644 --- a/package.xml +++ b/package.xml @@ -13,8 +13,8 @@ 2017-05-05 - 1.3.3 - 1.3.3 + 1.3.4 + 1.3.4 beta diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc index 2d44fb9d084..97437ba5308 100644 --- a/src/cpp/common/version_cc.cc +++ b/src/cpp/common/version_cc.cc @@ -37,5 +37,5 @@ #include namespace grpc { -grpc::string Version() { return "1.3.3"; } +grpc::string Version() { return "1.3.4"; } } diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include index 9ececc9b95a..881c311b17e 100755 --- a/src/csharp/Grpc.Core/Version.csproj.include +++ b/src/csharp/Grpc.Core/Version.csproj.include @@ -1,7 +1,7 @@ - 1.3.3 + 1.3.4 3.2.0 diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs index 12cbc6f0491..bbe5a17d6b7 100644 --- a/src/csharp/Grpc.Core/VersionInfo.cs +++ b/src/csharp/Grpc.Core/VersionInfo.cs @@ -48,11 +48,11 @@ namespace Grpc.Core /// /// Current AssemblyFileVersion of gRPC C# assemblies /// - public const string CurrentAssemblyFileVersion = "1.3.3.0"; + public const string CurrentAssemblyFileVersion = "1.3.4.0"; /// /// Current version of gRPC C# /// - public const string CurrentVersion = "1.3.3"; + public const string CurrentVersion = "1.3.4"; } } diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat index 6806bbd2ae5..a385ac74e3e 100755 --- a/src/csharp/build_packages_dotnetcli.bat +++ b/src/csharp/build_packages_dotnetcli.bat @@ -28,7 +28,7 @@ @rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @rem Current package versions -set VERSION=1.3.3 +set VERSION=1.3.4 @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh index fc9fd50f596..66c41d4d940 100755 --- a/src/csharp/build_packages_dotnetcli.sh +++ b/src/csharp/build_packages_dotnetcli.sh @@ -70,7 +70,7 @@ dotnet pack --configuration Release --include-symbols --include-source Grpc.Auth dotnet pack --configuration Release --include-symbols --include-source Grpc.HealthCheck --output ../../../artifacts dotnet pack --configuration Release --include-symbols --include-source Grpc.Reflection --output ../../../artifacts -nuget pack Grpc.nuspec -Version "1.3.3" -OutputDirectory ../../artifacts -nuget pack Grpc.Tools.nuspec -Version "1.3.3" -OutputDirectory ../../artifacts +nuget pack Grpc.nuspec -Version "1.3.4" -OutputDirectory ../../artifacts +nuget pack Grpc.Tools.nuspec -Version "1.3.4" -OutputDirectory ../../artifacts (cd ../../artifacts && zip csharp_nugets_dotnetcli.zip *.nupkg) diff --git a/src/node/health_check/package.json b/src/node/health_check/package.json index fe36fb2693d..6329cd9c377 100644 --- a/src/node/health_check/package.json +++ b/src/node/health_check/package.json @@ -1,6 +1,6 @@ { "name": "grpc-health-check", - "version": "1.3.3", + "version": "1.3.4", "author": "Google Inc.", "description": "Health check service for use with gRPC", "repository": { @@ -15,7 +15,7 @@ } ], "dependencies": { - "grpc": "^1.3.3", + "grpc": "^1.3.4", "lodash": "^3.9.3", "google-protobuf": "^3.0.0" }, diff --git a/src/node/tools/package.json b/src/node/tools/package.json index caf2b5a5cb9..355ae2fdc1f 100644 --- a/src/node/tools/package.json +++ b/src/node/tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.3.3", + "version": "1.3.4", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "http://www.grpc.io/", diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec index 4e93c0f1b53..b4fc9685049 100644 --- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec +++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec @@ -42,7 +42,7 @@ Pod::Spec.new do |s| # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed # before them. s.name = '!ProtoCompiler-gRPCPlugin' - v = '1.3.3' + v = '1.3.4' s.version = v s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.' s.description = <<-DESC diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h index 66408f5bbb3..ccf96230bc1 100644 --- a/src/objective-c/GRPCClient/private/version.h +++ b/src/objective-c/GRPCClient/private/version.h @@ -38,4 +38,4 @@ // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.3.3" +#define GRPC_OBJC_VERSION_STRING @"1.3.4" diff --git a/src/php/composer.json b/src/php/composer.json index bbe33974d5e..562859e6b3d 100644 --- a/src/php/composer.json +++ b/src/php/composer.json @@ -2,7 +2,7 @@ "name": "grpc/grpc-dev", "description": "gRPC library for PHP - for Developement use only", "license": "BSD-3-Clause", - "version": "1.3.3", + "version": "1.3.4", "require": { "php": ">=5.5.0", "google/protobuf": "^v3.1.0" diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py index 027f6caf28c..29ffcab1065 100644 --- a/src/python/grpcio/grpc_version.py +++ b/src/python/grpcio/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!! -VERSION='1.3.3' +VERSION='1.3.4' diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py index f2db8bb056f..16e0dc13275 100644 --- a/src/python/grpcio_health_checking/grpc_version.py +++ b/src/python/grpcio_health_checking/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!! -VERSION='1.3.3' +VERSION='1.3.4' diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py index 3f33eb3ed55..5ef0ed8045e 100644 --- a/src/python/grpcio_reflection/grpc_version.py +++ b/src/python/grpcio_reflection/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!! -VERSION='1.3.3' +VERSION='1.3.4' diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py index 1a681d01360..7e4c57e6ec6 100644 --- a/src/python/grpcio_tests/grpc_version.py +++ b/src/python/grpcio_tests/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!! -VERSION='1.3.3' +VERSION='1.3.4' diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb index 4ab94c91324..c03ec97196b 100644 --- a/src/ruby/lib/grpc/version.rb +++ b/src/ruby/lib/grpc/version.rb @@ -29,5 +29,5 @@ # GRPC contains the General RPC module. module GRPC - VERSION = '1.3.3' + VERSION = '1.3.4' end diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb index 58e05d08143..fe0fb2cef21 100644 --- a/src/ruby/tools/version.rb +++ b/src/ruby/tools/version.rb @@ -29,6 +29,6 @@ module GRPC module Tools - VERSION = '1.3.3' + VERSION = '1.3.4' end end diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py index ecfa9d85e36..020785aa730 100644 --- a/tools/distrib/python/grpcio_tools/grpc_version.py +++ b/tools/distrib/python/grpcio_tools/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!! -VERSION='1.3.3' +VERSION='1.3.4' diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 8067aa764c1..5021a1a153b 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.3.3 +PROJECT_NUMBER = 1.3.4 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 1a94b01e35e..1df6951aef2 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.3.3 +PROJECT_NUMBER = 1.3.4 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From c3b1f18a7e7f443329f95ff25485c503ab76cc69 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Tue, 18 Apr 2017 13:51:36 -0700 Subject: [PATCH 25/65] get rid of connectivity state watchers right after timeout --- CMakeLists.txt | 32 +++ Makefile | 36 +++ build.yaml | 12 + grpc.def | 1 + include/grpc/grpc.h | 6 + .../client_channel/channel_connectivity.c | 77 ++++-- .../filters/client_channel/client_channel.c | 115 ++++++++- .../filters/client_channel/client_channel.h | 6 +- src/ruby/ext/grpc/rb_grpc_imports.generated.c | 2 + src/ruby/ext/grpc/rb_grpc_imports.generated.h | 3 + .../surface/concurrent_connectivity_test.c | 69 +++++- .../num_external_connectivity_watchers_test.c | 221 ++++++++++++++++++ .../surface/sequential_connectivity_test.c | 3 + .../generated/sources_and_headers.json | 17 ++ tools/run_tests/generated/tests.json | 24 ++ vsprojects/buildtests_c.sln | 27 +++ ...xternal_connectivity_watchers_test.vcxproj | 199 ++++++++++++++++ ...connectivity_watchers_test.vcxproj.filters | 21 ++ 18 files changed, 837 insertions(+), 34 deletions(-) create mode 100644 test/core/surface/num_external_connectivity_watchers_test.c create mode 100644 vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj create mode 100644 vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj.filters diff --git a/CMakeLists.txt b/CMakeLists.txt index 81dba56b9ef..553caab8806 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) @@ -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 ) diff --git a/Makefile b/Makefile index 9e3daabe405..68dc9de4926 100644 --- a/Makefile +++ b/Makefile @@ -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 @@ -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 \ @@ -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" @@ -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 \ diff --git a/build.yaml b/build.yaml index 5f23562022a..cb9e67ff0b4 100644 --- a/build.yaml +++ b/build.yaml @@ -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 diff --git a/grpc.def b/grpc.def index 1589316a588..534a23d6000 100644 --- a/grpc.def +++ b/grpc.def @@ -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 diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h index e088435d6cc..bdb86174118 100644 --- a/include/grpc/grpc.h +++ b/include/grpc/grpc.h @@ -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. diff --git a/src/core/ext/filters/client_channel/channel_connectivity.c b/src/core/ext/filters/client_channel/channel_connectivity.c index 62f58fb278a..5f3ffd49470 100644 --- a/src/core/ext/filters/client_channel/channel_connectivity.c +++ b/src/core/ext/filters/client_channel/channel_connectivity.c @@ -67,9 +67,8 @@ 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 { @@ -77,11 +76,13 @@ typedef struct { 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; @@ -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; @@ -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); @@ -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); } @@ -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) { @@ -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(); } diff --git a/src/core/ext/filters/client_channel/client_channel.c b/src/core/ext/filters/client_channel/client_channel.c index 83e3b8f118d..4bd153e8ac7 100644 --- a/src/core/ext/filters/client_channel/client_channel.c +++ b/src/core/ext/filters/client_channel/client_channel.c @@ -174,6 +174,8 @@ static void *method_parameters_create_from_json(const grpc_json *json) { return value; } +struct external_connectivity_watcher; + /************************************************************************* * CHANNEL-WIDE FUNCTIONS */ @@ -209,6 +211,11 @@ typedef struct client_channel_channel_data { /** interested parties (owned) */ grpc_pollset_set *interested_parties; + /* external_connectivity_watcher_list head is guarded by its own mutex, since + * counts need to be grabbed immediately without polling on a cq */ + gpr_mu external_connectivity_watcher_list_mu; + struct external_connectivity_watcher *external_connectivity_watcher_list_head; + /* the following properties are guarded by a mutex since API's require them to be instantaneously available */ gpr_mu info_mu; @@ -632,6 +639,12 @@ static grpc_error *cc_init_channel_elem(grpc_exec_ctx *exec_ctx, // Initialize data members. chand->combiner = grpc_combiner_create(NULL); gpr_mu_init(&chand->info_mu); + gpr_mu_init(&chand->external_connectivity_watcher_list_mu); + + gpr_mu_lock(&chand->external_connectivity_watcher_list_mu); + chand->external_connectivity_watcher_list_head = NULL; + gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu); + chand->owning_stack = args->channel_stack; grpc_closure_init(&chand->on_resolver_result_changed, on_resolver_result_changed_locked, chand, @@ -718,6 +731,7 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx, grpc_pollset_set_destroy(exec_ctx, chand->interested_parties); GRPC_COMBINER_UNREF(exec_ctx, chand->combiner, "client_channel"); gpr_mu_destroy(&chand->info_mu); + gpr_mu_destroy(&chand->external_connectivity_watcher_list_mu); } /************************************************************************* @@ -1361,14 +1375,79 @@ grpc_connectivity_state grpc_client_channel_check_connectivity_state( return out; } -typedef struct { +typedef struct external_connectivity_watcher { channel_data *chand; grpc_pollset *pollset; grpc_closure *on_complete; + grpc_closure *watcher_timer_init; grpc_connectivity_state *state; grpc_closure my_closure; + struct external_connectivity_watcher *next; } external_connectivity_watcher; +static external_connectivity_watcher *lookup_external_connectivity_watcher( + channel_data *chand, grpc_closure *on_complete) { + gpr_mu_lock(&chand->external_connectivity_watcher_list_mu); + external_connectivity_watcher *w = + chand->external_connectivity_watcher_list_head; + while (w != NULL && w->on_complete != on_complete) { + w = w->next; + } + gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu); + return w; +} + +static void external_connectivity_watcher_list_append( + channel_data *chand, external_connectivity_watcher *w) { + GPR_ASSERT(!lookup_external_connectivity_watcher(chand, w->on_complete)); + + gpr_mu_lock(&w->chand->external_connectivity_watcher_list_mu); + GPR_ASSERT(!w->next); + w->next = chand->external_connectivity_watcher_list_head; + chand->external_connectivity_watcher_list_head = w; + gpr_mu_unlock(&w->chand->external_connectivity_watcher_list_mu); +} + +static void external_connectivity_watcher_list_remove( + channel_data *chand, external_connectivity_watcher *too_remove) { + GPR_ASSERT( + lookup_external_connectivity_watcher(chand, too_remove->on_complete)); + gpr_mu_lock(&chand->external_connectivity_watcher_list_mu); + if (too_remove == chand->external_connectivity_watcher_list_head) { + chand->external_connectivity_watcher_list_head = too_remove->next; + gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu); + return; + } + external_connectivity_watcher *w = + chand->external_connectivity_watcher_list_head; + while (w != NULL) { + if (w->next == too_remove) { + w->next = w->next->next; + gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu); + return; + } + w = w->next; + } + GPR_UNREACHABLE_CODE(return ); +} + +int grpc_client_channel_num_external_connectivity_watchers( + grpc_channel_element *elem) { + channel_data *chand = elem->channel_data; + int count = 0; + + gpr_mu_lock(&chand->external_connectivity_watcher_list_mu); + external_connectivity_watcher *w = + chand->external_connectivity_watcher_list_head; + while (w != NULL) { + count++; + w = w->next; + } + gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu); + + return count; +} + static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { external_connectivity_watcher *w = arg; @@ -1377,6 +1456,7 @@ static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg, w->pollset); GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, "external_connectivity_watcher"); + external_connectivity_watcher_list_remove(w->chand, w); gpr_free(w); grpc_closure_run(exec_ctx, follow_up, GRPC_ERROR_REF(error)); } @@ -1384,21 +1464,42 @@ static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg, static void watch_connectivity_state_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error_ignored) { external_connectivity_watcher *w = arg; - grpc_closure_init(&w->my_closure, on_external_watch_complete, w, - grpc_schedule_on_exec_ctx); - grpc_connectivity_state_notify_on_state_change( - exec_ctx, &w->chand->state_tracker, w->state, &w->my_closure); + external_connectivity_watcher *found = NULL; + if (w->state != NULL) { + external_connectivity_watcher_list_append(w->chand, w); + grpc_closure_run(exec_ctx, w->watcher_timer_init, GRPC_ERROR_NONE); + grpc_closure_init(&w->my_closure, on_external_watch_complete, w, + grpc_schedule_on_exec_ctx); + grpc_connectivity_state_notify_on_state_change( + exec_ctx, &w->chand->state_tracker, w->state, &w->my_closure); + } else { + GPR_ASSERT(w->watcher_timer_init == NULL); + found = lookup_external_connectivity_watcher(w->chand, w->on_complete); + if (found) { + GPR_ASSERT(found->on_complete == w->on_complete); + grpc_connectivity_state_notify_on_state_change( + exec_ctx, &found->chand->state_tracker, NULL, &found->my_closure); + } + grpc_pollset_set_del_pollset(exec_ctx, w->chand->interested_parties, + w->pollset); + GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, + "external_connectivity_watcher"); + gpr_free(w); + } } void grpc_client_channel_watch_connectivity_state( grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset, - grpc_connectivity_state *state, grpc_closure *on_complete) { + grpc_connectivity_state *state, grpc_closure *on_complete, + grpc_closure *watcher_timer_init) { channel_data *chand = elem->channel_data; - external_connectivity_watcher *w = gpr_malloc(sizeof(*w)); + external_connectivity_watcher *w = gpr_zalloc(sizeof(*w)); w->chand = chand; w->pollset = pollset; w->on_complete = on_complete; w->state = state; + w->watcher_timer_init = watcher_timer_init; + grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties, pollset); GRPC_CHANNEL_STACK_REF(w->chand->owning_stack, "external_connectivity_watcher"); diff --git a/src/core/ext/filters/client_channel/client_channel.h b/src/core/ext/filters/client_channel/client_channel.h index 8d2490ea55d..356a7ab0c15 100644 --- a/src/core/ext/filters/client_channel/client_channel.h +++ b/src/core/ext/filters/client_channel/client_channel.h @@ -53,9 +53,13 @@ extern const grpc_channel_filter grpc_client_channel_filter; grpc_connectivity_state grpc_client_channel_check_connectivity_state( grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect); +int grpc_client_channel_num_external_connectivity_watchers( + grpc_channel_element *elem); + void grpc_client_channel_watch_connectivity_state( grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset, - grpc_connectivity_state *state, grpc_closure *on_complete); + grpc_connectivity_state *state, grpc_closure *on_complete, + grpc_closure *watcher_timer_init); /* Debug helper: pull the subchannel call from a call stack element */ grpc_subchannel_call *grpc_client_channel_get_subchannel_call( diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c index 063f92114c0..332907c0af2 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c @@ -103,6 +103,7 @@ grpc_alarm_create_type grpc_alarm_create_import; grpc_alarm_cancel_type grpc_alarm_cancel_import; grpc_alarm_destroy_type grpc_alarm_destroy_import; grpc_channel_check_connectivity_state_type grpc_channel_check_connectivity_state_import; +grpc_channel_num_external_connectivity_watchers_type grpc_channel_num_external_connectivity_watchers_import; grpc_channel_watch_connectivity_state_type grpc_channel_watch_connectivity_state_import; grpc_channel_create_call_type grpc_channel_create_call_import; grpc_channel_ping_type grpc_channel_ping_import; @@ -400,6 +401,7 @@ void grpc_rb_load_imports(HMODULE library) { grpc_alarm_cancel_import = (grpc_alarm_cancel_type) GetProcAddress(library, "grpc_alarm_cancel"); grpc_alarm_destroy_import = (grpc_alarm_destroy_type) GetProcAddress(library, "grpc_alarm_destroy"); grpc_channel_check_connectivity_state_import = (grpc_channel_check_connectivity_state_type) GetProcAddress(library, "grpc_channel_check_connectivity_state"); + grpc_channel_num_external_connectivity_watchers_import = (grpc_channel_num_external_connectivity_watchers_type) GetProcAddress(library, "grpc_channel_num_external_connectivity_watchers"); grpc_channel_watch_connectivity_state_import = (grpc_channel_watch_connectivity_state_type) GetProcAddress(library, "grpc_channel_watch_connectivity_state"); grpc_channel_create_call_import = (grpc_channel_create_call_type) GetProcAddress(library, "grpc_channel_create_call"); grpc_channel_ping_import = (grpc_channel_ping_type) GetProcAddress(library, "grpc_channel_ping"); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index f5dcd68a8e9..e6a3f6d2f4f 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -260,6 +260,9 @@ extern grpc_alarm_destroy_type grpc_alarm_destroy_import; typedef grpc_connectivity_state(*grpc_channel_check_connectivity_state_type)(grpc_channel *channel, int try_to_connect); extern grpc_channel_check_connectivity_state_type grpc_channel_check_connectivity_state_import; #define grpc_channel_check_connectivity_state grpc_channel_check_connectivity_state_import +typedef int(*grpc_channel_num_external_connectivity_watchers_type)(grpc_channel *channel); +extern grpc_channel_num_external_connectivity_watchers_type grpc_channel_num_external_connectivity_watchers_import; +#define grpc_channel_num_external_connectivity_watchers grpc_channel_num_external_connectivity_watchers_import typedef void(*grpc_channel_watch_connectivity_state_type)(grpc_channel *channel, grpc_connectivity_state last_observed_state, gpr_timespec deadline, grpc_completion_queue *cq, void *tag); extern grpc_channel_watch_connectivity_state_type grpc_channel_watch_connectivity_state_import; #define grpc_channel_watch_connectivity_state grpc_channel_watch_connectivity_state_import diff --git a/test/core/surface/concurrent_connectivity_test.c b/test/core/surface/concurrent_connectivity_test.c index 2f7c3dfb856..73f2cd363eb 100644 --- a/test/core/surface/concurrent_connectivity_test.c +++ b/test/core/surface/concurrent_connectivity_test.c @@ -61,6 +61,14 @@ #define DELAY_MILLIS 10 #define POLL_MILLIS 3000 +#define NUM_OUTER_LOOPS_SHORT_TIMEOUTS 10 +#define NUM_INNER_LOOPS_SHORT_TIMEOUTS 100 +#define DELAY_MILLIS_SHORT_TIMEOUTS 1 +// in a successful test run, POLL_MILLIS should never be reached beause all runs +// should +// end after the shorter delay_millis +#define POLL_MILLIS_SHORT_TIMEOUTS 30000 + static void *tag(int n) { return (void *)(uintptr_t)n; } static int detag(void *p) { return (int)(uintptr_t)p; } @@ -79,6 +87,8 @@ void create_loop_destroy(void *addr) { grpc_timeout_milliseconds_to_deadline(POLL_MILLIS); GPR_ASSERT(grpc_completion_queue_next(cq, poll_time, NULL).type == GRPC_OP_COMPLETE); + /* check that the watcher from "watch state" was free'd */ + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(chan) == 0); } grpc_channel_destroy(chan); grpc_completion_queue_destroy(cq); @@ -166,11 +176,10 @@ static void done_pollset_shutdown(grpc_exec_ctx *exec_ctx, void *pollset, gpr_free(pollset); } -int main(int argc, char **argv) { +int run_concurrent_connectivity_test() { struct server_thread_args args; memset(&args, 0, sizeof(args)); - grpc_test_init(argc, argv); grpc_init(); gpr_thd_id threads[NUM_THREADS]; @@ -240,3 +249,59 @@ int main(int argc, char **argv) { grpc_shutdown(); return 0; } + +void watches_with_short_timeouts(void *addr) { + for (int i = 0; i < NUM_OUTER_LOOPS_SHORT_TIMEOUTS; ++i) { + grpc_completion_queue *cq = grpc_completion_queue_create(NULL); + grpc_channel *chan = grpc_insecure_channel_create((char *)addr, NULL, NULL); + + for (int j = 0; j < NUM_INNER_LOOPS_SHORT_TIMEOUTS; ++j) { + gpr_timespec later_time = + grpc_timeout_milliseconds_to_deadline(DELAY_MILLIS_SHORT_TIMEOUTS); + grpc_connectivity_state state = + grpc_channel_check_connectivity_state(chan, 0); + GPR_ASSERT(state == GRPC_CHANNEL_IDLE); + grpc_channel_watch_connectivity_state(chan, state, later_time, cq, NULL); + gpr_timespec poll_time = + grpc_timeout_milliseconds_to_deadline(POLL_MILLIS_SHORT_TIMEOUTS); + grpc_event ev = grpc_completion_queue_next(cq, poll_time, NULL); + GPR_ASSERT(ev.type == GRPC_OP_COMPLETE); + GPR_ASSERT(ev.success == false); + /* check that the watcher from "watch state" was free'd */ + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(chan) == 0); + } + grpc_channel_destroy(chan); + grpc_completion_queue_destroy(cq); + } +} + +// This test tries to catch deadlock situations. +// With short timeouts on "watches" and long timeouts on cq next calls, +// so that a QUEUE_TIMEOUT likely means that something is stuck. +int run_concurrent_watches_with_short_timeouts_test() { + grpc_init(); + + gpr_thd_id threads[NUM_THREADS]; + + char *localhost = gpr_strdup("localhost:54321"); + gpr_thd_options options = gpr_thd_options_default(); + gpr_thd_options_set_joinable(&options); + + for (size_t i = 0; i < NUM_THREADS; ++i) { + gpr_thd_new(&threads[i], watches_with_short_timeouts, localhost, &options); + } + for (size_t i = 0; i < NUM_THREADS; ++i) { + gpr_thd_join(threads[i]); + } + gpr_free(localhost); + + grpc_shutdown(); + return 0; +} + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + + run_concurrent_connectivity_test(); + run_concurrent_watches_with_short_timeouts_test(); +} diff --git a/test/core/surface/num_external_connectivity_watchers_test.c b/test/core/surface/num_external_connectivity_watchers_test.c new file mode 100644 index 00000000000..96288ab60db --- /dev/null +++ b/test/core/surface/num_external_connectivity_watchers_test.c @@ -0,0 +1,221 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/iomgr/exec_ctx.h" +#include "test/core/end2end/data/ssl_test_data.h" +#include "test/core/util/port.h" +#include "test/core/util/test_config.h" + +typedef struct test_fixture { + const char *name; + grpc_channel *(*create_channel)(const char *addr); +} test_fixture; + +static size_t next_tag = 1; + +static void channel_idle_start_watch(grpc_channel *channel, + grpc_completion_queue *cq) { + gpr_timespec connect_deadline = grpc_timeout_milliseconds_to_deadline(1); + GPR_ASSERT(grpc_channel_check_connectivity_state(channel, 0) == + GRPC_CHANNEL_IDLE); + + grpc_channel_watch_connectivity_state( + channel, GRPC_CHANNEL_IDLE, connect_deadline, cq, (void *)(next_tag++)); + gpr_log(GPR_DEBUG, "number of active connect watchers: %d", + grpc_channel_num_external_connectivity_watchers(channel)); +} + +static void channel_idle_poll_for_timeout(grpc_channel *channel, + grpc_completion_queue *cq) { + grpc_event ev = + grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL); + + /* expect watch_connectivity_state to end with a timeout */ + GPR_ASSERT(ev.type == GRPC_OP_COMPLETE); + GPR_ASSERT(ev.success == false); + GPR_ASSERT(grpc_channel_check_connectivity_state(channel, 0) == + GRPC_CHANNEL_IDLE); +} + +/* Test and use the "num_external_watchers" call to make sure + * that "connectivity watcher" structs are free'd just after, if + * their corresponding timeouts occur. */ +static void run_timeouts_test(const test_fixture *fixture) { + gpr_log(GPR_INFO, "TEST: %s", fixture->name); + + char *addr; + + grpc_init(); + + gpr_join_host_port(&addr, "localhost", grpc_pick_unused_port_or_die()); + + grpc_channel *channel = fixture->create_channel(addr); + grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL); + + /* start 1 watcher and then let it time out */ + channel_idle_start_watch(channel, cq); + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 1); + channel_idle_poll_for_timeout(channel, cq); + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 0); + + /* start 3 watchers and then let them all time out */ + for (size_t i = 1; i <= 3; i++) { + channel_idle_start_watch(channel, cq); + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == + (int)i); + } + for (size_t i = 1; i <= 3; i++) { + channel_idle_poll_for_timeout(channel, cq); + } + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 0); + + /* start 3 watchers, see one time out, start another 3, and then see them all + * time out */ + for (size_t i = 1; i <= 3; i++) { + channel_idle_start_watch(channel, cq); + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == + (int)i); + } + channel_idle_poll_for_timeout(channel, cq); + for (size_t i = 3; i <= 5; i++) { + channel_idle_start_watch(channel, cq); + } + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) >= 3); + for (size_t i = 1; i <= 5; i++) { + channel_idle_poll_for_timeout(channel, cq); + } + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 0); + + grpc_channel_destroy(channel); + grpc_completion_queue_shutdown(cq); + GPR_ASSERT( + grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL) + .type == GRPC_QUEUE_SHUTDOWN); + grpc_completion_queue_destroy(cq); + + grpc_shutdown(); + gpr_free(addr); +} + +/* An edge scenario; sets channel state to explicitly, and outside + * of a polling call. */ +static void run_channel_shutdown_before_timeout_test( + const test_fixture *fixture) { + gpr_log(GPR_INFO, "TEST: %s", fixture->name); + + char *addr; + + grpc_init(); + + gpr_join_host_port(&addr, "localhost", grpc_pick_unused_port_or_die()); + + grpc_channel *channel = fixture->create_channel(addr); + grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL); + + /* start 1 watcher and then shut down the channel before the timer goes off */ + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 0); + + /* expecting a 30 second timeout to go off much later than the shutdown. */ + gpr_timespec connect_deadline = grpc_timeout_seconds_to_deadline(30); + GPR_ASSERT(grpc_channel_check_connectivity_state(channel, 0) == + GRPC_CHANNEL_IDLE); + + grpc_channel_watch_connectivity_state(channel, GRPC_CHANNEL_IDLE, + connect_deadline, cq, (void *)1); + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 1); + grpc_channel_destroy(channel); + + grpc_event ev = + grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL); + GPR_ASSERT(ev.type == GRPC_OP_COMPLETE); + /* expect success with a state transition to CHANNEL_SHUTDOWN */ + GPR_ASSERT(ev.success == true); + + grpc_completion_queue_shutdown(cq); + GPR_ASSERT( + grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL) + .type == GRPC_QUEUE_SHUTDOWN); + grpc_completion_queue_destroy(cq); + + grpc_shutdown(); + gpr_free(addr); +} + +static grpc_channel *insecure_test_create_channel(const char *addr) { + return grpc_insecure_channel_create(addr, NULL, NULL); +} + +static const test_fixture insecure_test = { + "insecure", insecure_test_create_channel, +}; + +static grpc_channel *secure_test_create_channel(const char *addr) { + grpc_channel_credentials *ssl_creds = + grpc_ssl_credentials_create(test_root_cert, NULL, NULL); + grpc_arg ssl_name_override = {GRPC_ARG_STRING, + GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, + {"foo.test.google.fr"}}; + grpc_channel_args *new_client_args = + grpc_channel_args_copy_and_add(NULL, &ssl_name_override, 1); + grpc_channel *channel = + grpc_secure_channel_create(ssl_creds, addr, new_client_args, NULL); + { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_channel_args_destroy(&exec_ctx, new_client_args); + grpc_exec_ctx_finish(&exec_ctx); + } + grpc_channel_credentials_release(ssl_creds); + return channel; +} + +static const test_fixture secure_test = { + "secure", secure_test_create_channel, +}; + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + + run_timeouts_test(&insecure_test); + run_timeouts_test(&secure_test); + + run_channel_shutdown_before_timeout_test(&insecure_test); + run_channel_shutdown_before_timeout_test(&secure_test); +} diff --git a/test/core/surface/sequential_connectivity_test.c b/test/core/surface/sequential_connectivity_test.c index 5f66f900372..8a6dd69c0fa 100644 --- a/test/core/surface/sequential_connectivity_test.c +++ b/test/core/surface/sequential_connectivity_test.c @@ -99,6 +99,9 @@ static void run_test(const test_fixture *fixture) { connect_deadline, cq, NULL); grpc_event ev = grpc_completion_queue_next( cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL); + /* check that the watcher from "watch state" was free'd */ + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channels[i]) == + 0); GPR_ASSERT(ev.type == GRPC_OP_COMPLETE); GPR_ASSERT(ev.tag == NULL); GPR_ASSERT(ev.success == true); diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index f5653d6f9ef..5afeed3d252 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -1689,6 +1689,23 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "gpr", + "gpr_test_util", + "grpc", + "grpc_test_util" + ], + "headers": [], + "is_filegroup": false, + "language": "c", + "name": "num_external_connectivity_watchers_test", + "src": [ + "test/core/surface/num_external_connectivity_watchers_test.c" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "gpr", diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index a08caf30d36..7e350990c98 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -1763,6 +1763,30 @@ "windows" ] }, + { + "args": [], + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "gtest": false, + "language": "c", + "name": "num_external_connectivity_watchers_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ] + }, { "args": [], "ci_platforms": [ diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln index c8fcacf75b1..9cb966de488 100644 --- a/vsprojects/buildtests_c.sln +++ b/vsprojects/buildtests_c.sln @@ -1284,6 +1284,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "no_server_test", "vcxproj\t {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "num_external_connectivity_watchers_test", "vcxproj\test\num_external_connectivity_watchers_test\num_external_connectivity_watchers_test.vcxproj", "{4E856E4A-7497-1B1A-1AED-D4C01E5D873A}" + ProjectSection(myProperties) = preProject + lib = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} + {29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9} + {EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037} + {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} + EndProjectSection +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "parse_address_test", "vcxproj\test\parse_address_test\parse_address_test.vcxproj", "{EDEA8257-AEA8-1B0A-F95B-8D6CD7286463}" ProjectSection(myProperties) = preProject lib = "False" @@ -3577,6 +3588,22 @@ Global {A66AC548-E2B9-74CD-293C-43526EE51DCE}.Release-DLL|Win32.Build.0 = Release|Win32 {A66AC548-E2B9-74CD-293C-43526EE51DCE}.Release-DLL|x64.ActiveCfg = Release|x64 {A66AC548-E2B9-74CD-293C-43526EE51DCE}.Release-DLL|x64.Build.0 = Release|x64 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug|Win32.ActiveCfg = Debug|Win32 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug|x64.ActiveCfg = Debug|x64 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release|Win32.ActiveCfg = Release|Win32 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release|x64.ActiveCfg = Release|x64 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug|Win32.Build.0 = Debug|Win32 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug|x64.Build.0 = Debug|x64 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release|Win32.Build.0 = Release|Win32 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release|x64.Build.0 = Release|x64 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug-DLL|Win32.ActiveCfg = Debug|Win32 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug-DLL|Win32.Build.0 = Debug|Win32 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug-DLL|x64.ActiveCfg = Debug|x64 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug-DLL|x64.Build.0 = Debug|x64 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release-DLL|Win32.ActiveCfg = Release|Win32 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release-DLL|Win32.Build.0 = Release|Win32 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release-DLL|x64.ActiveCfg = Release|x64 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release-DLL|x64.Build.0 = Release|x64 {EDEA8257-AEA8-1B0A-F95B-8D6CD7286463}.Debug|Win32.ActiveCfg = Debug|Win32 {EDEA8257-AEA8-1B0A-F95B-8D6CD7286463}.Debug|x64.ActiveCfg = Debug|x64 {EDEA8257-AEA8-1B0A-F95B-8D6CD7286463}.Release|Win32.ActiveCfg = Release|Win32 diff --git a/vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj b/vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj new file mode 100644 index 00000000000..2b373e8a16d --- /dev/null +++ b/vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj @@ -0,0 +1,199 @@ + + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A} + true + $(SolutionDir)IntDir\$(MSBuildProjectName)\ + + + + v100 + + + v110 + + + v120 + + + v140 + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + num_external_connectivity_watchers_test + static + Debug + static + Debug + + + num_external_connectivity_watchers_test + static + Release + static + Release + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDebug + true + None + false + + + Console + true + false + + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDebug + true + None + false + + + Console + true + false + + + + + + NotUsing + Level3 + MaxSpeed + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + true + MultiThreaded + true + None + false + + + Console + true + false + true + true + + + + + + NotUsing + Level3 + MaxSpeed + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + true + MultiThreaded + true + None + false + + + Console + true + false + true + true + + + + + + + + + + {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} + + + {29D16885-7228-4C31-81ED-5F9187C7F2A9} + + + {EAB0A629-17A9-44DB-B5FF-E91A721FE037} + + + {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + diff --git a/vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj.filters b/vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj.filters new file mode 100644 index 00000000000..92a4198e307 --- /dev/null +++ b/vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj.filters @@ -0,0 +1,21 @@ + + + + + test\core\surface + + + + + + {9557f01e-947a-775e-4540-bf9a1fd9b19a} + + + {2b3a6de2-5820-e21f-5b39-66012c94bfbb} + + + {e3f23659-fc16-a4cc-a9e2-c73b625c38f5} + + + + From c0ce2cdf0030dd5df342fda3c3e76afccacaa854 Mon Sep 17 00:00:00 2001 From: Ken Payson Date: Fri, 19 May 2017 17:47:49 -0700 Subject: [PATCH 26/65] Update version to 1.3.5 --- BUILD | 2 +- CMakeLists.txt | 2 +- Makefile | 4 ++-- build.yaml | 2 +- gRPC-Core.podspec | 2 +- gRPC-ProtoRPC.podspec | 2 +- gRPC-RxLibrary.podspec | 2 +- gRPC.podspec | 2 +- package.json | 2 +- package.xml | 4 ++-- src/cpp/common/version_cc.cc | 2 +- src/csharp/Grpc.Core/Version.csproj.include | 2 +- src/csharp/Grpc.Core/VersionInfo.cs | 4 ++-- src/csharp/build_packages_dotnetcli.bat | 2 +- src/csharp/build_packages_dotnetcli.sh | 4 ++-- src/node/health_check/package.json | 4 ++-- src/node/tools/package.json | 2 +- src/objective-c/!ProtoCompiler-gRPCPlugin.podspec | 2 +- src/objective-c/GRPCClient/private/version.h | 2 +- src/php/composer.json | 2 +- src/python/grpcio/grpc_version.py | 2 +- src/python/grpcio_health_checking/grpc_version.py | 2 +- src/python/grpcio_reflection/grpc_version.py | 2 +- src/python/grpcio_tests/grpc_version.py | 2 +- src/ruby/lib/grpc/version.rb | 2 +- src/ruby/tools/version.rb | 2 +- tools/distrib/python/grpcio_tools/grpc_version.py | 2 +- tools/doxygen/Doxyfile.c++ | 2 +- tools/doxygen/Doxyfile.c++.internal | 2 +- 29 files changed, 34 insertions(+), 34 deletions(-) diff --git a/BUILD b/BUILD index 51314f645c0..166e6ba7518 100644 --- a/BUILD +++ b/BUILD @@ -42,7 +42,7 @@ g_stands_for = "gentle" core_version = "3.0.0" -version = "1.3.4" +version = "1.3.5" grpc_cc_library( name = "gpr", diff --git a/CMakeLists.txt b/CMakeLists.txt index 48f9bb42a90..cff8f856e02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ cmake_minimum_required(VERSION 2.8) set(PACKAGE_NAME "grpc") -set(PACKAGE_VERSION "1.3.4") +set(PACKAGE_VERSION "1.3.5") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/") diff --git a/Makefile b/Makefile index 8359ce2fc63..77206ba92bf 100644 --- a/Makefile +++ b/Makefile @@ -420,8 +420,8 @@ Q = @ endif CORE_VERSION = 3.0.0 -CPP_VERSION = 1.3.4 -CSHARP_VERSION = 1.3.4 +CPP_VERSION = 1.3.5 +CSHARP_VERSION = 1.3.5 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES)) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) diff --git a/build.yaml b/build.yaml index 0629b459ac8..3af590609a1 100644 --- a/build.yaml +++ b/build.yaml @@ -14,7 +14,7 @@ settings: '#10': See the expand_version.py for all the quirks here core_version: 3.0.0 g_stands_for: gentle - version: 1.3.4 + version: 1.3.5 filegroups: - name: census public_headers: diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index c8e50b577ac..5d1ba611830 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -37,7 +37,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-Core' - version = '1.3.4' + version = '1.3.5' s.version = version s.summary = 'Core cross-platform gRPC library, written in C' s.homepage = 'http://www.grpc.io' diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec index 6737e0136a8..e60ea7c08ee 100644 --- a/gRPC-ProtoRPC.podspec +++ b/gRPC-ProtoRPC.podspec @@ -36,7 +36,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-ProtoRPC' - version = '1.3.4' + version = '1.3.5' s.version = version s.summary = 'RPC library for Protocol Buffers, based on gRPC' s.homepage = 'http://www.grpc.io' diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec index 0b338d44aaf..d82130ad4ae 100644 --- a/gRPC-RxLibrary.podspec +++ b/gRPC-RxLibrary.podspec @@ -36,7 +36,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-RxLibrary' - version = '1.3.4' + version = '1.3.5' s.version = version s.summary = 'Reactive Extensions library for iOS/OSX.' s.homepage = 'http://www.grpc.io' diff --git a/gRPC.podspec b/gRPC.podspec index 1783df67ef5..5aa8a86a058 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -35,7 +35,7 @@ Pod::Spec.new do |s| s.name = 'gRPC' - version = '1.3.4' + version = '1.3.5' s.version = version s.summary = 'gRPC client library for iOS/OSX' s.homepage = 'http://www.grpc.io' diff --git a/package.json b/package.json index 11e34416520..c83f51c2212 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.3.4", + "version": "1.3.5", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "http://www.grpc.io/", diff --git a/package.xml b/package.xml index 6b3eddadf6d..1c91f1c0c23 100644 --- a/package.xml +++ b/package.xml @@ -13,8 +13,8 @@ 2017-05-05 - 1.3.4 - 1.3.4 + 1.3.5 + 1.3.5 beta diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc index 97437ba5308..0a1b72527b6 100644 --- a/src/cpp/common/version_cc.cc +++ b/src/cpp/common/version_cc.cc @@ -37,5 +37,5 @@ #include namespace grpc { -grpc::string Version() { return "1.3.4"; } +grpc::string Version() { return "1.3.5"; } } diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include index 881c311b17e..63536ecc6b4 100755 --- a/src/csharp/Grpc.Core/Version.csproj.include +++ b/src/csharp/Grpc.Core/Version.csproj.include @@ -1,7 +1,7 @@ - 1.3.4 + 1.3.5 3.2.0 diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs index bbe5a17d6b7..fed38292f04 100644 --- a/src/csharp/Grpc.Core/VersionInfo.cs +++ b/src/csharp/Grpc.Core/VersionInfo.cs @@ -48,11 +48,11 @@ namespace Grpc.Core /// /// Current AssemblyFileVersion of gRPC C# assemblies /// - public const string CurrentAssemblyFileVersion = "1.3.4.0"; + public const string CurrentAssemblyFileVersion = "1.3.5.0"; /// /// Current version of gRPC C# /// - public const string CurrentVersion = "1.3.4"; + public const string CurrentVersion = "1.3.5"; } } diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat index a385ac74e3e..3aec7aacbeb 100755 --- a/src/csharp/build_packages_dotnetcli.bat +++ b/src/csharp/build_packages_dotnetcli.bat @@ -28,7 +28,7 @@ @rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @rem Current package versions -set VERSION=1.3.4 +set VERSION=1.3.5 @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh index 66c41d4d940..da585cb663d 100755 --- a/src/csharp/build_packages_dotnetcli.sh +++ b/src/csharp/build_packages_dotnetcli.sh @@ -70,7 +70,7 @@ dotnet pack --configuration Release --include-symbols --include-source Grpc.Auth dotnet pack --configuration Release --include-symbols --include-source Grpc.HealthCheck --output ../../../artifacts dotnet pack --configuration Release --include-symbols --include-source Grpc.Reflection --output ../../../artifacts -nuget pack Grpc.nuspec -Version "1.3.4" -OutputDirectory ../../artifacts -nuget pack Grpc.Tools.nuspec -Version "1.3.4" -OutputDirectory ../../artifacts +nuget pack Grpc.nuspec -Version "1.3.5" -OutputDirectory ../../artifacts +nuget pack Grpc.Tools.nuspec -Version "1.3.5" -OutputDirectory ../../artifacts (cd ../../artifacts && zip csharp_nugets_dotnetcli.zip *.nupkg) diff --git a/src/node/health_check/package.json b/src/node/health_check/package.json index 6329cd9c377..2fdcb12777c 100644 --- a/src/node/health_check/package.json +++ b/src/node/health_check/package.json @@ -1,6 +1,6 @@ { "name": "grpc-health-check", - "version": "1.3.4", + "version": "1.3.5", "author": "Google Inc.", "description": "Health check service for use with gRPC", "repository": { @@ -15,7 +15,7 @@ } ], "dependencies": { - "grpc": "^1.3.4", + "grpc": "^1.3.5", "lodash": "^3.9.3", "google-protobuf": "^3.0.0" }, diff --git a/src/node/tools/package.json b/src/node/tools/package.json index 355ae2fdc1f..cabd4030dc9 100644 --- a/src/node/tools/package.json +++ b/src/node/tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.3.4", + "version": "1.3.5", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "http://www.grpc.io/", diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec index b4fc9685049..23f91867c41 100644 --- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec +++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec @@ -42,7 +42,7 @@ Pod::Spec.new do |s| # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed # before them. s.name = '!ProtoCompiler-gRPCPlugin' - v = '1.3.4' + v = '1.3.5' s.version = v s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.' s.description = <<-DESC diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h index ccf96230bc1..43ab9bd0641 100644 --- a/src/objective-c/GRPCClient/private/version.h +++ b/src/objective-c/GRPCClient/private/version.h @@ -38,4 +38,4 @@ // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.3.4" +#define GRPC_OBJC_VERSION_STRING @"1.3.5" diff --git a/src/php/composer.json b/src/php/composer.json index 562859e6b3d..08f2b9afabd 100644 --- a/src/php/composer.json +++ b/src/php/composer.json @@ -2,7 +2,7 @@ "name": "grpc/grpc-dev", "description": "gRPC library for PHP - for Developement use only", "license": "BSD-3-Clause", - "version": "1.3.4", + "version": "1.3.5", "require": { "php": ">=5.5.0", "google/protobuf": "^v3.1.0" diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py index 29ffcab1065..52b1397468c 100644 --- a/src/python/grpcio/grpc_version.py +++ b/src/python/grpcio/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!! -VERSION='1.3.4' +VERSION='1.3.5' diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py index 16e0dc13275..143c1ede368 100644 --- a/src/python/grpcio_health_checking/grpc_version.py +++ b/src/python/grpcio_health_checking/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!! -VERSION='1.3.4' +VERSION='1.3.5' diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py index 5ef0ed8045e..66f1ff968ae 100644 --- a/src/python/grpcio_reflection/grpc_version.py +++ b/src/python/grpcio_reflection/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!! -VERSION='1.3.4' +VERSION='1.3.5' diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py index 7e4c57e6ec6..a6da39c8ebf 100644 --- a/src/python/grpcio_tests/grpc_version.py +++ b/src/python/grpcio_tests/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!! -VERSION='1.3.4' +VERSION='1.3.5' diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb index c03ec97196b..27595318d33 100644 --- a/src/ruby/lib/grpc/version.rb +++ b/src/ruby/lib/grpc/version.rb @@ -29,5 +29,5 @@ # GRPC contains the General RPC module. module GRPC - VERSION = '1.3.4' + VERSION = '1.3.5' end diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb index fe0fb2cef21..f93c1f14af2 100644 --- a/src/ruby/tools/version.rb +++ b/src/ruby/tools/version.rb @@ -29,6 +29,6 @@ module GRPC module Tools - VERSION = '1.3.4' + VERSION = '1.3.5' end end diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py index 020785aa730..71786813299 100644 --- a/tools/distrib/python/grpcio_tools/grpc_version.py +++ b/tools/distrib/python/grpcio_tools/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!! -VERSION='1.3.4' +VERSION='1.3.5' diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 5021a1a153b..55980eadac5 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.3.4 +PROJECT_NUMBER = 1.3.5 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 1df6951aef2..7580617bf12 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.3.4 +PROJECT_NUMBER = 1.3.5 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From d854af32baff5fe1dcbf62a49b42a595004f5f97 Mon Sep 17 00:00:00 2001 From: jiangtaoli2016 Date: Sat, 20 May 2017 11:27:22 -0700 Subject: [PATCH 27/65] Address Mark Roth's comments. --- .../lib/security/transport/security_handshaker.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/core/lib/security/transport/security_handshaker.c b/src/core/lib/security/transport/security_handshaker.c index 9b158201fc6..c4267466ff2 100644 --- a/src/core/lib/security/transport/security_handshaker.c +++ b/src/core/lib/security/transport/security_handshaker.c @@ -71,7 +71,6 @@ typedef struct { unsigned char *handshake_buffer; size_t handshake_buffer_size; - grpc_slice_buffer left_overs; grpc_slice_buffer outgoing; grpc_closure on_handshake_data_sent_to_peer; grpc_closure on_handshake_data_received_from_peer; @@ -94,7 +93,6 @@ static void security_handshaker_unref(grpc_exec_ctx *exec_ctx, gpr_free(h->read_buffer_to_destroy); } gpr_free(h->handshake_buffer); - grpc_slice_buffer_destroy_internal(exec_ctx, &h->left_overs); grpc_slice_buffer_destroy_internal(exec_ctx, &h->outgoing); GRPC_AUTH_CONTEXT_UNREF(h->auth_context, "handshake"); GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, h->connector, "handshake"); @@ -168,14 +166,12 @@ static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *arg, size_t unused_bytes_size = 0; result = tsi_handshaker_result_get_unused_bytes( h->handshaker_result, &unused_bytes, &unused_bytes_size); - if (unused_bytes_size > 0) { - grpc_slice slice = - grpc_slice_from_copied_buffer((char *)unused_bytes, unused_bytes_size); - grpc_slice_buffer_add(&h->left_overs, slice); - } + grpc_slice leftover_slice = + grpc_slice_from_copied_buffer((char *)unused_bytes, unused_bytes_size); // Create secure endpoint. h->args->endpoint = grpc_secure_endpoint_create( - protector, h->args->endpoint, h->left_overs.slices, h->left_overs.count); + protector, h->args->endpoint, &leftover_slice, 1); + grpc_slice_unref_internal(exec_ctx, leftover_slice); tsi_handshaker_result_destroy(h->handshaker_result); h->handshaker_result = NULL; // Clear out the read buffer before it gets passed to the transport. @@ -226,7 +222,6 @@ static grpc_error *on_handshake_next_done_locked( return grpc_set_tsi_error_result( GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake failed"), result); } - // Send data to peer. grpc_slice to_send = grpc_slice_from_copied_buffer( (const char *)bytes_to_send, bytes_to_send_size); @@ -234,7 +229,6 @@ static grpc_error *on_handshake_next_done_locked( grpc_slice_buffer_add(&h->outgoing, to_send); grpc_endpoint_write(exec_ctx, h->args->endpoint, &h->outgoing, &h->on_handshake_data_sent_to_peer); - // If handshake has completed, check peer and so on. if (handshaker_result != NULL) { GPR_ASSERT(h->handshaker_result == NULL); @@ -415,7 +409,6 @@ static grpc_handshaker *security_handshaker_create( grpc_schedule_on_exec_ctx); grpc_closure_init(&h->on_peer_checked, on_peer_checked, h, grpc_schedule_on_exec_ctx); - grpc_slice_buffer_init(&h->left_overs); grpc_slice_buffer_init(&h->outgoing); return &h->base; } From 8f7bc54ff2256179ede6d4a6d1a8792b7820fc28 Mon Sep 17 00:00:00 2001 From: Ken Payson Date: Tue, 16 May 2017 10:30:59 -0700 Subject: [PATCH 28/65] Reconnect disconnected channels automatically --- src/python/grpcio/grpc/_channel.py | 7 +- src/python/grpcio_tests/tests/tests.json | 1 + .../tests/unit/_reconnect_test.py | 70 +++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 src/python/grpcio_tests/tests/unit/_reconnect_test.py diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py index 4316449ac65..012ed8ec812 100644 --- a/src/python/grpcio/grpc/_channel.py +++ b/src/python/grpcio/grpc/_channel.py @@ -786,7 +786,7 @@ def _channel_managed_call_management(state): class _ChannelConnectivityState(object): def __init__(self, channel): - self.lock = threading.Lock() + self.lock = threading.RLock() self.channel = channel self.polling = False self.connectivity = None @@ -926,6 +926,11 @@ class Channel(grpc.Channel): self._call_state = _ChannelCallState(self._channel) self._connectivity_state = _ChannelConnectivityState(self._channel) + # TODO(https://github.com/grpc/grpc/issues/9884) + # Temporary work around UNAVAILABLE issues + # Remove this once c-core has retry support + _subscribe(self._connectivity_state, lambda *args: None, None) + def subscribe(self, callback, try_to_connect=None): _subscribe(self._connectivity_state, callback, try_to_connect) diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json index f750b051022..5f641d87010 100644 --- a/src/python/grpcio_tests/tests/tests.json +++ b/src/python/grpcio_tests/tests/tests.json @@ -31,6 +31,7 @@ "unit._invocation_defects_test.InvocationDefectsTest", "unit._metadata_code_details_test.MetadataCodeDetailsTest", "unit._metadata_test.MetadataTest", + "unit._reconnect_test.ReconnectTest", "unit._resource_exhausted_test.ResourceExhaustedTest", "unit._rpc_test.RPCTest", "unit._sanity._sanity_test.Sanity", diff --git a/src/python/grpcio_tests/tests/unit/_reconnect_test.py b/src/python/grpcio_tests/tests/unit/_reconnect_test.py new file mode 100644 index 00000000000..6c316476b3e --- /dev/null +++ b/src/python/grpcio_tests/tests/unit/_reconnect_test.py @@ -0,0 +1,70 @@ +# Copyright 2017, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +"""Tests that a channel will reconnect if a connection is dropped""" + +import unittest + +import grpc +from grpc.framework.foundation import logging_pool + +from tests.unit.framework.common import test_constants + +_REQUEST = b'\x00\x00\x00' +_RESPONSE = b'\x00\x00\x01' + +_UNARY_UNARY = '/test/UnaryUnary' + + +def _handle_unary_unary(unused_request, unused_servicer_context): + return _RESPONSE + + +class ReconnectTest(unittest.TestCase): + + def test_reconnect(self): + server_pool = logging_pool.pool(test_constants.THREAD_CONCURRENCY) + handler = grpc.method_handlers_generic_handler('test', { + 'UnaryUnary': + grpc.unary_unary_rpc_method_handler(_handle_unary_unary) + }) + server = grpc.server(server_pool, (handler,)) + port = server.add_insecure_port('[::]:0') + server.start() + channel = grpc.insecure_channel('localhost:%d' % port) + multi_callable = channel.unary_unary(_UNARY_UNARY) + self.assertEqual(_RESPONSE, multi_callable(_REQUEST)) + server.stop(None) + server = grpc.server(server_pool, (handler,)) + server.add_insecure_port('[::]:{}'.format(port)) + server.start() + self.assertEqual(_RESPONSE, multi_callable(_REQUEST)) + + +if __name__ == '__main__': + unittest.main(verbosity=2) From 4f5bd0a8d1ff94ce8b0e7366cf32ce83c2b75f42 Mon Sep 17 00:00:00 2001 From: jiangtaoli2016 Date: Mon, 22 May 2017 11:29:46 -0700 Subject: [PATCH 29/65] Revise based on Mark Roth comments. --- .../security/transport/security_handshaker.c | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/core/lib/security/transport/security_handshaker.c b/src/core/lib/security/transport/security_handshaker.c index c4267466ff2..9144483b0c1 100644 --- a/src/core/lib/security/transport/security_handshaker.c +++ b/src/core/lib/security/transport/security_handshaker.c @@ -166,12 +166,17 @@ static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *arg, size_t unused_bytes_size = 0; result = tsi_handshaker_result_get_unused_bytes( h->handshaker_result, &unused_bytes, &unused_bytes_size); - grpc_slice leftover_slice = - grpc_slice_from_copied_buffer((char *)unused_bytes, unused_bytes_size); // Create secure endpoint. - h->args->endpoint = grpc_secure_endpoint_create( - protector, h->args->endpoint, &leftover_slice, 1); - grpc_slice_unref_internal(exec_ctx, leftover_slice); + if (unused_bytes_size > 0) { + grpc_slice slice = + grpc_slice_from_copied_buffer((char *)unused_bytes, unused_bytes_size); + h->args->endpoint = + grpc_secure_endpoint_create(protector, h->args->endpoint, &slice, 1); + grpc_slice_unref_internal(exec_ctx, slice); + } else { + h->args->endpoint = + grpc_secure_endpoint_create(protector, h->args->endpoint, NULL, 0); + } tsi_handshaker_result_destroy(h->handshaker_result); h->handshaker_result = NULL; // Clear out the read buffer before it gets passed to the transport. @@ -223,17 +228,23 @@ static grpc_error *on_handshake_next_done_locked( GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake failed"), result); } // Send data to peer. - grpc_slice to_send = grpc_slice_from_copied_buffer( - (const char *)bytes_to_send, bytes_to_send_size); - grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &h->outgoing); - grpc_slice_buffer_add(&h->outgoing, to_send); - grpc_endpoint_write(exec_ctx, h->args->endpoint, &h->outgoing, - &h->on_handshake_data_sent_to_peer); - // If handshake has completed, check peer and so on. + if (bytes_to_send_size > 0) { + grpc_slice to_send = grpc_slice_from_copied_buffer( + (const char *)bytes_to_send, bytes_to_send_size); + grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &h->outgoing); + grpc_slice_buffer_add(&h->outgoing, to_send); + grpc_endpoint_write(exec_ctx, h->args->endpoint, &h->outgoing, + &h->on_handshake_data_sent_to_peer); + } + // If handshake has completed, check peer and so on. Otherwise, need to read + // more data from the peer. if (handshaker_result != NULL) { GPR_ASSERT(h->handshaker_result == NULL); h->handshaker_result = handshaker_result; error = check_peer_locked(exec_ctx, h); + } else { + grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, + &h->on_handshake_data_received_from_peer); } return error; } @@ -335,10 +346,6 @@ static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *arg, security_handshaker_unref(exec_ctx, h); return; } - if (h->handshaker_result == NULL) { - grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, - &h->on_handshake_data_received_from_peer); - } gpr_mu_unlock(&h->mu); } From c91bc02d979c30da40b67204324f28b569a3c8b6 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 19 May 2017 14:49:26 +0200 Subject: [PATCH 30/65] Add Grpc.Microbenchmarks project --- src/csharp/Grpc.Microbenchmarks/.gitignore | 2 + .../Grpc.Microbenchmarks.csproj | 28 ++++++++++++ src/csharp/Grpc.Microbenchmarks/Program.cs | 45 +++++++++++++++++++ src/csharp/Grpc.sln | 8 +++- 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/csharp/Grpc.Microbenchmarks/.gitignore create mode 100644 src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj create mode 100644 src/csharp/Grpc.Microbenchmarks/Program.cs diff --git a/src/csharp/Grpc.Microbenchmarks/.gitignore b/src/csharp/Grpc.Microbenchmarks/.gitignore new file mode 100644 index 00000000000..1746e3269ed --- /dev/null +++ b/src/csharp/Grpc.Microbenchmarks/.gitignore @@ -0,0 +1,2 @@ +bin +obj diff --git a/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj new file mode 100644 index 00000000000..26a940e4887 --- /dev/null +++ b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj @@ -0,0 +1,28 @@ + + + + + + + net45;netcoreapp1.0 + Grpc.Microbenchmarks + Exe + Grpc.Microbenchmarks + $(PackageTargetFallback);portable-net45 + 1.0.4 + + + + + + + + + + + + + + + + diff --git a/src/csharp/Grpc.Microbenchmarks/Program.cs b/src/csharp/Grpc.Microbenchmarks/Program.cs new file mode 100644 index 00000000000..ac577d1b984 --- /dev/null +++ b/src/csharp/Grpc.Microbenchmarks/Program.cs @@ -0,0 +1,45 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; + +namespace Grpc.Microbenchmarks +{ + class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Helloworld"); + } + } +} diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln index beab3ccb36c..d9a7b8d556b 100644 --- a/src/csharp/Grpc.sln +++ b/src/csharp/Grpc.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26228.4 +VisualStudioVersion = 15.0.26430.4 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Core", "Grpc.Core\Grpc.Core.csproj", "{BD878CB3-BDB4-46AB-84EF-C3B4729F56BC}" EndProject @@ -37,6 +37,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Reflection", "Grpc.Ref EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Reflection.Tests", "Grpc.Reflection.Tests\Grpc.Reflection.Tests.csproj", "{335AD0A2-F2CC-4C2E-853C-26174206BEE7}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Microbenchmarks", "Grpc.Microbenchmarks\Grpc.Microbenchmarks.csproj", "{84C17746-4727-4290-8E8B-A380793DAE1E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -111,6 +113,10 @@ Global {335AD0A2-F2CC-4C2E-853C-26174206BEE7}.Debug|Any CPU.Build.0 = Debug|Any CPU {335AD0A2-F2CC-4C2E-853C-26174206BEE7}.Release|Any CPU.ActiveCfg = Release|Any CPU {335AD0A2-F2CC-4C2E-853C-26174206BEE7}.Release|Any CPU.Build.0 = Release|Any CPU + {84C17746-4727-4290-8E8B-A380793DAE1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {84C17746-4727-4290-8E8B-A380793DAE1E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {84C17746-4727-4290-8E8B-A380793DAE1E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {84C17746-4727-4290-8E8B-A380793DAE1E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From ff5f9d898f5ab2c49a0be09de33c8e2f80a6b785 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 19 May 2017 14:51:42 +0200 Subject: [PATCH 31/65] make internals visible to microbenchmarks --- src/csharp/Grpc.Core/Properties/AssemblyInfo.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs index 77ac347c7da..fe757820fd1 100644 --- a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs +++ b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs @@ -59,8 +59,14 @@ using System.Runtime.CompilerServices; "0442bb8e12768722de0b0cb1b15e955b32a11352740ee59f2c94c48edc8e177d1052536b8ac651bce11ce5da3a" + "27fc95aff3dc604a6971417453f9483c7b5e836756d5b271bf8f2403fe186e31956148c03d804487cf642f8cc0" + "71394ee9672dfe5b55ea0f95dfd5a7f77d22c962ccf51320d3")] +[assembly: InternalsVisibleTo("Grpc.Microbenchmarks,PublicKey=" + + "00240000048000009400000006020000002400005253413100040000010001002f5797a92c6fcde81bd4098f43" + + "0442bb8e12768722de0b0cb1b15e955b32a11352740ee59f2c94c48edc8e177d1052536b8ac651bce11ce5da3a" + + "27fc95aff3dc604a6971417453f9483c7b5e836756d5b271bf8f2403fe186e31956148c03d804487cf642f8cc0" + + "71394ee9672dfe5b55ea0f95dfd5a7f77d22c962ccf51320d3")] #else [assembly: InternalsVisibleTo("Grpc.Core.Tests")] [assembly: InternalsVisibleTo("Grpc.Core.Testing")] [assembly: InternalsVisibleTo("Grpc.IntegrationTesting")] +[assembly: InternalsVisibleTo("Grpc.Microbenchmarks")] #endif From c7c2bf171414d577d0df336059ff5732b2c0ca4a Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 19 May 2017 15:01:43 +0200 Subject: [PATCH 32/65] add editorconfig for C# --- src/csharp/.editorconfig | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/csharp/.editorconfig diff --git a/src/csharp/.editorconfig b/src/csharp/.editorconfig new file mode 100644 index 00000000000..7bc2bcce182 --- /dev/null +++ b/src/csharp/.editorconfig @@ -0,0 +1,7 @@ +root = true +[**] +end_of_line = LF +indent_style = space +indent_size = 4 +insert_final_newline = true +tab_width = 4 From 7cc83c8cd5772aff3033e4aafaa05cd2bdaa068a Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 19 May 2017 15:51:23 +0200 Subject: [PATCH 33/65] allow creating fake CallSafeHandle --- src/csharp/Grpc.Core/Internal/CallSafeHandle.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs index 8ed0c0b92f7..bc74e212b19 100644 --- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs @@ -218,5 +218,16 @@ namespace Grpc.Core.Internal { return buffered ? 0 : GRPC_WRITE_BUFFER_HINT; } + + /// + /// Only for testing. + /// + public static CallSafeHandle CreateFake(IntPtr ptr, CompletionQueueSafeHandle cq) + { + var call = new CallSafeHandle(); + call.SetHandle(ptr); + call.Initialize(cq); + return call; + } } } From e58842f33a988c8691d1591c970b4b1232021432 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 19 May 2017 15:52:05 +0200 Subject: [PATCH 34/65] benchmark prototype --- .../Grpc.Core/Internal/CompletionRegistry.cs | 7 ++ src/csharp/Grpc.Microbenchmarks/Program.cs | 10 +- .../SendMessageBenchmark.cs | 106 ++++++++++++++++++ .../Grpc.Microbenchmarks/ThreadedBenchmark.cs | 79 +++++++++++++ 4 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs create mode 100644 src/csharp/Grpc.Microbenchmarks/ThreadedBenchmark.cs diff --git a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs index a4aa8d3ffe4..fc0ff72e6a1 100644 --- a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs +++ b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs @@ -52,6 +52,7 @@ namespace Grpc.Core.Internal readonly GrpcEnvironment environment; readonly ConcurrentDictionary dict = new ConcurrentDictionary(new IntPtrComparer()); + IntPtr lastRegisteredKey; public CompletionRegistry(GrpcEnvironment environment) { @@ -62,6 +63,7 @@ namespace Grpc.Core.Internal { environment.DebugStats.PendingBatchCompletions.Increment(); GrpcPreconditions.CheckState(dict.TryAdd(key, callback)); + this.lastRegisteredKey = key; } public void RegisterBatchCompletion(BatchContextSafeHandle ctx, BatchCompletionDelegate callback) @@ -84,6 +86,11 @@ namespace Grpc.Core.Internal return value; } + public IntPtr LastRegisteredKey + { + get { return this.lastRegisteredKey; } + } + private static void HandleBatchCompletion(bool success, BatchContextSafeHandle ctx, BatchCompletionDelegate callback) { try diff --git a/src/csharp/Grpc.Microbenchmarks/Program.cs b/src/csharp/Grpc.Microbenchmarks/Program.cs index ac577d1b984..09b6eb68d91 100644 --- a/src/csharp/Grpc.Microbenchmarks/Program.cs +++ b/src/csharp/Grpc.Microbenchmarks/Program.cs @@ -32,6 +32,8 @@ #endregion using System; +using Grpc.Core; +using Grpc.Core.Internal; namespace Grpc.Microbenchmarks { @@ -39,7 +41,13 @@ namespace Grpc.Microbenchmarks { public static void Main(string[] args) { - Console.WriteLine("Helloworld"); + var benchmark = new SendMessageBenchmark(); + benchmark.Init(); + foreach (int threadCount in new int[] {1, 1, 2, 4, 8, 12}) + { + benchmark.Run(threadCount, 4 * 1000 * 1000, 0); + } + benchmark.Cleanup(); } } } diff --git a/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs new file mode 100644 index 00000000000..4575529bef6 --- /dev/null +++ b/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs @@ -0,0 +1,106 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Threading; +using Grpc.Core; +using Grpc.Core.Internal; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Grpc.Microbenchmarks +{ + public class SendMessageBenchmark + { + static readonly NativeMethods Native = NativeMethods.Get(); + + GrpcEnvironment environment; + + public void Init() + { + Native.grpcsharp_test_override_method("grpcsharp_call_start_batch", "nop"); + environment = GrpcEnvironment.AddRef(); + } + + public void Cleanup() + { + GrpcEnvironment.ReleaseAsync().Wait(); + // TODO(jtattermusch): track GC stats + } + + public void Run(int threadCount, int iterations, int payloadSize) + { + Console.WriteLine(string.Format("SendMessageBenchmark: threads={0}, iterations={1}, payloadSize={2}", threadCount, iterations, payloadSize)); + var threadedBenchmark = new ThreadedBenchmark(threadCount, () => ThreadBody(iterations, payloadSize)); + threadedBenchmark.Run(); + } + + private void ThreadBody(int iterations, int payloadSize) + { + // TODO(jtattermusch): parametrize by number of pending completions. + // TODO(jtattermusch): parametrize by cached/non-cached BatchContextSafeHandle + + var completionRegistry = new CompletionRegistry(environment); + var cq = CompletionQueueSafeHandle.CreateAsync(completionRegistry); + var call = CreateFakeCall(cq); + + var sendCompletionHandler = new SendCompletionHandler((success) => { }); + var payload = new byte[payloadSize]; + var writeFlags = default(WriteFlags); + + var stopwatch = Stopwatch.StartNew(); + for (int i = 0; i < iterations; i++) + { + call.StartSendMessage(sendCompletionHandler, payload, writeFlags, false); + var callback = completionRegistry.Extract(completionRegistry.LastRegisteredKey); + callback(); + } + stopwatch.Stop(); + Console.WriteLine("Elapsed millis: " + stopwatch.ElapsedMilliseconds); + + cq.Dispose(); + } + + private static CallSafeHandle CreateFakeCall(CompletionQueueSafeHandle cq) + { + var call = CallSafeHandle.CreateFake(new IntPtr(0xdead), cq); + bool success = false; + while (!success) + { + // avoid calling destroy on a nonexistent grpc_call pointer + call.DangerousAddRef(ref success); + } + return call; + } + } +} diff --git a/src/csharp/Grpc.Microbenchmarks/ThreadedBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/ThreadedBenchmark.cs new file mode 100644 index 00000000000..1c546240343 --- /dev/null +++ b/src/csharp/Grpc.Microbenchmarks/ThreadedBenchmark.cs @@ -0,0 +1,79 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Threading; +using Grpc.Core; +using Grpc.Core.Internal; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Grpc.Microbenchmarks +{ + public class ThreadedBenchmark + { + List runners; + + public ThreadedBenchmark(IEnumerable runners) + { + this.runners = new List(runners); + } + + public ThreadedBenchmark(int threadCount, Action threadBody) + { + this.runners = new List(); + for (int i = 0; i < threadCount; i++) + { + this.runners.Add(new ThreadStart(() => threadBody())); + } + } + + public void Run() + { + Console.WriteLine("Running threads."); + var threads = new List(); + for (int i = 0; i < runners.Count; i++) + { + var thread = new Thread(runners[i]); + thread.Start(); + threads.Add(thread); + } + + foreach (var thread in threads) + { + thread.Join(); + } + Console.WriteLine("All threads finished."); + } + } +} From 645ae74e88c73492ac3a98e5bf16ea24600e5a65 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Mon, 22 May 2017 08:46:26 -0700 Subject: [PATCH 35/65] overridable call_start_batch --- .../Grpc.Core/Internal/NativeMethods.cs | 4 ++ src/csharp/Grpc.Microbenchmarks/Program.cs | 2 + src/csharp/ext/grpc_csharp_ext.c | 65 +++++++++++++++---- 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/src/csharp/Grpc.Core/Internal/NativeMethods.cs b/src/csharp/Grpc.Core/Internal/NativeMethods.cs index 696987d2a85..5ce792d296d 100644 --- a/src/csharp/Grpc.Core/Internal/NativeMethods.cs +++ b/src/csharp/Grpc.Core/Internal/NativeMethods.cs @@ -164,6 +164,8 @@ namespace Grpc.Core.Internal public readonly Delegates.grpcsharp_test_callback_delegate grpcsharp_test_callback; public readonly Delegates.grpcsharp_test_nop_delegate grpcsharp_test_nop; + public readonly Delegates.grpcsharp_test_override_method_delegate grpcsharp_test_override_method; + #endregion public NativeMethods(UnmanagedLibrary library) @@ -278,6 +280,7 @@ namespace Grpc.Core.Internal this.grpcsharp_test_callback = GetMethodDelegate(library); this.grpcsharp_test_nop = GetMethodDelegate(library); + this.grpcsharp_test_override_method = GetMethodDelegate(library); } /// @@ -434,6 +437,7 @@ namespace Grpc.Core.Internal public delegate CallError grpcsharp_test_callback_delegate([MarshalAs(UnmanagedType.FunctionPtr)] OpCompletionDelegate callback); public delegate IntPtr grpcsharp_test_nop_delegate(IntPtr ptr); + public delegate void grpcsharp_test_override_method(string methodName, string variant); } } } diff --git a/src/csharp/Grpc.Microbenchmarks/Program.cs b/src/csharp/Grpc.Microbenchmarks/Program.cs index 09b6eb68d91..a0ca1f75ae6 100644 --- a/src/csharp/Grpc.Microbenchmarks/Program.cs +++ b/src/csharp/Grpc.Microbenchmarks/Program.cs @@ -34,6 +34,7 @@ using System; using Grpc.Core; using Grpc.Core.Internal; +using Grpc.Core.Logging; namespace Grpc.Microbenchmarks { @@ -41,6 +42,7 @@ namespace Grpc.Microbenchmarks { public static void Main(string[] args) { + GrpcEnvironment.SetLogger(new TextWriterLogger(Console.Error)); var benchmark = new SendMessageBenchmark(); benchmark.Init(); foreach (int threadCount in new int[] {1, 1, 2, 4, 8, 12}) diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index f6cff454bdb..34f8b928ddf 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -529,6 +529,31 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_call_destroy(grpc_call *call) { grpc_call_unref(call); } +typedef grpc_call_error (*grpcsharp_call_start_batch_func) ( + grpc_call *call, const grpc_op *ops, size_t nops, + void *tag, void *reserved); + +/* Only for testing */ +static grpc_call_error grpcsharp_call_start_batch_nop( + grpc_call *call, const grpc_op *ops, size_t nops, + void *tag, void *reserved) { + return GRPC_CALL_OK; +} + +static grpc_call_error grpcsharp_call_start_batch_default( + grpc_call *call, const grpc_op *ops, size_t nops, + void *tag, void *reserved) { + return grpc_call_start_batch(call, ops, nops, tag, reserved); +} + +static grpcsharp_call_start_batch_func g_call_start_batch_func = grpcsharp_call_start_batch_default; + +static grpc_call_error grpcsharp_call_start_batch( + grpc_call *call, const grpc_op *ops, size_t nops, + void *tag, void *reserved) { + return g_call_start_batch_func(call, ops, nops, tag, reserved); +} + GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_unary( grpc_call *call, grpcsharp_batch_context *ctx, const char *send_buffer, size_t send_buffer_len, uint32_t write_flags, @@ -576,7 +601,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_unary( ops[5].flags = 0; ops[5].reserved = NULL; - return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, + return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } @@ -616,7 +641,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_client_streaming( ops[3].flags = 0; ops[3].reserved = NULL; - return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, + return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } @@ -656,7 +681,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming( ops[3].flags = 0; ops[3].reserved = NULL; - return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, + return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } @@ -685,7 +710,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_duplex_streaming( ops[1].flags = 0; ops[1].reserved = NULL; - return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, + return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } @@ -699,7 +724,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_recv_initial_metadata( ops[0].flags = 0; ops[0].reserved = NULL; - return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, + return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } @@ -720,7 +745,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_message( ops[1].flags = 0; ops[1].reserved = NULL; - return grpc_call_start_batch(call, ops, nops, ctx, NULL); + return grpcsharp_call_start_batch(call, ops, nops, ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_close_from_client( @@ -731,7 +756,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_close_from_client( ops[0].flags = 0; ops[0].reserved = NULL; - return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, + return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } @@ -773,7 +798,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server( ops[nops].reserved = NULL; nops++; } - return grpc_call_start_batch(call, ops, nops, ctx, NULL); + return grpcsharp_call_start_batch(call, ops, nops, ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE @@ -784,7 +809,7 @@ grpcsharp_call_recv_message(grpc_call *call, grpcsharp_batch_context *ctx) { ops[0].data.recv_message.recv_message = &(ctx->recv_message); ops[0].flags = 0; ops[0].reserved = NULL; - return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, + return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } @@ -798,7 +823,7 @@ grpcsharp_call_start_serverside(grpc_call *call, grpcsharp_batch_context *ctx) { ops[0].flags = 0; ops[0].reserved = NULL; - return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, + return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } @@ -817,7 +842,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_initial_metadata( ops[0].flags = 0; ops[0].reserved = NULL; - return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, + return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, NULL); } @@ -1092,3 +1117,21 @@ GPR_EXPORT void *GPR_CALLTYPE grpcsharp_test_nop(void *ptr) { return ptr; } GPR_EXPORT int32_t GPR_CALLTYPE grpcsharp_sizeof_grpc_event(void) { return sizeof(grpc_event); } + +/* Override a method for testing */ +GPR_EXPORT void GPR_CALLTYPE grpcsharp_test_override_method(const char *method_name, + const char *variant) { + if (strcmp("grpcsharp_call_start_batch", method_name) == 0) + { + if (strcmp("nop", variant) == 0) + { + g_call_start_batch_func = grpcsharp_call_start_batch_nop; + } else { + GPR_ASSERT(0); + } + } else { + GPR_ASSERT(0); + } +} + + From 7c206f4c154c0897898042060cf0be481995e131 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Mon, 22 May 2017 09:23:18 -0700 Subject: [PATCH 36/65] override in benchmark --- src/csharp/Grpc.Core/Internal/NativeMethods.cs | 2 +- src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/csharp/Grpc.Core/Internal/NativeMethods.cs b/src/csharp/Grpc.Core/Internal/NativeMethods.cs index 5ce792d296d..e703e3e6cee 100644 --- a/src/csharp/Grpc.Core/Internal/NativeMethods.cs +++ b/src/csharp/Grpc.Core/Internal/NativeMethods.cs @@ -437,7 +437,7 @@ namespace Grpc.Core.Internal public delegate CallError grpcsharp_test_callback_delegate([MarshalAs(UnmanagedType.FunctionPtr)] OpCompletionDelegate callback); public delegate IntPtr grpcsharp_test_nop_delegate(IntPtr ptr); - public delegate void grpcsharp_test_override_method(string methodName, string variant); + public delegate void grpcsharp_test_override_method_delegate(string methodName, string variant); } } } diff --git a/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs index 4575529bef6..eea375824f3 100644 --- a/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs +++ b/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs @@ -83,7 +83,7 @@ namespace Grpc.Microbenchmarks { call.StartSendMessage(sendCompletionHandler, payload, writeFlags, false); var callback = completionRegistry.Extract(completionRegistry.LastRegisteredKey); - callback(); + callback(true); } stopwatch.Stop(); Console.WriteLine("Elapsed millis: " + stopwatch.ElapsedMilliseconds); From 254ab4c085ae39c0935b06edccfffdaeaeda94a1 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 23 May 2017 18:07:17 +0200 Subject: [PATCH 37/65] clang format code --- src/csharp/ext/grpc_csharp_ext.c | 81 +++++++++++++++++--------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 34f8b928ddf..a56113eca3c 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -529,28 +529,35 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_call_destroy(grpc_call *call) { grpc_call_unref(call); } -typedef grpc_call_error (*grpcsharp_call_start_batch_func) ( - grpc_call *call, const grpc_op *ops, size_t nops, - void *tag, void *reserved); +typedef grpc_call_error (*grpcsharp_call_start_batch_func)(grpc_call *call, + const grpc_op *ops, + size_t nops, + void *tag, + void *reserved); /* Only for testing */ -static grpc_call_error grpcsharp_call_start_batch_nop( - grpc_call *call, const grpc_op *ops, size_t nops, - void *tag, void *reserved) { +static grpc_call_error grpcsharp_call_start_batch_nop(grpc_call *call, + const grpc_op *ops, + size_t nops, void *tag, + void *reserved) { return GRPC_CALL_OK; } -static grpc_call_error grpcsharp_call_start_batch_default( - grpc_call *call, const grpc_op *ops, size_t nops, - void *tag, void *reserved) { +static grpc_call_error grpcsharp_call_start_batch_default(grpc_call *call, + const grpc_op *ops, + size_t nops, + void *tag, + void *reserved) { return grpc_call_start_batch(call, ops, nops, tag, reserved); } -static grpcsharp_call_start_batch_func g_call_start_batch_func = grpcsharp_call_start_batch_default; +static grpcsharp_call_start_batch_func g_call_start_batch_func = + grpcsharp_call_start_batch_default; -static grpc_call_error grpcsharp_call_start_batch( - grpc_call *call, const grpc_op *ops, size_t nops, - void *tag, void *reserved) { +static grpc_call_error grpcsharp_call_start_batch(grpc_call *call, + const grpc_op *ops, + size_t nops, void *tag, + void *reserved) { return g_call_start_batch_func(call, ops, nops, tag, reserved); } @@ -601,8 +608,8 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_unary( ops[5].flags = 0; ops[5].reserved = NULL; - return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, - NULL); + return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), + ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_client_streaming( @@ -641,8 +648,8 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_client_streaming( ops[3].flags = 0; ops[3].reserved = NULL; - return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, - NULL); + return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), + ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming( @@ -681,8 +688,8 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming( ops[3].flags = 0; ops[3].reserved = NULL; - return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, - NULL); + return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), + ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_duplex_streaming( @@ -710,8 +717,8 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_duplex_streaming( ops[1].flags = 0; ops[1].reserved = NULL; - return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, - NULL); + return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), + ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_recv_initial_metadata( @@ -724,8 +731,8 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_recv_initial_metadata( ops[0].flags = 0; ops[0].reserved = NULL; - return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, - NULL); + return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), + ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_message( @@ -756,8 +763,8 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_close_from_client( ops[0].flags = 0; ops[0].reserved = NULL; - return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, - NULL); + return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), + ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server( @@ -809,8 +816,8 @@ grpcsharp_call_recv_message(grpc_call *call, grpcsharp_batch_context *ctx) { ops[0].data.recv_message.recv_message = &(ctx->recv_message); ops[0].flags = 0; ops[0].reserved = NULL; - return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, - NULL); + return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), + ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE @@ -823,8 +830,8 @@ grpcsharp_call_start_serverside(grpc_call *call, grpcsharp_batch_context *ctx) { ops[0].flags = 0; ops[0].reserved = NULL; - return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, - NULL); + return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), + ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_initial_metadata( @@ -842,8 +849,8 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_initial_metadata( ops[0].flags = 0; ops[0].reserved = NULL; - return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx, - NULL); + return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), + ctx, NULL); } GPR_EXPORT grpc_call_error GPR_CALLTYPE @@ -1119,12 +1126,10 @@ GPR_EXPORT int32_t GPR_CALLTYPE grpcsharp_sizeof_grpc_event(void) { } /* Override a method for testing */ -GPR_EXPORT void GPR_CALLTYPE grpcsharp_test_override_method(const char *method_name, - const char *variant) { - if (strcmp("grpcsharp_call_start_batch", method_name) == 0) - { - if (strcmp("nop", variant) == 0) - { +GPR_EXPORT void GPR_CALLTYPE +grpcsharp_test_override_method(const char *method_name, const char *variant) { + if (strcmp("grpcsharp_call_start_batch", method_name) == 0) { + if (strcmp("nop", variant) == 0) { g_call_start_batch_func = grpcsharp_call_start_batch_nop; } else { GPR_ASSERT(0); @@ -1133,5 +1138,3 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_test_override_method(const char *method_n GPR_ASSERT(0); } } - - From c92df4cbbd0dded5efe095223a578fc6746405e1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 23 May 2017 10:28:47 -0700 Subject: [PATCH 38/65] Refactor some code and document most of the API --- src/node/README.md | 64 +--- src/node/index.js | 142 ++++----- src/node/src/client.js | 254 ++++++++------- src/node/src/common.js | 64 +++- src/node/src/constants.js | 24 +- src/node/src/credentials.js | 63 +++- src/node/src/grpc_extension.js | 4 +- src/node/src/metadata.js | 15 +- src/node/src/protobuf_js_5_common.js | 9 +- src/node/src/protobuf_js_6_common.js | 9 +- src/node/src/server.js | 445 ++++++++++++++++++--------- src/node/test/surface_test.js | 8 +- 12 files changed, 653 insertions(+), 448 deletions(-) diff --git a/src/node/README.md b/src/node/README.md index 4b906643bc0..3b98b97879b 100644 --- a/src/node/README.md +++ b/src/node/README.md @@ -2,9 +2,9 @@ # Node.js gRPC Library ## PREREQUISITES -- `node`: This requires `node` to be installed, version `0.12` or above. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package. +- `node`: This requires `node` to be installed, version `4.0` or above. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package. -- **Note:** If you installed `node` via a package manager and the version is still less than `0.12`, try directly installing it from [nodejs.org](https://nodejs.org). +- **Note:** If you installed `node` via a package manager and the version is still less than `4.0`, try directly installing it from [nodejs.org](https://nodejs.org). ## INSTALLATION @@ -16,7 +16,7 @@ npm install grpc ## BUILD FROM SOURCE 1. Clone [the grpc Git Repository](https://github.com/grpc/grpc). - 2. Run `npm install` from the repository root. + 2. Run `npm install --build-from-source` from the repository root. - **Note:** On Windows, this might fail due to [nodejs issue #4932](https://github.com/nodejs/node/issues/4932) in which case, you will see something like the following in `npm install`'s output (towards the very beginning): @@ -34,61 +34,3 @@ npm install grpc ## TESTING To run the test suite, simply run `npm test` in the install location. - -## API -This library internally uses [ProtoBuf.js](https://github.com/dcodeIO/ProtoBuf.js), and some structures it exports match those exported by that library. - -If you require this module, you will get an object with the following members - -```javascript -function load(filename) -``` - -Takes a filename of a [Protocol Buffer](https://developers.google.com/protocol-buffers/) file, and returns an object representing the structure of the protocol buffer in the following way: - - - Namespaces become maps from the names of their direct members to those member objects - - Service definitions become client constructors for clients for that service. They also have a `service` member that can be used for constructing servers. - - Message definitions become Message constructors like those that ProtoBuf.js would create - - Enum definitions become Enum objects like those that ProtoBuf.js would create - - Anything else becomes the relevant reflection object that ProtoBuf.js would create - - -```javascript -function loadObject(reflectionObject) -``` - -Returns the same structure that `load` returns, but takes a reflection object from `ProtoBuf.js` instead of a file name. - -```javascript -function Server([serverOptions]) -``` - -Constructs a server to which service/implementation pairs can be added. - - -```javascript -status -``` - -An object mapping status names to status code numbers. - - -```javascript -callError -``` - -An object mapping call error names to codes. This is primarily useful for tracking down certain kinds of internal errors. - - -```javascript -Credentials -``` - -An object with factory methods for creating credential objects for clients. - - -```javascript -ServerCredentials -``` - -An object with factory methods for creating credential objects for servers. diff --git a/src/node/index.js b/src/node/index.js index 0da3440eb77..f217994ab46 100644 --- a/src/node/index.js +++ b/src/node/index.js @@ -1,5 +1,5 @@ -/* - * +/** + * @license * Copyright 2015, Google Inc. * All rights reserved. * @@ -31,10 +31,6 @@ * */ -/** - * @module - */ - 'use strict'; var path = require('path'); @@ -64,26 +60,30 @@ var constants = require('./src/constants.js'); grpc.setDefaultRootsPem(fs.readFileSync(SSL_ROOTS_PATH, 'ascii')); /** - * Load a ProtoBuf.js object as a gRPC object. The options object can provide - * the following options: - * - binaryAsBase64: deserialize bytes values as base64 strings instead of - * Buffers. Defaults to false - * - longsAsStrings: deserialize long values as strings instead of objects. - * Defaults to true - * - enumsAsStrings: deserialize enum values as strings instead of numbers. - * Defaults to true - * - deprecatedArgumentOrder: Use the beta method argument order for client - * methods, with optional arguments after the callback. Defaults to false. - * This option is only a temporary stopgap measure to smooth an API breakage. - * It is deprecated, and new code should not use it. - * - protobufjsVersion: Available values are 5, 6, and 'detect'. 5 and 6 - * respectively indicate that an object from the corresponding version of - * ProtoBuf.js is provided in the value argument. If the option is 'detect', - * gRPC will guess what the version is based on the structure of the value. - * Defaults to 'detect'. + * @namespace grpc + */ + +/** + * Load a ProtoBuf.js object as a gRPC object. + * @memberof grpc + * @alias grpc.loadObject * @param {Object} value The ProtoBuf.js reflection object to load * @param {Object=} options Options to apply to the loaded file - * @return {Object} The resulting gRPC object + * @param {bool=} [options.binaryAsBase64=false] deserialize bytes values as + * base64 strings instead of Buffers + * @param {bool=} [options.longsAsStrings=true] deserialize long values as + * strings instead of objects + * @param {bool=} [options.enumsAsStrings=true] deserialize enum values as + * strings instead of numbers. Only works with Protobuf.js 6 values. + * @param {bool=} [options.deprecatedArgumentOrder=false] use the beta method + * argument order for client methods, with optional arguments after the + * callback. This option is only a temporary stopgap measure to smooth an + * API breakage. It is deprecated, and new code should not use it. + * @param {(number|string)=} [options.protobufjsVersion='detect'] 5 and 6 + * respectively indicate that an object from the corresponding version of + * Protobuf.js is provided in the value argument. If the option is 'detect', + * gRPC wll guess what the version is based on the structure of the value. + * @return {Object} The resulting gRPC object. */ exports.loadObject = function loadObject(value, options) { options = _.defaults(options, common.defaultGrpcOptions); @@ -131,24 +131,23 @@ function applyProtoRoot(filename, root) { } /** - * Load a gRPC object from a .proto file. The options object can provide the - * following options: - * - convertFieldsToCamelCase: Load this file with field names in camel case - * instead of their original case - * - binaryAsBase64: deserialize bytes values as base64 strings instead of - * Buffers. Defaults to false - * - longsAsStrings: deserialize long values as strings instead of objects. - * Defaults to true - * - enumsAsStrings: deserialize enum values as strings instead of numbers. - * Defaults to true - * - deprecatedArgumentOrder: Use the beta method argument order for client - * methods, with optional arguments after the callback. Defaults to false. - * This option is only a temporary stopgap measure to smooth an API breakage. - * It is deprecated, and new code should not use it. + * Load a gRPC object from a .proto file. + * @memberof grpc + * @alias grpc.load * @param {string|{root: string, file: string}} filename The file to load * @param {string=} format The file format to expect. Must be either 'proto' or * 'json'. Defaults to 'proto' * @param {Object=} options Options to apply to the loaded file + * @param {bool=} [options.convertFieldsToCamelCase=false] Load this file with + * field names in camel case instead of their original case + * @param {bool=} [options.binaryAsBase64=false] deserialize bytes values as + * base64 strings instead of Buffers + * @param {bool=} [options.longsAsStrings=true] deserialize long values as + * strings instead of objects + * @param {bool=} [options.deprecatedArgumentOrder=false] use the beta method + * argument order for client methods, with optional arguments after the + * callback. This option is only a temporary stopgap measure to smooth an + * API breakage. It is deprecated, and new code should not use it. * @return {Object} The resulting gRPC object */ exports.load = function load(filename, format, options) { @@ -175,6 +174,8 @@ var log_template = _.template( * called. Note: the output format here is intended to be informational, and * is not guaranteed to stay the same in the future. * Logs will be directed to logger.error. + * @memberof grpc + * @alias grpc.setLogger * @param {Console} logger A Console-like object. */ exports.setLogger = function setLogger(logger) { @@ -194,6 +195,8 @@ exports.setLogger = function setLogger(logger) { /** * Sets the logger verbosity for gRPC module logging. The options are members * of the grpc.logVerbosity map. + * @memberof grpc + * @alias grpc.setLogVerbosity * @param {Number} verbosity The minimum severity to log */ exports.setLogVerbosity = function setLogVerbosity(verbosity) { @@ -201,71 +204,70 @@ exports.setLogVerbosity = function setLogVerbosity(verbosity) { grpc.setLogVerbosity(verbosity); }; -/** - * @see module:src/server.Server - */ exports.Server = server.Server; -/** - * @see module:src/metadata - */ exports.Metadata = Metadata; -/** - * Status name to code number mapping - */ exports.status = constants.status; -/** - * Propagate flag name to number mapping - */ exports.propagate = constants.propagate; -/** - * Call error name to code number mapping - */ exports.callError = constants.callError; -/** - * Write flag name to code number mapping - */ exports.writeFlags = constants.writeFlags; -/** - * Log verbosity setting name to code number mapping - */ exports.logVerbosity = constants.logVerbosity; -/** - * Credentials factories - */ exports.credentials = require('./src/credentials.js'); /** * ServerCredentials factories + * @constructor ServerCredentials + * @memberof grpc */ exports.ServerCredentials = grpc.ServerCredentials; /** - * @see module:src/client.makeClientConstructor + * Create insecure server credentials + * @name grpc.ServerCredentials.createInsecure + * @kind function + * @return grpc.ServerCredentials */ -exports.makeGenericClientConstructor = client.makeClientConstructor; /** - * @see module:src/client.getClientChannel + * A private key and certificate pair + * @typedef {Object} grpc.ServerCredentials~keyCertPair + * @property {Buffer} privateKey The server's private key + * @property {Buffer} certChain The server's certificate chain */ -exports.getClientChannel = client.getClientChannel; /** - * @see module:src/client.waitForClientReady + * Create SSL server credentials + * @name grpc.ServerCredentials.createInsecure + * @kind function + * @param {?Buffer} rootCerts Root CA certificates for validating client + * certificates + * @param {Array} keyCertPairs A list of + * private key and certificate chain pairs to be used for authenticating + * the server + * @param {boolean} [checkClientCertificate=false] Indicates that the server + * should request and verify the client's certificates + * @return grpc.ServerCredentials */ + +exports.makeGenericClientConstructor = client.makeClientConstructor; + +exports.getClientChannel = client.getClientChannel; + exports.waitForClientReady = client.waitForClientReady; +/** + * @memberof grpc + * @alias grpc.closeClient + * @param {grpc.Client} client_obj The client to close + */ exports.closeClient = function closeClient(client_obj) { client.Client.prototype.close.apply(client_obj); }; -/** - * @see module:src/client.Client - */ exports.Client = client.Client; diff --git a/src/node/src/client.js b/src/node/src/client.js index 16fe06a54d2..cf4c104144c 100644 --- a/src/node/src/client.js +++ b/src/node/src/client.js @@ -1,5 +1,5 @@ -/* - * +/** + * @license * Copyright 2015, Google Inc. * All rights reserved. * @@ -43,8 +43,6 @@ * var Client = proto_obj.package.subpackage.ServiceName; * var client = new Client(server_address, client_credentials); * var call = client.unaryMethod(arguments, callback); - * - * @module */ 'use strict'; @@ -70,13 +68,26 @@ var Duplex = stream.Duplex; var util = require('util'); var version = require('../../../package.json').version; +/** + * Initial response metadata sent by the server when it starts processing the + * call + * @event grpc~ClientUnaryCall#metadata + * @type {grpc.Metadata} + */ + +/** + * Status of the call when it has completed. + * @event grpc~ClientUnaryCall#status + * @type grpc~StatusObject + */ + util.inherits(ClientUnaryCall, EventEmitter); /** - * An EventEmitter. Used for unary calls - * @constructor + * An EventEmitter. Used for unary calls. + * @constructor grpc~ClientUnaryCall * @extends external:EventEmitter - * @param {grpc.Call} call The call object associated with the request + * @param {grpc.internal~Call} call The call object associated with the request */ function ClientUnaryCall(call) { EventEmitter.call(this); @@ -88,14 +99,16 @@ util.inherits(ClientWritableStream, Writable); /** * A stream that the client can write to. Used for calls that are streaming from * the client side. - * @constructor + * @constructor grpc~ClientWritableStream * @extends external:Writable - * @borrows module:src/client~ClientUnaryCall#cancel as - * module:src/client~ClientWritableStream#cancel - * @borrows module:src/client~ClientUnaryCall#getPeer as - * module:src/client~ClientWritableStream#getPeer - * @param {grpc.Call} call The call object to send data with - * @param {module:src/common~serialize=} [serialize=identity] Serialization + * @borrows grpc~ClientUnaryCall#cancel as grpc~ClientWritableStream#cancel + * @borrows grpc~ClientUnaryCall#getPeer as grpc~ClientWritableStream#getPeer + * @borrows grpc~ClientUnaryCall#event:metadata as + * grpc~ClientWritableStream#metadata + * @borrows grpc~ClientUnaryCall#event:status as + * grpc~ClientWritableStream#status + * @param {grpc.internal~Call} call The call object to send data with + * @param {grpc~serialize=} [serialize=identity] Serialization * function for writes. */ function ClientWritableStream(call, serialize) { @@ -109,12 +122,25 @@ function ClientWritableStream(call, serialize) { }); } +/** + * Write a message to the request stream. If serializing the argument fails, + * the call will be cancelled and the stream will end with an error. + * @name grpc~ClientWritableStream#write + * @kind function + * @override + * @param {*} message The message to write. Must be a valid argument to the + * serialize function of the corresponding method + * @param {grpc.writeFlags} flags Flags to modify how the message is written + * @param {Function} callback Callback for when this chunk of data is flushed + * @return {boolean} As defined for [Writable]{@link external:Writable} + */ + /** * Attempt to write the given chunk. Calls the callback when done. This is an * implementation of a method needed for implementing stream.Writable. - * @access private - * @param {Buffer} chunk The chunk to write - * @param {string} encoding Used to pass write flags + * @private + * @param {*} chunk The chunk to write + * @param {grpc.writeFlags} encoding Used to pass write flags * @param {function(Error=)} callback Called when the write is complete */ function _write(chunk, encoding, callback) { @@ -155,14 +181,16 @@ util.inherits(ClientReadableStream, Readable); /** * A stream that the client can read from. Used for calls that are streaming * from the server side. - * @constructor + * @constructor grpc~ClientReadableStream * @extends external:Readable - * @borrows module:src/client~ClientUnaryCall#cancel as - * module:src/client~ClientReadableStream#cancel - * @borrows module:src/client~ClientUnaryCall#getPeer as - * module:src/client~ClientReadableStream#getPeer - * @param {grpc.Call} call The call object to read data with - * @param {module:src/common~deserialize=} [deserialize=identity] + * @borrows grpc~ClientUnaryCall#cancel as grpc~ClientReadableStream#cancel + * @borrows grpc~ClientUnaryCall#getPeer as grpc~ClientReadableStream#getPeer + * @borrows grpc~ClientUnaryCall#event:metadata as + * grpc~ClientReadableStream#metadata + * @borrows grpc~ClientUnaryCall#event:status as + * grpc~ClientReadableStream#status + * @param {grpc.internal~Call} call The call object to read data with + * @param {grpc~deserialize=} [deserialize=identity] * Deserialization function for reads */ function ClientReadableStream(call, deserialize) { @@ -183,7 +211,7 @@ function ClientReadableStream(call, deserialize) { * parameter indicates that the call should end with that status. status * defaults to OK if not provided. * @param {Object!} status The status that the call should end with - * @access private + * @private */ function _readsDone(status) { /* jshint validthis: true */ @@ -202,7 +230,7 @@ ClientReadableStream.prototype._readsDone = _readsDone; /** * Called to indicate that we have received a status from the server. - * @access private + * @private */ function _receiveStatus(status) { /* jshint validthis: true */ @@ -215,7 +243,7 @@ ClientReadableStream.prototype._receiveStatus = _receiveStatus; /** * If we have both processed all incoming messages and received the status from * the server, emit the status. Otherwise, do nothing. - * @access private + * @private */ function _emitStatusIfDone() { /* jshint validthis: true */ @@ -242,7 +270,7 @@ ClientReadableStream.prototype._emitStatusIfDone = _emitStatusIfDone; /** * Read the next object from the stream. - * @access private + * @private * @param {*} size Ignored because we use objectMode=true */ function _read(size) { @@ -300,16 +328,19 @@ util.inherits(ClientDuplexStream, Duplex); /** * A stream that the client can read from or write to. Used for calls with * duplex streaming. - * @constructor + * @constructor grpc~ClientDuplexStream * @extends external:Duplex - * @borrows module:src/client~ClientUnaryCall#cancel as - * module:src/client~ClientDuplexStream#cancel - * @borrows module:src/client~ClientUnaryCall#getPeer as - * module:src/client~ClientDuplexStream#getPeer - * @param {grpc.Call} call Call object to proxy - * @param {module:src/common~serialize=} [serialize=identity] Serialization + * @borrows grpc~ClientUnaryCall#cancel as grpc~ClientDuplexStream#cancel + * @borrows grpc~ClientUnaryCall#getPeer as grpc~ClientDuplexStream#getPeer + * @borrows grpc~ClientWritableStream#write as grpc~ClientDuplexStream#write + * @borrows grpc~ClientUnaryCall#event:metadata as + * grpc~ClientDuplexStream#metadata + * @borrows grpc~ClientUnaryCall#event:status as + * grpc~ClientDuplexStream#status + * @param {grpc.internal~Call} call Call object to proxy + * @param {grpc~serialize=} [serialize=identity] Serialization * function for requests - * @param {module:src/common~deserialize=} [deserialize=identity] + * @param {grpc~deserialize=} [deserialize=identity] * Deserialization function for responses */ function ClientDuplexStream(call, serialize, deserialize) { @@ -336,8 +367,9 @@ ClientDuplexStream.prototype._read = _read; ClientDuplexStream.prototype._write = _write; /** - * Cancel the ongoing call - * @alias module:src/client~ClientUnaryCall#cancel + * Cancel the ongoing call. Results in the call ending with a CANCELLED status, + * unless it has already ended with some other status. + * @alias grpc~ClientUnaryCall#cancel */ function cancel() { /* jshint validthis: true */ @@ -352,7 +384,7 @@ ClientDuplexStream.prototype.cancel = cancel; /** * Get the endpoint this call/stream is connected to. * @return {string} The URI of the endpoint - * @alias module:src/client~ClientUnaryCall#getPeer + * @alias grpc~ClientUnaryCall#getPeer */ function getPeer() { /* jshint validthis: true */ @@ -368,33 +400,31 @@ ClientDuplexStream.prototype.getPeer = getPeer; * Any client call type * @typedef {(ClientUnaryCall|ClientReadableStream| * ClientWritableStream|ClientDuplexStream)} - * module:src/client~Call + * grpc.Client~Call */ /** * Options that can be set on a call. - * @typedef {Object} module:src/client~CallOptions - * @property {(date|number)} deadline The deadline for the entire call to - * complete. A value of Infinity indicates that no deadline should be set. - * @property {(string)} host Server hostname to set on the call. Only meaningful + * @typedef {Object} grpc.Client~CallOptions + * @property {grpc~Deadline} deadline The deadline for the entire call to + * complete. + * @property {string} host Server hostname to set on the call. Only meaningful * if different from the server address used to construct the client. - * @property {module:src/client~Call} parent Parent call. Used in servers when + * @property {grpc.Client~Call} parent Parent call. Used in servers when * making a call as part of the process of handling a call. Used to * propagate some information automatically, as specified by * propagate_flags. * @property {number} propagate_flags Indicates which properties of a parent * call should propagate to this call. Bitwise combination of flags in - * [grpc.propagate]{@link module:index.propagate}. - * @property {module:src/credentials~CallCredentials} credentials The - * credentials that should be used to make this particular call. + * {@link grpc.propagate}. + * @property {grpc.credentials~CallCredentials} credentials The credentials that + * should be used to make this particular call. */ /** - * Get a call object built with the provided options. Keys for options are - * 'deadline', which takes a date or number, and 'host', which takes a string - * and overrides the hostname to connect to. + * Get a call object built with the provided options. * @access private - * @param {module:src/client~CallOptions=} options Options object. + * @param {grpc.Client~CallOptions=} options Options object. */ function getCall(channel, method, options) { var deadline; @@ -422,14 +452,14 @@ function getCall(channel, method, options) { /** * A generic gRPC client. Primarily useful as a base class for generated clients - * @alias module:src/client.Client + * @memberof grpc * @constructor * @param {string} address Server address to connect to - * @param {module:src/credentials~ChannelCredentials} credentials Credentials to - * use to connect to the server + * @param {grpc~ChannelCredentials} credentials Credentials to use to connect to + * the server * @param {Object} options Options to apply to channel creation */ -var Client = exports.Client = function Client(address, credentials, options) { +function Client(address, credentials, options) { if (!options) { options = {}; } @@ -445,19 +475,13 @@ var Client = exports.Client = function Client(address, credentials, options) { /* Private fields use $ as a prefix instead of _ because it is an invalid * prefix of a method name */ this.$channel = new grpc.Channel(address, credentials, options); -}; +} -/** - * @typedef {Error} module:src/client.Client~ServiceError - * @property {number} code The error code, a key of - * [grpc.status]{@link module:src/client.status} - * @property {module:metadata.Metadata} metadata Metadata sent with the status - * by the server, if any - */ +exports.Client = Client; /** - * @callback module:src/client.Client~requestCallback - * @param {?module:src/client.Client~ServiceError} error The error, if the call + * @callback grpc.Client~requestCallback + * @param {?grpc~ServiceError} error The error, if the call * failed * @param {*} value The response value, if the call succeeded */ @@ -466,17 +490,17 @@ var Client = exports.Client = function Client(address, credentials, options) { * Make a unary request to the given method, using the given serialize * and deserialize functions, with the given argument. * @param {string} method The name of the method to request - * @param {module:src/common~serialize} serialize The serialization function for + * @param {grpc~serialize} serialize The serialization function for * inputs - * @param {module:src/common~deserialize} deserialize The deserialization + * @param {grpc~deserialize} deserialize The deserialization * function for outputs * @param {*} argument The argument to the call. Should be serializable with * serialize - * @param {module:src/metadata.Metadata=} metadata Metadata to add to the call - * @param {module:src/client~CallOptions=} options Options map - * @param {module:src/client.Client~requestCallback} callback The callback to + * @param {grpc.Metadata=} metadata Metadata to add to the call + * @param {grpc.Client~CallOptions=} options Options map + * @param {grpc.Client~requestCallback} callback The callback to * for when the response is received - * @return {EventEmitter} An event emitter for stream related events + * @return {grpc~ClientUnaryCall} An event emitter for stream related events */ Client.prototype.makeUnaryRequest = function(method, serialize, deserialize, argument, metadata, options, @@ -548,17 +572,17 @@ Client.prototype.makeUnaryRequest = function(method, serialize, deserialize, * Make a client stream request to the given method, using the given serialize * and deserialize functions, with the given argument. * @param {string} method The name of the method to request - * @param {module:src/common~serialize} serialize The serialization function for + * @param {grpc~serialize} serialize The serialization function for * inputs - * @param {module:src/common~deserialize} deserialize The deserialization + * @param {grpc~deserialize} deserialize The deserialization * function for outputs - * @param {module:src/metadata.Metadata=} metadata Array of metadata key/value - * pairs to add to the call - * @param {module:src/client~CallOptions=} options Options map - * @param {Client~requestCallback} callback The callback to for when the + * @param {grpc.Metadata=} metadata Array of metadata key/value pairs to add to + * the call + * @param {grpc.Client~CallOptions=} options Options map + * @param {grpc.Client~requestCallback} callback The callback to for when the * response is received - * @return {module:src/client~ClientWritableStream} An event emitter for stream - * related events + * @return {grpc~ClientWritableStream} An event emitter for stream related + * events */ Client.prototype.makeClientStreamRequest = function(method, serialize, deserialize, metadata, @@ -631,17 +655,16 @@ Client.prototype.makeClientStreamRequest = function(method, serialize, * Make a server stream request to the given method, with the given serialize * and deserialize function, using the given argument * @param {string} method The name of the method to request - * @param {module:src/common~serialize} serialize The serialization function for - * inputs - * @param {module:src/common~deserialize} deserialize The deserialization + * @param {grpc~serialize} serialize The serialization function for inputs + * @param {grpc~deserialize} deserialize The deserialization * function for outputs * @param {*} argument The argument to the call. Should be serializable with * serialize - * @param {module:src/metadata.Metadata=} metadata Array of metadata key/value - * pairs to add to the call - * @param {module:src/client~CallOptions=} options Options map - * @return {module:src/client~ClientReadableStream} An event emitter for stream - * related events + * @param {grpc.Metadata=} metadata Array of metadata key/value pairs to add to + * the call + * @param {grpc.Client~CallOptions=} options Options map + * @return {grpc~ClientReadableStream} An event emitter for stream related + * events */ Client.prototype.makeServerStreamRequest = function(method, serialize, deserialize, argument, @@ -693,15 +716,13 @@ Client.prototype.makeServerStreamRequest = function(method, serialize, /** * Make a bidirectional stream request with this method on the given channel. * @param {string} method The name of the method to request - * @param {module:src/common~serialize} serialize The serialization function for - * inputs - * @param {module:src/common~deserialize} deserialize The deserialization + * @param {grpc~serialize} serialize The serialization function for inputs + * @param {grpc~deserialize} deserialize The deserialization * function for outputs - * @param {module:src/metadata.Metadata=} metadata Array of metadata key/value + * @param {grpc.Metadata=} metadata Array of metadata key/value * pairs to add to the call - * @param {module:src/client~CallOptions=} options Options map - * @return {module:src/client~ClientDuplexStream} An event emitter for stream - * related events + * @param {grpc.Client~CallOptions=} options Options map + * @return {grpc~ClientDuplexStream} An event emitter for stream related events */ Client.prototype.makeBidiStreamRequest = function(method, serialize, deserialize, metadata, @@ -743,6 +764,9 @@ Client.prototype.makeBidiStreamRequest = function(method, serialize, return stream; }; +/** + * Close this client. + */ Client.prototype.close = function() { this.$channel.close(); }; @@ -761,8 +785,7 @@ Client.prototype.getChannel = function() { * with an error if the attempt to connect to the server has unrecoverablly * failed or if the deadline expires. This function will make the channel * start connecting if it has not already done so. - * @param {(Date|Number)} deadline When to stop waiting for a connection. Pass - * Infinity to wait forever. + * @param {grpc~Deadline} deadline When to stop waiting for a connection. * @param {function(Error)} callback The callback to call when done attempting * to connect. */ @@ -788,7 +811,7 @@ Client.prototype.waitForReady = function(deadline, callback) { /** * Map with short names for each of the requester maker functions. Used in * makeClientConstructor - * @access private + * @private */ var requester_funcs = { unary: Client.prototype.makeUnaryRequest, @@ -834,9 +857,15 @@ var deprecated_request_wrap = { /** * Creates a constructor for a client with the given methods, as specified in - * the methods argument. - * @param {module:src/common~ServiceDefinition} methods An object mapping - * method names to method attributes + * the methods argument. The resulting class will have an instance method for + * each method in the service, which is a partial application of one of the + * [Client]{@link grpc.Client} request methods, depending on `requestSerialize` + * and `responseSerialize`, with the `method`, `serialize`, and `deserialize` + * arguments predefined. + * @memberof grpc + * @alias grpc~makeGenericClientConstructor + * @param {grpc~ServiceDefinition} methods An object mapping method names to + * method attributes * @param {string} serviceName The fully qualified name of the service * @param {Object} class_options An options object. * @param {boolean=} [class_options.deprecatedArgumentOrder=false] Indicates @@ -844,9 +873,8 @@ var deprecated_request_wrap = { * arguments at the end instead of the callback at the end. This option * is only a temporary stopgap measure to smooth an API breakage. * It is deprecated, and new code should not use it. - * @return {function(string, Object)} New client constructor, which is a - * subclass of [grpc.Client]{@link module:src/client.Client}, and has the - * same arguments as that constructor. + * @return {function} New client constructor, which is a subclass of + * {@link grpc.Client}, and has the same arguments as that constructor. */ exports.makeClientConstructor = function(methods, serviceName, class_options) { @@ -898,8 +926,11 @@ exports.makeClientConstructor = function(methods, serviceName, /** * Return the underlying channel object for the specified client + * @memberof grpc + * @alias grpc~getClientChannel * @param {Client} client * @return {Channel} The channel + * @see grpc.Client#getChannel */ exports.getClientChannel = function(client) { return Client.prototype.getChannel.call(client); @@ -911,22 +942,15 @@ exports.getClientChannel = function(client) { * with an error if the attempt to connect to the server has unrecoverablly * failed or if the deadline expires. This function will make the channel * start connecting if it has not already done so. + * @memberof grpc + * @alias grpc~waitForClientReady * @param {Client} client The client to wait on - * @param {(Date|Number)} deadline When to stop waiting for a connection. Pass + * @param {grpc~Deadline} deadline When to stop waiting for a connection. Pass * Infinity to wait forever. * @param {function(Error)} callback The callback to call when done attempting * to connect. + * @see grpc.Client#waitForReady */ exports.waitForClientReady = function(client, deadline, callback) { Client.prototype.waitForReady.call(client, deadline, callback); }; - -/** - * Map of status code names to status codes - */ -exports.status = constants.status; - -/** - * See docs for client.callError - */ -exports.callError = grpc.callError; diff --git a/src/node/src/common.js b/src/node/src/common.js index 4dad60e630f..0f835317ea6 100644 --- a/src/node/src/common.js +++ b/src/node/src/common.js @@ -1,5 +1,5 @@ -/* - * +/** + * @license * Copyright 2015, Google Inc. * All rights reserved. * @@ -31,12 +31,6 @@ * */ -/** - * This module contains functions that are common to client and server - * code. None of them should be used directly by gRPC users. - * @module - */ - 'use strict'; var _ = require('lodash'); @@ -62,16 +56,19 @@ exports.wrapIgnoreNull = function wrapIgnoreNull(func) { /** * The logger object for the gRPC module. Defaults to console. + * @private */ exports.logger = console; /** * The current logging verbosity. 0 corresponds to logging everything + * @private */ exports.logVerbosity = 0; /** * Log a message if the severity is at least as high as the current verbosity + * @private * @param {Number} severity A value of the grpc.logVerbosity map * @param {String} message The message to log */ @@ -83,6 +80,7 @@ exports.log = function log(severity, message) { /** * Default options for loading proto files into gRPC + * @alias grpc~defaultLoadOptions */ exports.defaultGrpcOptions = { convertFieldsToCamelCase: false, @@ -94,6 +92,30 @@ exports.defaultGrpcOptions = { // JSDoc definitions that are used in multiple other modules +/** + * Represents the status of a completed request. If `code` is + * {@link grpc.status}.OK, then the request has completed successfully. + * Otherwise, the request has failed, `details` will contain a description of + * the error. Either way, `metadata` contains the trailing response metadata + * sent by the server when it finishes processing the call. + * @typedef {object} grpc~StatusObject + * @property {number} code The error code, a key of {@link grpc.status} + * @property {string} details Human-readable description of the status + * @property {grpc.Metadata} metadata Trailing metadata sent with the status, + * if applicable + */ + +/** + * Describes how a request has failed. The member `message` will be the same as + * `details` in {@link grpc~StatusObject}, and `code` and `metadata` are the + * same as in that object. + * @typedef {Error} grpc~ServiceError + * @property {number} code The error code, a key of {@link grpc.status} that is + * not `grpc.status.OK` + * @property {grpc.Metadata} metadata Trailing metadata sent with the status, + * if applicable + */ + /** * The EventEmitter class in the event standard module * @external EventEmitter @@ -120,38 +142,46 @@ exports.defaultGrpcOptions = { /** * A serialization function - * @callback module:src/common~serialize + * @callback grpc~serialize * @param {*} value The value to serialize * @return {Buffer} The value serialized as a byte sequence */ /** * A deserialization function - * @callback module:src/common~deserialize + * @callback grpc~deserialize * @param {Buffer} data The byte sequence to deserialize * @return {*} The data deserialized as a value */ +/** + * The deadline of an operation. If it is a date, the deadline is reached at + * the date and time specified. If it is a finite number, it is treated as + * a number of milliseconds since the Unix Epoch. If it is Infinity, the + * deadline will never be reached. If it is -Infinity, the deadline has already + * passed. + * @typedef {(number|date)} grpc~Deadline + */ + /** * An object that completely defines a service method signature. - * @typedef {Object} module:src/common~MethodDefinition + * @typedef {Object} grpc~MethodDefinition * @property {string} path The method's URL path * @property {boolean} requestStream Indicates whether the method accepts * a stream of requests * @property {boolean} responseStream Indicates whether the method returns * a stream of responses - * @property {module:src/common~serialize} requestSerialize Serialization + * @property {grpc~serialize} requestSerialize Serialization * function for request values - * @property {module:src/common~serialize} responseSerialize Serialization + * @property {grpc~serialize} responseSerialize Serialization * function for response values - * @property {module:src/common~deserialize} requestDeserialize Deserialization + * @property {grpc~deserialize} requestDeserialize Deserialization * function for request data - * @property {module:src/common~deserialize} responseDeserialize Deserialization + * @property {grpc~deserialize} responseDeserialize Deserialization * function for repsonse data */ /** * An object that completely defines a service. - * @typedef {Object.} - * module:src/common~ServiceDefinition + * @typedef {Object.} grpc~ServiceDefinition */ diff --git a/src/node/src/constants.js b/src/node/src/constants.js index 528dab120e0..c441ee740b2 100644 --- a/src/node/src/constants.js +++ b/src/node/src/constants.js @@ -1,5 +1,5 @@ -/* - * +/** + * @license * Copyright 2017, Google Inc. * All rights reserved. * @@ -31,16 +31,14 @@ * */ -/** - * @module - */ - /* The comments about status codes are copied verbatim (with some formatting * modifications) from include/grpc/impl/codegen/status.h, for the purpose of * including them in generated documentation. */ /** * Enum of status codes that gRPC can return + * @memberof grpc + * @alias grpc.status * @readonly * @enum {number} */ @@ -178,6 +176,8 @@ exports.status = { * Users are encouraged to write propagation masks as deltas from the default. * i.e. write `grpc.propagate.DEFAULTS & ~grpc.propagate.DEADLINE` to disable * deadline propagation. + * @memberof grpc + * @alias grpc.propagate * @enum {number} */ exports.propagate = { @@ -194,9 +194,11 @@ exports.propagate = { /** * Call error constants. Call errors almost always indicate bugs in the gRPC * library, and these error codes are mainly useful for finding those bugs. + * @memberof grpc + * @readonly * @enum {number} */ -exports.callError = { +const callError = { OK: 0, ERROR: 1, NOT_ON_SERVER: 2, @@ -213,9 +215,14 @@ exports.callError = { PAYLOAD_TYPE_MISMATCH: 14 }; +exports.callError = callError; + /** * Write flags: these can be bitwise or-ed to form write options that modify * how data is written. + * @memberof grpc + * @alias grpc.writeFlags + * @readonly * @enum {number} */ exports.writeFlags = { @@ -232,6 +239,9 @@ exports.writeFlags = { }; /** + * @memberof grpc + * @alias grpc.logVerbosity + * @readonly * @enum {number} */ exports.logVerbosity = { diff --git a/src/node/src/credentials.js b/src/node/src/credentials.js index b1e86bbd090..b1dbc1c450b 100644 --- a/src/node/src/credentials.js +++ b/src/node/src/credentials.js @@ -1,5 +1,5 @@ -/* - * +/** + * @license * Copyright 2015, Google Inc. * All rights reserved. * @@ -48,6 +48,7 @@ * For example, to create a client secured with SSL that uses Google * default application credentials to authenticate: * + * @example * var channel_creds = credentials.createSsl(root_certs); * (new GoogleAuth()).getApplicationDefault(function(err, credential) { * var call_creds = credentials.createFromGoogleCredential(credential); @@ -56,15 +57,25 @@ * var client = new Client(address, combined_creds); * }); * - * @module + * @namespace grpc.credentials */ 'use strict'; var grpc = require('./grpc_extension'); +/** + * This cannot be constructed directly. Instead, instances of this class should + * be created using the factory functions in {@link grpc.credentials} + * @constructor grpc.credentials~CallCredentials + */ var CallCredentials = grpc.CallCredentials; +/** + * This cannot be constructed directly. Instead, instances of this class should + * be created using the factory functions in {@link grpc.credentials} + * @constructor grpc.credentials~ChannelCredentials + */ var ChannelCredentials = grpc.ChannelCredentials; var Metadata = require('./metadata.js'); @@ -75,25 +86,49 @@ var constants = require('./constants'); var _ = require('lodash'); +/** + * @external GoogleCredential + * @see https://github.com/google/google-auth-library-nodejs + */ + /** * Create an SSL Credentials object. If using a client-side certificate, both * the second and third arguments must be passed. + * @memberof grpc.credentials + * @alias grpc.credentials.createSsl + * @kind function * @param {Buffer} root_certs The root certificate data * @param {Buffer=} private_key The client certificate private key, if * applicable * @param {Buffer=} cert_chain The client certificate cert chain, if applicable - * @return {ChannelCredentials} The SSL Credentials object + * @return {grpc.credentials.ChannelCredentials} The SSL Credentials object */ exports.createSsl = ChannelCredentials.createSsl; +/** + * @callback grpc.credentials~metadataCallback + * @param {Error} error The error, if getting metadata failed + * @param {grpc.Metadata} metadata The metadata + */ + +/** + * @callback grpc.credentials~generateMetadata + * @param {Object} params Parameters that can modify metadata generation + * @param {string} params.service_url The URL of the service that the call is + * going to + * @param {grpc.credentials~metadataCallback} callback + */ + /** * Create a gRPC credentials object from a metadata generation function. This * function gets the service URL and a callback as parameters. The error * passed to the callback can optionally have a 'code' value attached to it, * which corresponds to a status code that this library uses. - * @param {function(String, function(Error, Metadata))} metadata_generator The - * function that generates metadata - * @return {CallCredentials} The credentials object + * @memberof grpc.credentials + * @alias grpc.credentials.createFromMetadataGenerator + * @param {grpc.credentials~generateMetadata} metadata_generator The function + * that generates metadata + * @return {grpc.credentials.CallCredentials} The credentials object */ exports.createFromMetadataGenerator = function(metadata_generator) { return CallCredentials.createFromPlugin(function(service_url, cb_data, @@ -119,8 +154,11 @@ exports.createFromMetadataGenerator = function(metadata_generator) { /** * Create a gRPC credential from a Google credential object. - * @param {Object} google_credential The Google credential object to use - * @return {CallCredentials} The resulting credentials object + * @memberof grpc.credentials + * @alias grpc.credentials.createFromGoogleCredential + * @param {external:GoogleCredential} google_credential The Google credential + * object to use + * @return {grpc.credentials.CallCredentials} The resulting credentials object */ exports.createFromGoogleCredential = function(google_credential) { return exports.createFromMetadataGenerator(function(auth_context, callback) { @@ -141,6 +179,8 @@ exports.createFromGoogleCredential = function(google_credential) { /** * Combine a ChannelCredentials with any number of CallCredentials into a single * ChannelCredentials object. + * @memberof grpc.credentials + * @alias grpc.credentials.combineChannelCredentials * @param {ChannelCredentials} channel_credential The ChannelCredentials to * start with * @param {...CallCredentials} credentials The CallCredentials to compose @@ -157,6 +197,8 @@ exports.combineChannelCredentials = function(channel_credential) { /** * Combine any number of CallCredentials into a single CallCredentials object + * @memberof grpc.credentials + * @alias grpc.credentials.combineCallCredentials * @param {...CallCredentials} credentials the CallCredentials to compose * @return CallCredentials A credentials object that combines all of the input * credentials @@ -172,6 +214,9 @@ exports.combineCallCredentials = function() { /** * Create an insecure credentials object. This is used to create a channel that * does not use SSL. This cannot be composed with anything. + * @memberof grpc.credentials + * @alias grpc.credentials.createInsecure + * @kind function * @return {ChannelCredentials} The insecure credentials object */ exports.createInsecure = ChannelCredentials.createInsecure; diff --git a/src/node/src/grpc_extension.js b/src/node/src/grpc_extension.js index 63a281ddbcf..864da973144 100644 --- a/src/node/src/grpc_extension.js +++ b/src/node/src/grpc_extension.js @@ -1,5 +1,5 @@ -/* - * +/** + * @license * Copyright 2016, Google Inc. * All rights reserved. * diff --git a/src/node/src/metadata.js b/src/node/src/metadata.js index 92cf23998b3..c757d520f8d 100644 --- a/src/node/src/metadata.js +++ b/src/node/src/metadata.js @@ -1,5 +1,5 @@ -/* - * +/** + * @license * Copyright 2015, Google Inc. * All rights reserved. * @@ -31,15 +31,6 @@ * */ -/** - * Metadata module - * - * This module defines the Metadata class, which represents header and trailer - * metadata for gRPC calls. - * - * @module - */ - 'use strict'; var _ = require('lodash'); @@ -48,8 +39,8 @@ var grpc = require('./grpc_extension'); /** * Class for storing metadata. Keys are normalized to lowercase ASCII. + * @memberof grpc * @constructor - * @alias module:src/metadata.Metadata * @example * var metadata = new metadata_module.Metadata(); * metadata.set('key1', 'value1'); diff --git a/src/node/src/protobuf_js_5_common.js b/src/node/src/protobuf_js_5_common.js index 62cf2f4acaa..dc80d1ba8c9 100644 --- a/src/node/src/protobuf_js_5_common.js +++ b/src/node/src/protobuf_js_5_common.js @@ -1,5 +1,5 @@ -/* - * +/** + * @license * Copyright 2017, Google Inc. * All rights reserved. * @@ -31,6 +31,11 @@ * */ +/** + * @module + * @private + */ + 'use strict'; var _ = require('lodash'); diff --git a/src/node/src/protobuf_js_6_common.js b/src/node/src/protobuf_js_6_common.js index 00f11f27363..91a458aa20e 100644 --- a/src/node/src/protobuf_js_6_common.js +++ b/src/node/src/protobuf_js_6_common.js @@ -1,5 +1,5 @@ -/* - * +/** + * @license * Copyright 2017, Google Inc. * All rights reserved. * @@ -31,6 +31,11 @@ * */ +/** + * @module + * @private + */ + 'use strict'; var _ = require('lodash'); diff --git a/src/node/src/server.js b/src/node/src/server.js index 08417a74c1e..2bc8d5dcee5 100644 --- a/src/node/src/server.js +++ b/src/node/src/server.js @@ -1,5 +1,5 @@ -/* - * +/** + * @license * Copyright 2015, Google Inc. * All rights reserved. * @@ -31,22 +31,6 @@ * */ -/** - * Server module - * - * This module contains all the server code for Node gRPC: both the Server - * class itself and the method handler code for all types of methods. - * - * For example, to create a Server, add a service, and start it: - * - * var server = new server_module.Server(); - * server.addProtoService(protobuf_service_descriptor, service_implementation); - * server.bind('address:port', server_credential); - * server.start(); - * - * @module - */ - 'use strict'; var _ = require('lodash'); @@ -70,9 +54,9 @@ var EventEmitter = require('events').EventEmitter; /** * Handle an error on a call by sending it as a status - * @access private - * @param {grpc.Call} call The call to send the error on - * @param {Object} error The error object + * @private + * @param {grpc.internal~Call} call The call to send the error on + * @param {(Object|Error)} error The error object */ function handleError(call, error) { var statusMetadata = new Metadata(); @@ -104,14 +88,14 @@ function handleError(call, error) { /** * Send a response to a unary or client streaming call. - * @access private + * @private * @param {grpc.Call} call The call to respond on * @param {*} value The value to respond with - * @param {function(*):Buffer=} serialize Serialization function for the + * @param {grpc~serialize} serialize Serialization function for the * response - * @param {Metadata=} metadata Optional trailing metadata to send with status - * @param {number=} flags Flags for modifying how the message is sent. - * Defaults to 0. + * @param {grpc.Metadata=} metadata Optional trailing metadata to send with + * status + * @param {number=} [flags=0] Flags for modifying how the message is sent. */ function sendUnaryResponse(call, value, serialize, metadata, flags) { var end_batch = {}; @@ -146,7 +130,7 @@ function sendUnaryResponse(call, value, serialize, metadata, flags) { /** * Initialize a writable stream. This is used for both the writable and duplex * stream constructors. - * @access private + * @private * @param {Writable} stream The stream to set up * @param {function(*):Buffer=} Serialization function for responses */ @@ -225,9 +209,9 @@ function setUpWritable(stream, serialize) { /** * Initialize a readable stream. This is used for both the readable and duplex * stream constructors. - * @access private + * @private * @param {Readable} stream The stream to initialize - * @param {function(Buffer):*=} deserialize Deserialization function for + * @param {grpc~deserialize} deserialize Deserialization function for * incoming data. */ function setUpReadable(stream, deserialize) { @@ -245,34 +229,88 @@ function setUpReadable(stream, deserialize) { }); } +/** + * Emitted when the call has been cancelled. After this has been emitted, the + * call's `cancelled` property will be set to `true`. + * @event grpc~ServerUnaryCall~cancelled + */ + util.inherits(ServerUnaryCall, EventEmitter); -function ServerUnaryCall(call) { +/** + * An EventEmitter. Used for unary calls. + * @constructor grpc~ServerUnaryCall + * @extends external:EventEmitter + * @param {grpc.internal~Call} call The call object associated with the request + * @param {grpc.Metadata} metadata The request metadata from the client + */ +function ServerUnaryCall(call, metadata) { EventEmitter.call(this); this.call = call; + /** + * Indicates if the call has been cancelled + * @member {boolean} grpc~ServerUnaryCall#cancelled + */ + this.cancelled = false; + /** + * The request metadata from the client + * @member {grpc.Metadata} grpc~ServerUnaryCall#metadata + */ + this.metadata = metadata; + /** + * The request message from the client + * @member {*} grpc~ServerUnaryCall#request + */ + this.request = undefined; } +/** + * Emitted when the call has been cancelled. After this has been emitted, the + * call's `cancelled` property will be set to `true`. + * @event grpc~ServerWritableStream~cancelled + */ + util.inherits(ServerWritableStream, Writable); /** * A stream that the server can write to. Used for calls that are streaming from * the server side. - * @constructor - * @param {grpc.Call} call The call object to send data with - * @param {function(*):Buffer=} serialize Serialization function for writes + * @constructor grpc~ServerWritableStream + * @extends external:Writable + * @borrows grpc~ServerUnaryCall#sendMetadata as + * grpc~ServerWritableStream#sendMetadata + * @borrows grpc~ServerUnaryCall#getPeer as grpc~ServerWritableStream#getPeer + * @param {grpc.internal~Call} call The call object to send data with + * @param {grpc.Metadata} metadata The request metadata from the client + * @param {grpc~serialize} serialize Serialization function for writes */ -function ServerWritableStream(call, serialize) { +function ServerWritableStream(call, metadata, serialize) { Writable.call(this, {objectMode: true}); this.call = call; this.finished = false; setUpWritable(this, serialize); + /** + * Indicates if the call has been cancelled + * @member {boolean} grpc~ServerWritableStream#cancelled + */ + this.cancelled = false; + /** + * The request metadata from the client + * @member {grpc.Metadata} grpc~ServerWritableStream#metadata + */ + this.metadata = metadata; + /** + * The request message from the client + * @member {*} grpc~ServerWritableStream#request + */ + this.request = undefined; } /** * Start writing a chunk of data. This is an implementation of a method required * for implementing stream.Writable. - * @access private + * @private * @param {Buffer} chunk The chunk of data to write * @param {string} encoding Used to pass write flags * @param {function(Error=)} callback Callback to indicate that the write is @@ -312,19 +350,40 @@ function _write(chunk, encoding, callback) { ServerWritableStream.prototype._write = _write; +/** + * Emitted when the call has been cancelled. After this has been emitted, the + * call's `cancelled` property will be set to `true`. + * @event grpc~ServerReadableStream~cancelled + */ + util.inherits(ServerReadableStream, Readable); /** * A stream that the server can read from. Used for calls that are streaming * from the client side. - * @constructor - * @param {grpc.Call} call The call object to read data with - * @param {function(Buffer):*=} deserialize Deserialization function for reads + * @constructor grpc~ServerReadableStream + * @extends external:Readable + * @borrows grpc~ServerUnaryCall#sendMetadata as + * grpc~ServerReadableStream#sendMetadata + * @borrows grpc~ServerUnaryCall#getPeer as grpc~ServerReadableStream#getPeer + * @param {grpc.internal~Call} call The call object to read data with + * @param {grpc.Metadata} metadata The request metadata from the client + * @param {grpc~deserialize} deserialize Deserialization function for reads */ -function ServerReadableStream(call, deserialize) { +function ServerReadableStream(call, metadata, deserialize) { Readable.call(this, {objectMode: true}); this.call = call; setUpReadable(this, deserialize); + /** + * Indicates if the call has been cancelled + * @member {boolean} grpc~ServerReadableStream#cancelled + */ + this.cancelled = false; + /** + * The request metadata from the client + * @member {grpc.Metadata} grpc~ServerReadableStream#metadata + */ + this.metadata = metadata; } /** @@ -381,22 +440,43 @@ function _read(size) { ServerReadableStream.prototype._read = _read; +/** + * Emitted when the call has been cancelled. After this has been emitted, the + * call's `cancelled` property will be set to `true`. + * @event grpc~ServerDuplexStream~cancelled + */ + util.inherits(ServerDuplexStream, Duplex); /** * A stream that the server can read from or write to. Used for calls with * duplex streaming. - * @constructor - * @param {grpc.Call} call Call object to proxy - * @param {function(*):Buffer=} serialize Serialization function for requests - * @param {function(Buffer):*=} deserialize Deserialization function for + * @constructor grpc~ServerDuplexStream + * @extends external:Duplex + * @borrows grpc~ServerUnaryCall#sendMetadata as + * grpc~ServerDuplexStream#sendMetadata + * @borrows grpc~ServerUnaryCall#getPeer as grpc~ServerDuplexStream#getPeer + * @param {grpc.internal~Call} call Call object to proxy + * @param {grpc.Metadata} metadata The request metadata from the client + * @param {grpc~serialize} serialize Serialization function for requests + * @param {grpc~deserialize} deserialize Deserialization function for * responses */ -function ServerDuplexStream(call, serialize, deserialize) { +function ServerDuplexStream(call, metadata, serialize, deserialize) { Duplex.call(this, {objectMode: true}); this.call = call; setUpWritable(this, serialize); setUpReadable(this, deserialize); + /** + * Indicates if the call has been cancelled + * @member {boolean} grpc~ServerReadableStream#cancelled + */ + this.cancelled = false; + /** + * The request metadata from the client + * @member {grpc.Metadata} grpc~ServerReadableStream#metadata + */ + this.metadata = metadata; } ServerDuplexStream.prototype._read = _read; @@ -404,6 +484,7 @@ ServerDuplexStream.prototype._write = _write; /** * Send the initial metadata for a writable stream. + * @alias grpc~ServerUnaryCall#sendMetadata * @param {Metadata} responseMetadata Metadata to send */ function sendMetadata(responseMetadata) { @@ -430,6 +511,7 @@ ServerDuplexStream.prototype.sendMetadata = sendMetadata; /** * Get the endpoint this call/stream is connected to. + * @alias grpc~ServerUnaryCall#getPeer * @return {string} The URI of the endpoint */ function getPeer() { @@ -445,6 +527,7 @@ ServerDuplexStream.prototype.getPeer = getPeer; /** * Wait for the client to close, then emit a cancelled event if the client * cancelled. + * @private */ function waitForCancel() { /* jshint validthis: true */ @@ -467,19 +550,42 @@ ServerReadableStream.prototype.waitForCancel = waitForCancel; ServerWritableStream.prototype.waitForCancel = waitForCancel; ServerDuplexStream.prototype.waitForCancel = waitForCancel; +/** + * Callback function passed to server handlers that handle methods with unary + * responses. + * @callback grpc.Server~sendUnaryData + * @param {grpc~ServiceError} error An error, if the call failed + * @param {*} value The response value. Must be a valid argument to the + * `responseSerialize` method of the method that is being handled + * @param {grpc.Metadata=} trailer Trailing metadata to send, if applicable + * @param {grpc.writeFlags=} flags Flags to modify writing the response + */ + +/** + * User-provided method to handle unary requests on a server + * @callback grpc.Server~handleUnaryCall + * @param {grpc~ServerUnaryCall} call The call object + * @param {grpc.Server~sendUnaryData} callback The callback to call to respond + * to the request + */ + /** * Fully handle a unary call - * @access private - * @param {grpc.Call} call The call to handle + * @private + * @param {grpc.internal~Call} call The call to handle * @param {Object} handler Request handler object for the method that was called - * @param {Metadata} metadata Metadata from the client + * @param {grpc~Server.handleUnaryCall} handler.func The handler function + * @param {grpc~deserialize} handler.deserialize The deserialization function + * for request data + * @param {grpc~serialize} handler.serialize The serialization function for + * response data + * @param {grpc.Metadata} metadata Metadata from the client */ function handleUnary(call, handler, metadata) { - var emitter = new ServerUnaryCall(call); + var emitter = new ServerUnaryCall(call, metadata); emitter.on('error', function(error) { handleError(call, error); }); - emitter.metadata = metadata; emitter.waitForCancel(); var batch = {}; batch[grpc.opType.RECV_MESSAGE] = true; @@ -511,17 +617,28 @@ function handleUnary(call, handler, metadata) { }); } +/** + * User provided method to handle server streaming methods on the server. + * @callback grpc.Server~handleServerStreamingCall + * @param {grpc~ServerWritableStream} call The call object + */ + /** * Fully handle a server streaming call - * @access private - * @param {grpc.Call} call The call to handle + * @private + * @param {grpc.internal~Call} call The call to handle * @param {Object} handler Request handler object for the method that was called - * @param {Metadata} metadata Metadata from the client + * @param {grpc~Server.handleServerStreamingCall} handler.func The handler + * function + * @param {grpc~deserialize} handler.deserialize The deserialization function + * for request data + * @param {grpc~serialize} handler.serialize The serialization function for + * response data + * @param {grpc.Metadata} metadata Metadata from the client */ function handleServerStreaming(call, handler, metadata) { - var stream = new ServerWritableStream(call, handler.serialize); + var stream = new ServerWritableStream(call, metadata, handler.serialize); stream.waitForCancel(); - stream.metadata = metadata; var batch = {}; batch[grpc.opType.RECV_MESSAGE] = true; call.startBatch(batch, function(err, result) { @@ -540,20 +657,33 @@ function handleServerStreaming(call, handler, metadata) { }); } +/** + * User provided method to handle client streaming methods on the server. + * @callback grpc.Server~handleClientStreamingCall + * @param {grpc~ServerReadableStream} call The call object + * @param {grpc.Server~sendUnaryData} callback The callback to call to respond + * to the request + */ + /** * Fully handle a client streaming call * @access private - * @param {grpc.Call} call The call to handle + * @param {grpc.internal~Call} call The call to handle * @param {Object} handler Request handler object for the method that was called - * @param {Metadata} metadata Metadata from the client + * @param {grpc~Server.handleClientStreamingCall} handler.func The handler + * function + * @param {grpc~deserialize} handler.deserialize The deserialization function + * for request data + * @param {grpc~serialize} handler.serialize The serialization function for + * response data + * @param {grpc.Metadata} metadata Metadata from the client */ function handleClientStreaming(call, handler, metadata) { - var stream = new ServerReadableStream(call, handler.deserialize); + var stream = new ServerReadableStream(call, metadata, handler.deserialize); stream.on('error', function(error) { handleError(call, error); }); stream.waitForCancel(); - stream.metadata = metadata; handler.func(stream, function(err, value, trailer, flags) { stream.terminate(); if (err) { @@ -567,18 +697,29 @@ function handleClientStreaming(call, handler, metadata) { }); } +/** + * User provided method to handle bidirectional streaming calls on the server. + * @callback grpc.Server~handleBidiStreamingCall + * @param {grpc~ServerDuplexStream} call The call object + */ + /** * Fully handle a bidirectional streaming call - * @access private - * @param {grpc.Call} call The call to handle + * @private + * @param {grpc.internal~Call} call The call to handle * @param {Object} handler Request handler object for the method that was called + * @param {grpc~Server.handleBidiStreamingCall} handler.func The handler + * function + * @param {grpc~deserialize} handler.deserialize The deserialization function + * for request data + * @param {grpc~serialize} handler.serialize The serialization function for + * response data * @param {Metadata} metadata Metadata from the client */ function handleBidiStreaming(call, handler, metadata) { - var stream = new ServerDuplexStream(call, handler.serialize, + var stream = new ServerDuplexStream(call, metadata, handler.serialize, handler.deserialize); stream.waitForCancel(); - stream.metadata = metadata; handler.func(stream); } @@ -592,96 +733,90 @@ var streamHandlers = { /** * Constructs a server object that stores request handlers and delegates * incoming requests to those handlers + * @memberof grpc * @constructor * @param {Object=} options Options that should be passed to the internal server * implementation + * @example + * var server = new grpc.Server(); + * server.addProtoService(protobuf_service_descriptor, service_implementation); + * server.bind('address:port', server_credential); + * server.start(); */ function Server(options) { this.handlers = {}; - var handlers = this.handlers; var server = new grpc.Server(options); this._server = server; this.started = false; +} + +/** + * Start the server and begin handling requests + */ +Server.prototype.start = function() { + if (this.started) { + throw new Error('Server is already running'); + } + var self = this; + this.started = true; + this._server.start(); /** - * Start the server and begin handling requests - * @this Server + * Handles the SERVER_RPC_NEW event. If there is a handler associated with + * the requested method, use that handler to respond to the request. Then + * wait for the next request + * @param {grpc.internal~Event} event The event to handle with tag + * SERVER_RPC_NEW */ - this.start = function() { - if (this.started) { - throw new Error('Server is already running'); + function handleNewCall(err, event) { + if (err) { + return; } - this.started = true; - server.start(); - /** - * Handles the SERVER_RPC_NEW event. If there is a handler associated with - * the requested method, use that handler to respond to the request. Then - * wait for the next request - * @param {grpc.Event} event The event to handle with tag SERVER_RPC_NEW - */ - function handleNewCall(err, event) { - if (err) { - return; - } - var details = event.new_call; - var call = details.call; - var method = details.method; - var metadata = Metadata._fromCoreRepresentation(details.metadata); - if (method === null) { - return; - } - server.requestCall(handleNewCall); - var handler; - if (handlers.hasOwnProperty(method)) { - handler = handlers[method]; - } else { - var batch = {}; - batch[grpc.opType.SEND_INITIAL_METADATA] = - (new Metadata())._getCoreRepresentation(); - batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - code: constants.status.UNIMPLEMENTED, - details: '', - metadata: {} - }; - batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; - call.startBatch(batch, function() {}); - return; - } - streamHandlers[handler.type](call, handler, metadata); + var details = event.new_call; + var call = details.call; + var method = details.method; + var metadata = Metadata._fromCoreRepresentation(details.metadata); + if (method === null) { + return; } - server.requestCall(handleNewCall); - }; - - /** - * Gracefully shuts down the server. The server will stop receiving new calls, - * and any pending calls will complete. The callback will be called when all - * pending calls have completed and the server is fully shut down. This method - * is idempotent with itself and forceShutdown. - * @param {function()} callback The shutdown complete callback - */ - this.tryShutdown = function(callback) { - server.tryShutdown(callback); - }; + self._server.requestCall(handleNewCall); + var handler; + if (self.handlers.hasOwnProperty(method)) { + handler = self.handlers[method]; + } else { + var batch = {}; + batch[grpc.opType.SEND_INITIAL_METADATA] = + (new Metadata())._getCoreRepresentation(); + batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { + code: constants.status.UNIMPLEMENTED, + details: '', + metadata: {} + }; + batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; + call.startBatch(batch, function() {}); + return; + } + streamHandlers[handler.type](call, handler, metadata); + } + this._server.requestCall(handleNewCall); +}; - /** - * Forcibly shuts down the server. The server will stop receiving new calls - * and cancel all pending calls. When it returns, the server has shut down. - * This method is idempotent with itself and tryShutdown, and it will trigger - * any outstanding tryShutdown callbacks. - */ - this.forceShutdown = function() { - server.forceShutdown(); - }; -} +/** + * Unified type for application handlers for all types of calls + * @typedef {(grpc.Server~handleUnaryCall + * |grpc.Server~handleClientStreamingCall + * |grpc.Server~handleServerStreamingCall + * |grpc.Server~handleBidiStreamingCall)} grpc.Server~handleCall + */ /** * Registers a handler to handle the named method. Fails if there already is * a handler for the given method. Returns true on success * @param {string} name The name of the method that the provided function should * handle/respond to. - * @param {function} handler Function that takes a stream of request values and - * returns a stream of response values - * @param {function(*):Buffer} serialize Serialization function for responses - * @param {function(Buffer):*} deserialize Deserialization function for requests + * @param {grpc.Server~handleCall} handler Function that takes a stream of + * request values and returns a stream of response values + * @param {grpc~serialize} serialize Serialization function for responses + * @param {grpc~deserialize} deserialize Deserialization function for requests * @param {string} type The streaming type of method that this handles * @return {boolean} True if the handler was set. False if a handler was already * set for that name. @@ -700,6 +835,27 @@ Server.prototype.register = function(name, handler, serialize, deserialize, return true; }; +/** + * Gracefully shuts down the server. The server will stop receiving new calls, + * and any pending calls will complete. The callback will be called when all + * pending calls have completed and the server is fully shut down. This method + * is idempotent with itself and forceShutdown. + * @param {function()} callback The shutdown complete callback + */ +Server.prototype.tryShutdown = function(callback) { + this._server.tryShutdown(callback); +}; + +/** + * Forcibly shuts down the server. The server will stop receiving new calls + * and cancel all pending calls. When it returns, the server has shut down. + * This method is idempotent with itself and tryShutdown, and it will trigger + * any outstanding tryShutdown callbacks. + */ +Server.prototype.forceShutdown = function() { + this._server.forceShutdown(); +}; + var unimplementedStatusResponse = { code: constants.status.UNIMPLEMENTED, details: 'The server does not implement this method' @@ -721,13 +877,10 @@ var defaultHandler = { }; /** - * Add a service to the server, with a corresponding implementation. If you are - * generating this from a proto file, you should instead use - * addProtoService. - * @param {Object} service The service descriptor, as - * {@link module:src/common.getProtobufServiceAttrs} returns - * @param {Object} implementation Map of method names to - * method implementation for the provided service. + * Add a service to the server, with a corresponding implementation. + * @param {grpc~ServiceDefinition} service The service descriptor + * @param {Object} implementation Map of method + * names to method implementation for the provided service. */ Server.prototype.addService = function(service, implementation) { if (!_.isObject(service) || !_.isObject(implementation)) { @@ -783,10 +936,10 @@ Server.prototype.addService = function(service, implementation) { /** * Add a proto service to the server, with a corresponding implementation - * @deprecated Use grpc.load and Server#addService instead + * @deprecated Use {@link grpc.Server#addService} instead * @param {Protobuf.Reflect.Service} service The proto service descriptor - * @param {Object} implementation Map of method names to - * method implementation for the provided service. + * @param {Object} implementation Map of method + * names to method implementation for the provided service. */ Server.prototype.addProtoService = function(service, implementation) { var options; @@ -811,10 +964,11 @@ Server.prototype.addProtoService = function(service, implementation) { }; /** - * Binds the server to the given port, with SSL enabled if creds is given + * Binds the server to the given port, with SSL disabled if creds is an + * insecure credentials object * @param {string} port The port that the server should bind on, in the format * "address:port" - * @param {ServerCredentials=} creds Server credential object to be used for + * @param {grpc.ServerCredentials} creds Server credential object to be used for * SSL. Pass an insecure credentials object for an insecure port. */ Server.prototype.bind = function(port, creds) { @@ -824,7 +978,4 @@ Server.prototype.bind = function(port, creds) { return this._server.addHttp2Port(port, creds); }; -/** - * @see module:src/server~Server - */ exports.Server = Server; diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js index 783028fa99f..9bb7d2fca80 100644 --- a/src/node/test/surface_test.js +++ b/src/node/test/surface_test.js @@ -1330,14 +1330,14 @@ describe('Cancelling surface client', function() { }); it('Should correctly cancel a unary call', function(done) { var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) { - assert.strictEqual(err.code, surface_client.status.CANCELLED); + assert.strictEqual(err.code, grpc.status.CANCELLED); done(); }); call.cancel(); }); it('Should correctly cancel a client stream call', function(done) { var call = client.sum(function(err, resp) { - assert.strictEqual(err.code, surface_client.status.CANCELLED); + assert.strictEqual(err.code, grpc.status.CANCELLED); done(); }); call.cancel(); @@ -1346,7 +1346,7 @@ describe('Cancelling surface client', function() { var call = client.fib({'limit': 5}); call.on('data', function() {}); call.on('error', function(error) { - assert.strictEqual(error.code, surface_client.status.CANCELLED); + assert.strictEqual(error.code, grpc.status.CANCELLED); done(); }); call.cancel(); @@ -1355,7 +1355,7 @@ describe('Cancelling surface client', function() { var call = client.divMany(); call.on('data', function() {}); call.on('error', function(error) { - assert.strictEqual(error.code, surface_client.status.CANCELLED); + assert.strictEqual(error.code, grpc.status.CANCELLED); done(); }); call.cancel(); From 850fe7fdba9147f8d46a21ca173ff491c818727c Mon Sep 17 00:00:00 2001 From: jiangtaoli2016 Date: Tue, 23 May 2017 11:21:42 -0700 Subject: [PATCH 39/65] Revise handshaker to make callback once a time. --- .../security/transport/security_handshaker.c | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/core/lib/security/transport/security_handshaker.c b/src/core/lib/security/transport/security_handshaker.c index 9144483b0c1..3bc113e20ff 100644 --- a/src/core/lib/security/transport/security_handshaker.c +++ b/src/core/lib/security/transport/security_handshaker.c @@ -227,24 +227,26 @@ static grpc_error *on_handshake_next_done_locked( return grpc_set_tsi_error_result( GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake failed"), result); } - // Send data to peer. + // Update handshaker result. + if (handshaker_result != NULL) { + GPR_ASSERT(h->handshaker_result == NULL); + h->handshaker_result = handshaker_result; + } if (bytes_to_send_size > 0) { + // Send data to peer, if needed. grpc_slice to_send = grpc_slice_from_copied_buffer( (const char *)bytes_to_send, bytes_to_send_size); grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &h->outgoing); grpc_slice_buffer_add(&h->outgoing, to_send); grpc_endpoint_write(exec_ctx, h->args->endpoint, &h->outgoing, &h->on_handshake_data_sent_to_peer); - } - // If handshake has completed, check peer and so on. Otherwise, need to read - // more data from the peer. - if (handshaker_result != NULL) { - GPR_ASSERT(h->handshaker_result == NULL); - h->handshaker_result = handshaker_result; - error = check_peer_locked(exec_ctx, h); - } else { + } else if (handshaker_result == NULL) { + // There is nothing to send, but need to read from peer. grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, &h->on_handshake_data_received_from_peer); + } else { + // Handshake has finished, check peer and so on. + error = check_peer_locked(exec_ctx, h); } return error; } @@ -346,6 +348,19 @@ static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *arg, security_handshaker_unref(exec_ctx, h); return; } + // We may be done. + if (h->handshaker_result == NULL) { + grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, + &h->on_handshake_data_received_from_peer); + } else { + error = check_peer_locked(exec_ctx, h); + if (error != GRPC_ERROR_NONE) { + security_handshake_failed_locked(exec_ctx, h, error); + gpr_mu_unlock(&h->mu); + security_handshaker_unref(exec_ctx, h); + return; + } + } gpr_mu_unlock(&h->mu); } From f8be2d65cc942e94c81d76e1fba5bb3aee538189 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 23 May 2017 21:08:34 +0200 Subject: [PATCH 40/65] add privateassets none to C# nugets depending on Grpc.Core --- src/csharp/Grpc.Auth/Grpc.Auth.csproj | 4 +++- src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj | 6 ++++-- src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj | 4 +++- src/csharp/Grpc.Reflection/Grpc.Reflection.csproj | 4 +++- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj index 6ac25aa1f02..c082e30c46c 100755 --- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj +++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj @@ -23,7 +23,9 @@ - + + None + diff --git a/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj b/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj index f4dd5105fc7..1efda925bd7 100755 --- a/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj +++ b/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj @@ -1,4 +1,4 @@ - + @@ -23,7 +23,9 @@ - + + None + diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj index eac6e1fc95f..80c7dfe48ca 100755 --- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj +++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj @@ -22,7 +22,9 @@ - + + None + diff --git a/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj b/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj index 70bfcc89c5c..eafa0f4e108 100755 --- a/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj +++ b/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj @@ -22,7 +22,9 @@ - + + None + From be8522974d9a8237468193d680b20cb503793a57 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 23 May 2017 22:17:22 +0200 Subject: [PATCH 41/65] include symbols and source in nugets --- src/csharp/Grpc.Auth/Grpc.Auth.csproj | 2 ++ src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj | 2 ++ src/csharp/Grpc.Core/Grpc.Core.csproj | 4 +++- src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj | 2 ++ src/csharp/Grpc.Reflection/Grpc.Reflection.csproj | 2 ++ 5 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj index c082e30c46c..188ddb95b99 100755 --- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj +++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj @@ -16,6 +16,8 @@ https://github.com/grpc/grpc https://github.com/grpc/grpc/blob/master/LICENSE 1.6.0 + true + true diff --git a/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj b/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj index 1efda925bd7..45ec8743222 100755 --- a/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj +++ b/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj @@ -16,6 +16,8 @@ https://github.com/grpc/grpc https://github.com/grpc/grpc/blob/master/LICENSE 1.6.0 + true + true diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index 7e0f3f053d0..bcf0282b92e 100755 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -1,4 +1,4 @@ - + @@ -15,6 +15,8 @@ https://github.com/grpc/grpc https://github.com/grpc/grpc/blob/master/LICENSE 1.6.0 + true + true diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj index 80c7dfe48ca..c3791a4e6b2 100755 --- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj +++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj @@ -15,6 +15,8 @@ https://github.com/grpc/grpc https://github.com/grpc/grpc/blob/master/LICENSE 1.6.0 + true + true diff --git a/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj b/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj index eafa0f4e108..3a075552483 100755 --- a/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj +++ b/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj @@ -15,6 +15,8 @@ https://github.com/grpc/grpc https://github.com/grpc/grpc/blob/master/LICENSE 1.6.0 + true + true From 905f41869bbf143ccf38f3aa4ed6980251ad7de3 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 23 May 2017 22:34:14 +0200 Subject: [PATCH 42/65] remove now unnecessary extra args --- src/csharp/build_packages_dotnetcli.bat | 10 +++++----- src/csharp/build_packages_dotnetcli.sh | 10 +++++----- .../src/csharp/build_packages_dotnetcli.bat.template | 10 +++++----- .../src/csharp/build_packages_dotnetcli.sh.template | 10 +++++----- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat index 3aec7aacbeb..eb3ba2a952e 100755 --- a/src/csharp/build_packages_dotnetcli.bat +++ b/src/csharp/build_packages_dotnetcli.bat @@ -60,11 +60,11 @@ xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=macos\artifacts\* pr @rem To be able to build, we also need to put grpc_csharp_ext to its normal location xcopy /Y /I nativelibs\windows_x64\grpc_csharp_ext.dll ..\..\cmake\build\x64\Release\ -%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Core --output ..\..\..\artifacts || goto :error -%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Core.Testing --output ..\..\..\artifacts || goto :error -%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Auth --output ..\..\..\artifacts || goto :error -%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.HealthCheck --output ..\..\..\artifacts || goto :error -%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Reflection --output ..\..\..\artifacts || goto :error +%DOTNET% pack --configuration Release Grpc.Core --output ..\..\..\artifacts || goto :error +%DOTNET% pack --configuration Release Grpc.Core.Testing --output ..\..\..\artifacts || goto :error +%DOTNET% pack --configuration Release Grpc.Auth --output ..\..\..\artifacts || goto :error +%DOTNET% pack --configuration Release Grpc.HealthCheck --output ..\..\..\artifacts || goto :error +%DOTNET% pack --configuration Release Grpc.Reflection --output ..\..\..\artifacts || goto :error %NUGET% pack Grpc.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts || goto :error %NUGET% pack Grpc.Tools.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh index da585cb663d..76ae99a2fb1 100755 --- a/src/csharp/build_packages_dotnetcli.sh +++ b/src/csharp/build_packages_dotnetcli.sh @@ -64,11 +64,11 @@ dotnet restore Grpc.sln mkdir -p ../../libs/opt cp nativelibs/linux_x64/libgrpc_csharp_ext.so ../../libs/opt -dotnet pack --configuration Release --include-symbols --include-source Grpc.Core --output ../../../artifacts -dotnet pack --configuration Release --include-symbols --include-source Grpc.Core.Testing --output ../../../artifacts -dotnet pack --configuration Release --include-symbols --include-source Grpc.Auth --output ../../../artifacts -dotnet pack --configuration Release --include-symbols --include-source Grpc.HealthCheck --output ../../../artifacts -dotnet pack --configuration Release --include-symbols --include-source Grpc.Reflection --output ../../../artifacts +dotnet pack --configuration Release Grpc.Core --output ../../../artifacts +dotnet pack --configuration Release Grpc.Core.Testing --output ../../../artifacts +dotnet pack --configuration Release Grpc.Auth --output ../../../artifacts +dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts +dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts nuget pack Grpc.nuspec -Version "1.3.5" -OutputDirectory ../../artifacts nuget pack Grpc.Tools.nuspec -Version "1.3.5" -OutputDirectory ../../artifacts diff --git a/templates/src/csharp/build_packages_dotnetcli.bat.template b/templates/src/csharp/build_packages_dotnetcli.bat.template index 5f6ffb97544..91808e0d266 100755 --- a/templates/src/csharp/build_packages_dotnetcli.bat.template +++ b/templates/src/csharp/build_packages_dotnetcli.bat.template @@ -62,11 +62,11 @@ @rem To be able to build, we also need to put grpc_csharp_ext to its normal location xcopy /Y /I nativelibs\windows_x64\grpc_csharp_ext.dll ..\..\cmake\build\x64\Release${"\\"} - %%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Core --output ..\..\..\artifacts || goto :error - %%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Core.Testing --output ..\..\..\artifacts || goto :error - %%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Auth --output ..\..\..\artifacts || goto :error - %%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.HealthCheck --output ..\..\..\artifacts || goto :error - %%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Reflection --output ..\..\..\artifacts || goto :error + %%DOTNET% pack --configuration Release Grpc.Core --output ..\..\..\artifacts || goto :error + %%DOTNET% pack --configuration Release Grpc.Core.Testing --output ..\..\..\artifacts || goto :error + %%DOTNET% pack --configuration Release Grpc.Auth --output ..\..\..\artifacts || goto :error + %%DOTNET% pack --configuration Release Grpc.HealthCheck --output ..\..\..\artifacts || goto :error + %%DOTNET% pack --configuration Release Grpc.Reflection --output ..\..\..\artifacts || goto :error %%NUGET% pack Grpc.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts || goto :error %%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts diff --git a/templates/src/csharp/build_packages_dotnetcli.sh.template b/templates/src/csharp/build_packages_dotnetcli.sh.template index d37f4eb4f4e..374b236f93c 100755 --- a/templates/src/csharp/build_packages_dotnetcli.sh.template +++ b/templates/src/csharp/build_packages_dotnetcli.sh.template @@ -66,11 +66,11 @@ mkdir -p ../../libs/opt cp nativelibs/linux_x64/libgrpc_csharp_ext.so ../../libs/opt - dotnet pack --configuration Release --include-symbols --include-source Grpc.Core --output ../../../artifacts - dotnet pack --configuration Release --include-symbols --include-source Grpc.Core.Testing --output ../../../artifacts - dotnet pack --configuration Release --include-symbols --include-source Grpc.Auth --output ../../../artifacts - dotnet pack --configuration Release --include-symbols --include-source Grpc.HealthCheck --output ../../../artifacts - dotnet pack --configuration Release --include-symbols --include-source Grpc.Reflection --output ../../../artifacts + dotnet pack --configuration Release Grpc.Core --output ../../../artifacts + dotnet pack --configuration Release Grpc.Core.Testing --output ../../../artifacts + dotnet pack --configuration Release Grpc.Auth --output ../../../artifacts + dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts + dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts nuget pack Grpc.nuspec -Version "${settings.csharp_version}" -OutputDirectory ../../artifacts nuget pack Grpc.Tools.nuspec -Version "${settings.csharp_version}" -OutputDirectory ../../artifacts From bbfdbb19c002d23e2fd3d94d6a089cff5b03a390 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 23 May 2017 22:48:45 +0200 Subject: [PATCH 43/65] bump version to 1.3.6 --- BUILD | 2 +- CMakeLists.txt | 2 +- Makefile | 4 ++-- build.yaml | 2 +- gRPC-Core.podspec | 2 +- gRPC-ProtoRPC.podspec | 2 +- gRPC-RxLibrary.podspec | 2 +- gRPC.podspec | 2 +- package.json | 2 +- package.xml | 4 ++-- src/cpp/common/version_cc.cc | 2 +- src/csharp/Grpc.Core/Version.csproj.include | 2 +- src/csharp/Grpc.Core/VersionInfo.cs | 4 ++-- src/csharp/build_packages_dotnetcli.bat | 2 +- src/csharp/build_packages_dotnetcli.sh | 4 ++-- src/node/health_check/package.json | 4 ++-- src/node/tools/package.json | 2 +- src/objective-c/!ProtoCompiler-gRPCPlugin.podspec | 2 +- src/objective-c/GRPCClient/private/version.h | 2 +- src/php/composer.json | 2 +- src/python/grpcio/grpc_version.py | 2 +- src/python/grpcio_health_checking/grpc_version.py | 2 +- src/python/grpcio_reflection/grpc_version.py | 2 +- src/python/grpcio_tests/grpc_version.py | 2 +- src/ruby/lib/grpc/version.rb | 2 +- src/ruby/tools/version.rb | 2 +- tools/distrib/python/grpcio_tools/grpc_version.py | 2 +- tools/doxygen/Doxyfile.c++ | 2 +- tools/doxygen/Doxyfile.c++.internal | 2 +- 29 files changed, 34 insertions(+), 34 deletions(-) diff --git a/BUILD b/BUILD index 166e6ba7518..cb8c08a6368 100644 --- a/BUILD +++ b/BUILD @@ -42,7 +42,7 @@ g_stands_for = "gentle" core_version = "3.0.0" -version = "1.3.5" +version = "1.3.6" grpc_cc_library( name = "gpr", diff --git a/CMakeLists.txt b/CMakeLists.txt index cff8f856e02..86416cc11e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ cmake_minimum_required(VERSION 2.8) set(PACKAGE_NAME "grpc") -set(PACKAGE_VERSION "1.3.5") +set(PACKAGE_VERSION "1.3.6") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/") diff --git a/Makefile b/Makefile index 77206ba92bf..b5bb74113b1 100644 --- a/Makefile +++ b/Makefile @@ -420,8 +420,8 @@ Q = @ endif CORE_VERSION = 3.0.0 -CPP_VERSION = 1.3.5 -CSHARP_VERSION = 1.3.5 +CPP_VERSION = 1.3.6 +CSHARP_VERSION = 1.3.6 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES)) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) diff --git a/build.yaml b/build.yaml index 3af590609a1..4c01cf245d2 100644 --- a/build.yaml +++ b/build.yaml @@ -14,7 +14,7 @@ settings: '#10': See the expand_version.py for all the quirks here core_version: 3.0.0 g_stands_for: gentle - version: 1.3.5 + version: 1.3.6 filegroups: - name: census public_headers: diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 5d1ba611830..515a8dad63d 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -37,7 +37,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-Core' - version = '1.3.5' + version = '1.3.6' s.version = version s.summary = 'Core cross-platform gRPC library, written in C' s.homepage = 'http://www.grpc.io' diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec index e60ea7c08ee..d4dd0b10445 100644 --- a/gRPC-ProtoRPC.podspec +++ b/gRPC-ProtoRPC.podspec @@ -36,7 +36,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-ProtoRPC' - version = '1.3.5' + version = '1.3.6' s.version = version s.summary = 'RPC library for Protocol Buffers, based on gRPC' s.homepage = 'http://www.grpc.io' diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec index d82130ad4ae..6ed1849f028 100644 --- a/gRPC-RxLibrary.podspec +++ b/gRPC-RxLibrary.podspec @@ -36,7 +36,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-RxLibrary' - version = '1.3.5' + version = '1.3.6' s.version = version s.summary = 'Reactive Extensions library for iOS/OSX.' s.homepage = 'http://www.grpc.io' diff --git a/gRPC.podspec b/gRPC.podspec index 5aa8a86a058..808bbf92e87 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -35,7 +35,7 @@ Pod::Spec.new do |s| s.name = 'gRPC' - version = '1.3.5' + version = '1.3.6' s.version = version s.summary = 'gRPC client library for iOS/OSX' s.homepage = 'http://www.grpc.io' diff --git a/package.json b/package.json index c83f51c2212..b8ac31aa552 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.3.5", + "version": "1.3.6", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "http://www.grpc.io/", diff --git a/package.xml b/package.xml index 1c91f1c0c23..66e313b1a41 100644 --- a/package.xml +++ b/package.xml @@ -13,8 +13,8 @@ 2017-05-05 - 1.3.5 - 1.3.5 + 1.3.6 + 1.3.6 beta diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc index 0a1b72527b6..71018423469 100644 --- a/src/cpp/common/version_cc.cc +++ b/src/cpp/common/version_cc.cc @@ -37,5 +37,5 @@ #include namespace grpc { -grpc::string Version() { return "1.3.5"; } +grpc::string Version() { return "1.3.6"; } } diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include index 63536ecc6b4..22d7b92ae31 100755 --- a/src/csharp/Grpc.Core/Version.csproj.include +++ b/src/csharp/Grpc.Core/Version.csproj.include @@ -1,7 +1,7 @@ - 1.3.5 + 1.3.6 3.2.0 diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs index fed38292f04..fb6a4b41972 100644 --- a/src/csharp/Grpc.Core/VersionInfo.cs +++ b/src/csharp/Grpc.Core/VersionInfo.cs @@ -48,11 +48,11 @@ namespace Grpc.Core /// /// Current AssemblyFileVersion of gRPC C# assemblies /// - public const string CurrentAssemblyFileVersion = "1.3.5.0"; + public const string CurrentAssemblyFileVersion = "1.3.6.0"; /// /// Current version of gRPC C# /// - public const string CurrentVersion = "1.3.5"; + public const string CurrentVersion = "1.3.6"; } } diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat index 3aec7aacbeb..1f93ff694f3 100755 --- a/src/csharp/build_packages_dotnetcli.bat +++ b/src/csharp/build_packages_dotnetcli.bat @@ -28,7 +28,7 @@ @rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @rem Current package versions -set VERSION=1.3.5 +set VERSION=1.3.6 @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh index da585cb663d..9f467fcbe61 100755 --- a/src/csharp/build_packages_dotnetcli.sh +++ b/src/csharp/build_packages_dotnetcli.sh @@ -70,7 +70,7 @@ dotnet pack --configuration Release --include-symbols --include-source Grpc.Auth dotnet pack --configuration Release --include-symbols --include-source Grpc.HealthCheck --output ../../../artifacts dotnet pack --configuration Release --include-symbols --include-source Grpc.Reflection --output ../../../artifacts -nuget pack Grpc.nuspec -Version "1.3.5" -OutputDirectory ../../artifacts -nuget pack Grpc.Tools.nuspec -Version "1.3.5" -OutputDirectory ../../artifacts +nuget pack Grpc.nuspec -Version "1.3.6" -OutputDirectory ../../artifacts +nuget pack Grpc.Tools.nuspec -Version "1.3.6" -OutputDirectory ../../artifacts (cd ../../artifacts && zip csharp_nugets_dotnetcli.zip *.nupkg) diff --git a/src/node/health_check/package.json b/src/node/health_check/package.json index 2fdcb12777c..f5700206fde 100644 --- a/src/node/health_check/package.json +++ b/src/node/health_check/package.json @@ -1,6 +1,6 @@ { "name": "grpc-health-check", - "version": "1.3.5", + "version": "1.3.6", "author": "Google Inc.", "description": "Health check service for use with gRPC", "repository": { @@ -15,7 +15,7 @@ } ], "dependencies": { - "grpc": "^1.3.5", + "grpc": "^1.3.6", "lodash": "^3.9.3", "google-protobuf": "^3.0.0" }, diff --git a/src/node/tools/package.json b/src/node/tools/package.json index cabd4030dc9..59397a5c24f 100644 --- a/src/node/tools/package.json +++ b/src/node/tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.3.5", + "version": "1.3.6", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "http://www.grpc.io/", diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec index 23f91867c41..0d14df62df7 100644 --- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec +++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec @@ -42,7 +42,7 @@ Pod::Spec.new do |s| # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed # before them. s.name = '!ProtoCompiler-gRPCPlugin' - v = '1.3.5' + v = '1.3.6' s.version = v s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.' s.description = <<-DESC diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h index 43ab9bd0641..578d31c9ed6 100644 --- a/src/objective-c/GRPCClient/private/version.h +++ b/src/objective-c/GRPCClient/private/version.h @@ -38,4 +38,4 @@ // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.3.5" +#define GRPC_OBJC_VERSION_STRING @"1.3.6" diff --git a/src/php/composer.json b/src/php/composer.json index 08f2b9afabd..45be98eba3a 100644 --- a/src/php/composer.json +++ b/src/php/composer.json @@ -2,7 +2,7 @@ "name": "grpc/grpc-dev", "description": "gRPC library for PHP - for Developement use only", "license": "BSD-3-Clause", - "version": "1.3.5", + "version": "1.3.6", "require": { "php": ">=5.5.0", "google/protobuf": "^v3.1.0" diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py index 52b1397468c..1997ce98fad 100644 --- a/src/python/grpcio/grpc_version.py +++ b/src/python/grpcio/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!! -VERSION='1.3.5' +VERSION='1.3.6' diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py index 143c1ede368..4e4ddd5e2d8 100644 --- a/src/python/grpcio_health_checking/grpc_version.py +++ b/src/python/grpcio_health_checking/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!! -VERSION='1.3.5' +VERSION='1.3.6' diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py index 66f1ff968ae..de61ce0ab27 100644 --- a/src/python/grpcio_reflection/grpc_version.py +++ b/src/python/grpcio_reflection/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!! -VERSION='1.3.5' +VERSION='1.3.6' diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py index a6da39c8ebf..b07ec7946da 100644 --- a/src/python/grpcio_tests/grpc_version.py +++ b/src/python/grpcio_tests/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!! -VERSION='1.3.5' +VERSION='1.3.6' diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb index 27595318d33..3973654d5fb 100644 --- a/src/ruby/lib/grpc/version.rb +++ b/src/ruby/lib/grpc/version.rb @@ -29,5 +29,5 @@ # GRPC contains the General RPC module. module GRPC - VERSION = '1.3.5' + VERSION = '1.3.6' end diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb index f93c1f14af2..1650938cda0 100644 --- a/src/ruby/tools/version.rb +++ b/src/ruby/tools/version.rb @@ -29,6 +29,6 @@ module GRPC module Tools - VERSION = '1.3.5' + VERSION = '1.3.6' end end diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py index 71786813299..3e94e82a6dd 100644 --- a/tools/distrib/python/grpcio_tools/grpc_version.py +++ b/tools/distrib/python/grpcio_tools/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!! -VERSION='1.3.5' +VERSION='1.3.6' diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 55980eadac5..c8a2a9f01c4 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.3.5 +PROJECT_NUMBER = 1.3.6 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 7580617bf12..d09757c2b1a 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.3.5 +PROJECT_NUMBER = 1.3.6 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From 4a1e432ca5fa6acfc0f648163f6f70dc52e33b78 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 23 May 2017 22:49:18 +0000 Subject: [PATCH 44/65] Refcounting fix --- src/core/lib/http/httpcli.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/lib/http/httpcli.c b/src/core/lib/http/httpcli.c index 0ac2c2ad52a..c3421e1b55c 100644 --- a/src/core/lib/http/httpcli.c +++ b/src/core/lib/http/httpcli.c @@ -120,6 +120,7 @@ static void finish(grpc_exec_ctx *exec_ctx, internal_request *req, grpc_slice_buffer_destroy_internal(exec_ctx, &req->incoming); grpc_slice_buffer_destroy_internal(exec_ctx, &req->outgoing); GRPC_ERROR_UNREF(req->overall_error); + GRPC_ERROR_UNREF(error); grpc_resource_quota_unref_internal(exec_ctx, req->resource_quota); gpr_free(req); } From c1947ef5700f4431b77728ab12be8186c1e58eb5 Mon Sep 17 00:00:00 2001 From: Vizerai Date: Tue, 23 May 2017 16:13:25 -0700 Subject: [PATCH 45/65] update --- BUILD | 1 + build.yaml | 1 + config.w32 | 1 + gRPC-Core.podspec | 2 + grpc.gemspec | 1 + package.xml | 1 + src/core/ext/census/intrusive_hash_map.c | 5 +- src/core/ext/census/intrusive_hash_map.h | 73 +++++++------------ .../ext/census/intrusive_hash_map_internal.h | 46 ++++++++++++ test/core/census/intrusive_hash_map_test.c | 18 ++++- tools/doxygen/Doxyfile.core.internal | 1 + .../generated/sources_and_headers.json | 2 + vsprojects/vcxproj/grpc/grpc.vcxproj | 1 + vsprojects/vcxproj/grpc/grpc.vcxproj.filters | 3 + .../grpc_unsecure/grpc_unsecure.vcxproj | 1 + .../grpc_unsecure.vcxproj.filters | 3 + 16 files changed, 107 insertions(+), 53 deletions(-) create mode 100644 src/core/ext/census/intrusive_hash_map_internal.h diff --git a/BUILD b/BUILD index 4429e9a81fc..bdea522ad15 100644 --- a/BUILD +++ b/BUILD @@ -299,6 +299,7 @@ grpc_cc_library( "src/core/ext/census/gen/trace_context.pb.h", "src/core/ext/census/grpc_filter.h", "src/core/ext/census/intrusive_hash_map.h", + "src/core/ext/census/intrusive_hash_map_internal.h", "src/core/ext/census/mlog.h", "src/core/ext/census/resource.h", "src/core/ext/census/rpc_metric_id.h", diff --git a/build.yaml b/build.yaml index c0886ae4b46..d2ea16c8c20 100644 --- a/build.yaml +++ b/build.yaml @@ -28,6 +28,7 @@ filegroups: - src/core/ext/census/gen/trace_context.pb.h - src/core/ext/census/grpc_filter.h - src/core/ext/census/intrusive_hash_map.h + - src/core/ext/census/intrusive_hash_map_internal.h - src/core/ext/census/mlog.h - src/core/ext/census/resource.h - src/core/ext/census/rpc_metric_id.h diff --git a/config.w32 b/config.w32 index 0d82f9d757f..7c407e848a4 100644 --- a/config.w32 +++ b/config.w32 @@ -299,6 +299,7 @@ if (PHP_GRPC != "no") { "src\\core\\ext\\census\\grpc_filter.c " + "src\\core\\ext\\census\\grpc_plugin.c " + "src\\core\\ext\\census\\initialize.c " + + "src\\core\\ext\\census\\intrusive_hash_map.c " + "src\\core\\ext\\census\\mlog.c " + "src\\core\\ext\\census\\operation.c " + "src\\core\\ext\\census\\placeholders.c " + diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 0762dfed2a0..d9de2d78a05 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -464,6 +464,7 @@ Pod::Spec.new do |s| 'src/core/ext/census/gen/trace_context.pb.h', 'src/core/ext/census/grpc_filter.h', 'src/core/ext/census/intrusive_hash_map.h', + 'src/core/ext/census/intrusive_hash_map_internal.h', 'src/core/ext/census/mlog.h', 'src/core/ext/census/resource.h', 'src/core/ext/census/rpc_metric_id.h', @@ -949,6 +950,7 @@ Pod::Spec.new do |s| 'src/core/ext/census/gen/trace_context.pb.h', 'src/core/ext/census/grpc_filter.h', 'src/core/ext/census/intrusive_hash_map.h', + 'src/core/ext/census/intrusive_hash_map_internal.h', 'src/core/ext/census/mlog.h', 'src/core/ext/census/resource.h', 'src/core/ext/census/rpc_metric_id.h', diff --git a/grpc.gemspec b/grpc.gemspec index 13bcd7dc406..b334efb0b5d 100755 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -380,6 +380,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/census/gen/trace_context.pb.h ) s.files += %w( src/core/ext/census/grpc_filter.h ) s.files += %w( src/core/ext/census/intrusive_hash_map.h ) + s.files += %w( src/core/ext/census/intrusive_hash_map_internal.h ) s.files += %w( src/core/ext/census/mlog.h ) s.files += %w( src/core/ext/census/resource.h ) s.files += %w( src/core/ext/census/rpc_metric_id.h ) diff --git a/package.xml b/package.xml index ece21f9468e..9179ef238c9 100644 --- a/package.xml +++ b/package.xml @@ -394,6 +394,7 @@ + diff --git a/src/core/ext/census/intrusive_hash_map.c b/src/core/ext/census/intrusive_hash_map.c index 4a747c91374..e64e8086ca2 100644 --- a/src/core/ext/census/intrusive_hash_map.c +++ b/src/core/ext/census/intrusive_hash_map.c @@ -27,8 +27,7 @@ static inline uint32_t chunked_vector_hasher(uint64_t key) { /* Vector chunks are 1MiB divided by pointer size. */ static const size_t VECTOR_CHUNK_SIZE = (1 << 20) / sizeof(void *); -/* Helper functions which return buckets from the chunked vector. These are - meant for internal use only within the intrusive_hash_map data structure. */ +/* Helper functions which return buckets from the chunked vector. */ static inline void **get_mutable_bucket(const chunked_vector *buckets, uint32_t index) { if (index < VECTOR_CHUNK_SIZE) { @@ -68,7 +67,7 @@ static void chunked_vector_clear(chunked_vector *vec) { } if (vec->rest_ != NULL) { size_t rest_size = RestSize(vec); - for (uint32_t i = 0; i < rest_size; ++i) { + for (size_t i = 0; i < rest_size; ++i) { if (vec->rest_[i] != NULL) { gpr_free(vec->rest_[i]); } diff --git a/src/core/ext/census/intrusive_hash_map.h b/src/core/ext/census/intrusive_hash_map.h index 900e4368c96..f005cc3b82b 100644 --- a/src/core/ext/census/intrusive_hash_map.h +++ b/src/core/ext/census/intrusive_hash_map.h @@ -17,21 +17,17 @@ #ifndef GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H #define GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H -#include -#include -#include -#include - -/* intrusive_hash_map is a fast chained hash table. It is almost always faster - * than STL hash_map, since this hash map avoids malloc and free during insert - * and erase. This hash map is faster than a dense hash map when the application - * calls insert and erase more often than find. When the workload is dominated - * by find() a dense hash map may be faster. +#include "src/core/ext/census/intrusive_hash_map_internal.h" + +/* intrusive_hash_map is a fast chained hash table. This hash map is faster than + * a dense hash map when the application calls insert and erase more often than + * find. When the workload is dominated by find() a dense hash map may be + * faster. * * intrusive_hash_map uses an intrusive header placed within a user defined - * struct. IHM_key MUST be set to a valid value before insertion into the hash - * map or undefined behavior may occur. IHM_hash_link needs to be set to NULL - * initially. + * struct. The header field IHM_key MUST be set to a valid value before + * insertion into the hash map or undefined behavior may occur. The header field + * IHM_hash_link MUST to be set to NULL initially. * * EXAMPLE USAGE: * @@ -53,6 +49,8 @@ * return item; * } * + * intrusive_hash_map hash_map; + * intrusive_hash_map_init(&hash_map, 4); * string_item *new_item1 = make_string_item(10, "test1", 5); * bool ok = intrusive_hash_map_insert(&hash_map, (hm_item *)new_item1); * @@ -61,9 +59,10 @@ */ /* Hash map item. Stores key and a pointer to the actual object. A user defined - * version of this can be passed in as long as the first 2 entries (key and - * hash_link) are the same. Pointer to struct will need to be cast as - * (hm_item *) when passed to hash map. This allows it to be intrusive. */ + * version of this can be passed in provided the first 2 entries (key and + * hash_link) are the same. These entries must be first in the user defined + * struct. Pointer to struct will need to be cast as (hm_item *) when passed to + * hash map. This allows it to be intrusive. */ typedef struct hm_item { uint64_t key; struct hm_item *hash_link; @@ -71,33 +70,12 @@ typedef struct hm_item { } hm_item; /* Macro provided for ease of use. This must be first in the user defined - * struct. */ + * struct (i.e. uint64_t key and hm_item * must be the first two elements in + * that order). */ #define INTRUSIVE_HASH_MAP_HEADER \ uint64_t IHM_key; \ struct hm_item *IHM_hash_link -/* The chunked vector is a data structure that allocates buckets for use in the - * hash map. ChunkedVector is logically equivalent to T*[N] (cast void* as - * T*). It's internally implemented as an array of 1MB arrays to avoid - * allocating large consecutive memory chunks. This is an internal data - * structure that should never be accessed directly. */ -typedef struct chunked_vector { - size_t size_; - void **first_; - void ***rest_; -} chunked_vector; - -/* Core intrusive hash map data structure. All internal elements are managed by - * functions and should not be altered manually. intrusive_hash_map_init() - * must first be called before an intrusive_hash_map can be used. */ -typedef struct intrusive_hash_map { - uint32_t num_items; - uint32_t extend_threshold; - uint32_t log2_num_buckets; - uint32_t hash_mask; - chunked_vector buckets; -} intrusive_hash_map; - /* Index struct which acts as a pseudo-iterator within the hash map. */ typedef struct hm_index { uint32_t bucket_index; // hash map bucket index. @@ -110,7 +88,10 @@ inline bool hm_index_compare(const hm_index *A, const hm_index *B) { return (A->item == B->item && A->bucket_index == B->bucket_index); } -/* Helper functions for iterating over the hash map. */ +/* + Helper functions for iterating over the hash map. + */ + /* On return idx will contain an invalid index which is always equal to * hash_map->buckets.size_ */ void intrusive_hash_map_end(const intrusive_hash_map *hash_map, hm_index *idx); @@ -152,18 +133,18 @@ hm_item *intrusive_hash_map_erase(intrusive_hash_map *hash_map, uint64_t key); * Otherwise, it will insert the new item and return true. */ bool intrusive_hash_map_insert(intrusive_hash_map *hash_map, hm_item *item); -/* Clear entire contents of the hash map, but leaves internal data structure - * untouched. Second argument takes a function pointer to a method that will +/* Clears entire contents of the hash map, but leaves internal data structure + * untouched. Second argument takes a function pointer to a function that will * free the object designated by the user and pointed to by hash_map->value. */ void intrusive_hash_map_clear(intrusive_hash_map *hash_map, void (*free_object)(void *)); /* Erase all contents of hash map and free the memory. Hash map is invalid * after calling this function and cannot be used until it has been - * reinitialized (intrusive_hash_map_init()). takes a function pointer to a - * method that will free the object designated by the user and pointed to by - * hash_map->value.*/ + * reinitialized (intrusive_hash_map_init()). This function takes a function + * pointer to a function that will free the object designated by the user and + * pointed to by hash_map->value. */ void intrusive_hash_map_free(intrusive_hash_map *hash_map, void (*free_object)(void *)); -#endif +#endif // GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H diff --git a/src/core/ext/census/intrusive_hash_map_internal.h b/src/core/ext/census/intrusive_hash_map_internal.h new file mode 100644 index 00000000000..c0a3c6f59a8 --- /dev/null +++ b/src/core/ext/census/intrusive_hash_map_internal.h @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H +#define GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H + +#include +#include +#include +#include + +/* The chunked vector is a data structure that allocates buckets for use in the + * hash map. ChunkedVector is logically equivalent to T*[N] (cast void* as + * T*). It's internally implemented as an array of 1MB arrays to avoid + * allocating large consecutive memory chunks. This is an internal data + * structure that should never be accessed directly. */ +typedef struct chunked_vector { + size_t size_; + void **first_; + void ***rest_; +} chunked_vector; + +/* Core intrusive hash map data structure. All internal elements are managed by + * functions and should not be altered manually. */ +typedef struct intrusive_hash_map { + uint32_t num_items; + uint32_t extend_threshold; + uint32_t log2_num_buckets; + uint32_t hash_mask; + chunked_vector buckets; +} intrusive_hash_map; + +#endif // GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H diff --git a/test/core/census/intrusive_hash_map_test.c b/test/core/census/intrusive_hash_map_test.c index d35a01e1032..a0a46ebadfa 100644 --- a/test/core/census/intrusive_hash_map_test.c +++ b/test/core/census/intrusive_hash_map_test.c @@ -28,14 +28,17 @@ /* The initial size of an intrusive hash map will be 2 to this power. */ static const uint32_t kInitialLog2Size = 4; +/* Simple object used for testing intrusive_hash_map. */ typedef struct object { uint64_t val; } object; +/* Helper function to allocate and initialize object. */ static inline object *make_new_object(uint64_t val) { object *obj = (object *)gpr_malloc(sizeof(object)); obj->val = val; return obj; } +/* Wrapper struct for object. */ typedef struct ptr_item { INTRUSIVE_HASH_MAP_HEADER; object *obj; @@ -51,8 +54,10 @@ static inline ptr_item *make_ptr_item(uint64_t key, uint64_t value) { return new_item; } +/* Helper function to deallocate ptr_item. */ static void free_ptr_item(void *ptr) { gpr_free(((ptr_item *)ptr)->obj); } +/* Simple string object used for testing intrusive_hash_map. */ typedef struct string_item { INTRUSIVE_HASH_MAP_HEADER; // User data. @@ -60,6 +65,7 @@ typedef struct string_item { uint16_t len; } string_item; +/* Helper function to allocate and initialize string object. */ static string_item *make_string_item(uint64_t key, const char *buf, uint16_t len) { string_item *item = (string_item *)gpr_malloc(sizeof(string_item)); @@ -70,6 +76,7 @@ static string_item *make_string_item(uint64_t key, const char *buf, return item; } +/* Helper function for comparing two string objects. */ static bool compare_string_item(const string_item *A, const string_item *B) { if (A->IHM_key != B->IHM_key || A->len != B->len) return false; @@ -90,7 +97,7 @@ void test_empty() { intrusive_hash_map_free(&hash_map, NULL); } -void test_basic() { +void test_single_item() { intrusive_hash_map hash_map; intrusive_hash_map_init(&hash_map, kInitialLog2Size); @@ -113,7 +120,7 @@ void test_basic() { intrusive_hash_map_free(&hash_map, &free_ptr_item); } -void test_basic2() { +void test_two_items() { intrusive_hash_map hash_map; intrusive_hash_map_init(&hash_map, kInitialLog2Size); @@ -215,10 +222,12 @@ void test_stress() { intrusive_hash_map_init(&hash_map, kInitialLog2Size); size_t n = 0; + // Randomly add and insert entries 1000000 times. for (uint64_t i = 0; i < 1000000; ++i) { int op = rand() & 0x1; switch (op) { + // Case 0 is insertion of entry. case 0: { uint64_t key = (uint64_t)(rand() % 10000); ptr_item *item = make_ptr_item(key, key); @@ -231,6 +240,7 @@ void test_stress() { } break; } + // Case 1 is removal of entry. case 1: { uint64_t key = (uint64_t)(rand() % 10000); ptr_item *item = (ptr_item *)intrusive_hash_map_find(&hash_map, key); @@ -262,8 +272,8 @@ int main(int argc, char **argv) { srand((unsigned)gpr_now(GPR_CLOCK_REALTIME).tv_nsec); test_empty(); - test_basic(); - test_basic2(); + test_single_item(); + test_two_items(); test_reset_clear(); test_extend(); test_stress(); diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 3d4bf7b4677..15410dec019 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -885,6 +885,7 @@ src/core/ext/census/grpc_plugin.c \ src/core/ext/census/initialize.c \ src/core/ext/census/intrusive_hash_map.c \ src/core/ext/census/intrusive_hash_map.h \ +src/core/ext/census/intrusive_hash_map_internal.h \ src/core/ext/census/mlog.c \ src/core/ext/census/mlog.h \ src/core/ext/census/operation.c \ diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index ca42c430e6e..97e079d8a8e 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -7559,6 +7559,7 @@ "src/core/ext/census/gen/trace_context.pb.h", "src/core/ext/census/grpc_filter.h", "src/core/ext/census/intrusive_hash_map.h", + "src/core/ext/census/intrusive_hash_map_internal.h", "src/core/ext/census/mlog.h", "src/core/ext/census/resource.h", "src/core/ext/census/rpc_metric_id.h", @@ -7591,6 +7592,7 @@ "src/core/ext/census/initialize.c", "src/core/ext/census/intrusive_hash_map.c", "src/core/ext/census/intrusive_hash_map.h", + "src/core/ext/census/intrusive_hash_map_internal.h", "src/core/ext/census/mlog.c", "src/core/ext/census/mlog.h", "src/core/ext/census/operation.c", diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj index 1c42774c316..1303366574d 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj @@ -505,6 +505,7 @@ + diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters index c110037bc85..9f25a1c179c 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters @@ -1460,6 +1460,9 @@ src\core\ext\census + + src\core\ext\census + src\core\ext\census diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj index 8b6b8cbd15c..ac403a7c485 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj @@ -470,6 +470,7 @@ + diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters index 69657eb65f4..9fee2ec22b7 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters @@ -1295,6 +1295,9 @@ src\core\ext\census + + src\core\ext\census + src\core\ext\census From d6466872c8ccf09fdc30a80ad86b78542069dd66 Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Tue, 23 May 2017 16:29:00 -0700 Subject: [PATCH 46/65] Add missing ref --- src/core/lib/http/httpcli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/lib/http/httpcli.c b/src/core/lib/http/httpcli.c index c3421e1b55c..f5588a9a767 100644 --- a/src/core/lib/http/httpcli.c +++ b/src/core/lib/http/httpcli.c @@ -245,7 +245,7 @@ static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req, static void on_resolved(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { internal_request *req = arg; if (error != GRPC_ERROR_NONE) { - finish(exec_ctx, req, error); + finish(exec_ctx, req, GRPC_ERROR_REF(error)); return; } req->next_address = 0; From 364cceb0f9f8ae8a3572afff9f521dc69721f3de Mon Sep 17 00:00:00 2001 From: Vizerai Date: Wed, 24 May 2017 13:52:53 -0700 Subject: [PATCH 47/65] update --- src/core/ext/census/intrusive_hash_map.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/ext/census/intrusive_hash_map.h b/src/core/ext/census/intrusive_hash_map.h index f005cc3b82b..9a7fd07f20a 100644 --- a/src/core/ext/census/intrusive_hash_map.h +++ b/src/core/ext/census/intrusive_hash_map.h @@ -89,8 +89,8 @@ inline bool hm_index_compare(const hm_index *A, const hm_index *B) { } /* - Helper functions for iterating over the hash map. - */ + * Helper functions for iterating over the hash map. + */ /* On return idx will contain an invalid index which is always equal to * hash_map->buckets.size_ */ From 1e9a93c3f5bf4a8334d491fe24e1a24c9752139b Mon Sep 17 00:00:00 2001 From: Feng Li Date: Wed, 24 May 2017 15:55:33 -0700 Subject: [PATCH 48/65] Remove the section for b64 encoded trailers. Remove the section for b64 encoded trailers. As gRPC-Web uses CRLF to separate the trailers in the trailers frame, a binary trailer need to reserve in a base64 encoded format for their values. This cannot be skipped even base64 is applied on the whole trailers frame per client's request via content-type: application/grpc-web-text. --- doc/PROTOCOL-WEB.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/PROTOCOL-WEB.md b/doc/PROTOCOL-WEB.md index 10998899c43..912dbe6d8f0 100644 --- a/doc/PROTOCOL-WEB.md +++ b/doc/PROTOCOL-WEB.md @@ -103,10 +103,6 @@ to security policies with XHR * While the server runtime will always base64-encode and flush gRPC messages atomically the client library should not assume base64 padding always happens at the boundary of message frames. That is, the implementation may send base64-encoded "chunks" with potential padding whenever the runtime needs to flush a byte buffer. -3. For binary trailers, when the content-type is set to -application/grpc-web-text, the extra base64 encoding specified -in [gRPC over HTTP2](http://www.grpc.io/docs/guides/wire.html) -for binary custom metadata is skipped. # Other features From d89248f51c7d0ea848b216484e3f580e54cfc839 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 24 May 2017 11:09:19 -0700 Subject: [PATCH 49/65] improve CONTRIBUTING.md and add rules for PRs --- CONTRIBUTING.md | 106 ++++++++++++++++++-------------------------- templates/README.md | 9 ++++ 2 files changed, 52 insertions(+), 63 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 56bb4b6eb98..e9c5fe20141 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,74 +1,54 @@ # How to contribute -We definitely welcome patches and contribution to grpc! Here is some guideline -and information about how to do so. +We definitely welcome your patches and contributions to gRPC! -## Getting started +If you are new to github, please start by reading [Pull Request howto](https://help.github.com/articles/about-pull-requests/) -### Legal requirements +## Legal requirements In order to protect both you and ourselves, you will need to sign the [Contributor License Agreement](https://cla.developers.google.com/clas). -### Technical requirements +## Running tests + +Use `tools/run_tests/run_tests.py` script to run the unit tests. +See [tools/run_tests](tools/run_tests) for how to run tests for a given language. + +Prerequisites for building and running tests are listed in [INSTALL.md](INSTALL.md) +and in `src/YOUR-LANGUAGE` (e.g. `src/csharp`) + +## Generated project files + +To ease maintenance of language- and platform- specific build systems, +many projects files are generated using templates and should not be edited +by hand. +Run `tools/buildgen/generate_projects.sh` to regenerate. +See [templates](templates) for details. + +As a rule of thumb, if you see the "sanity tests" failing you've most likely edited generated files or you didn't regenerate the projects properly (or your code formatting doesn't match our code style). + +## Guidelines for Pull Requests +How to get your contributions merged smoothly and quickly. + +- Create **small PRs** that are narrowly focused on **addressing a single concern**. We often times receive PRs that are trying to fix several things at a time, but only one fix is considered acceptable, nothing gets merged and both author's & review's time is wasted. Create more PRs to address different concerns and everyone will be happy. + +- For speculative changes, consider opening an issue and discussing it first. If you are suggesting a behavioral or API change, consider starting with a [gRFC proposal](https://github.com/grpc/proposal). + +- Provide a good **PR description** as a record of **what** change is being made and **why** it was made. Link to a github issue if it exists. + +- Don't fix code style and formatting unless you are already changing that line to address an issue. PRs with irrelevant changes won't be merged. If you do want to fix formatting or style, do that in a separate PR. + +- Unless your PR is trivial, you should expect there will be reviewer comments that you'll need to address before merging. We expect you to be reasonably responsive to those comments, otherwise the PR will be closed after 2-3 weeks of inactivity. + +- Maintain **clean commit history** and use **meaningful commit messages**. PRs with messy commit history are difficult to review and won't be merged. Use `rebase -i upstream/master` to curate your commit history and/or to bring in latest changes from master (but avoid rebasing in the middle of a code review). + +- Keep your PR up to date with upstream/master (if there are merge conflicts, we can't really merge your change). + +- if you are regenerating the projects using `tools/buildgen/generate_projects.sh`, make changes to generated files a separate commit with commit message `regenerate projects`. Mixing changes to generated and hand-written files make your PR difficult to review. + +- **All tests need to be passing** before your change can be merged. We recommend you **run tests locally** before creating your PR to catch breakages early on (see [tools/run_tests](tools/run_tests). Ultimately, the green signal will be provided by our testing infrastructure. The reviewer will help you if there are test failures that seem not related to the change you are making. + +- Exceptions to the rules can be made if there's a compelling reason for doing so. -You will need several tools to work with this repository. In addition to all of -the packages described in the [INSTALL](INSTALL.md) file, you will also need -python, and the mako template renderer. To install the latter, using pip, one -should simply be able to do `pip install mako`. -In order to run all of the tests we provide, you will need valgrind and clang. -More specifically, under debian, you will need the package libc++-dev to -properly run all the tests. -Compiling and running grpc C++ tests depend on protobuf 3.0.0, gtest and gflags. -Although gflags is provided in third_party, you will need to manually install -that dependency on your system to run these tests. Under a Debian or Ubuntu -system, you can install the gtests and gflags packages using apt-get: - -```sh - $ [sudo] apt-get install libgflags-dev libgtest-dev -``` - -If you are planning to work on any of the languages other than C and C++, you -will also need their appropriate development environments. - -If you want to work under Windows, we recommend the use of Visual Studio 2013. -The [Community or Express editions](http://www.visualstudio.com/en-us/downloads/download-visual-studio-vs.aspx) -are free and suitable for developing with grpc. Note however that our test -environment and tools are available for Unix environments only at the moment. - -## Testing your changes - -We provide a tool to help run the suite of tests in various environments. -In order to run most of the available tests, one would need to run: - -`./tools/run_tests/run_tests.py` - -If you want to run tests for any of the languages {c, c++, csharp, node, objc, php, python, ruby}, do this: - -`./tools/run_tests/run_tests.py -l ` - -To know about the list of available commands, do this: - -`./tools/run_tests/run_tests.py -h` - -If you are running tests for ObjC on osx, follow these steps before running tests: -* install Xcode command-line tools by running -`sudo xcode-select --install` -* install macports from https://www.macports.org/install.php -* install autoconf, automake, libtool, gflags, cmake using macports -* restart your terminal window or run source ~/.bash_profile to pick up the new PATH changes. - -## Adding or removing source code - -Each language uses its own build system to work. Currently, the root's Makefile -and the Visual Studio project files are building only the C and C++ source code. -In order to ease the maintenance of these files, we have a -template system. Please do not contribute manual changes to any of the generated -files. Instead, modify the template files, or the build.yaml file, and -re-generate the project files using the following command: - -`./tools/buildgen/generate_projects.sh` - -You'll find more information about this in the [templates](templates) folder. diff --git a/templates/README.md b/templates/README.md index eedc6e9c09f..7b7707203fb 100644 --- a/templates/README.md +++ b/templates/README.md @@ -1,3 +1,12 @@ +# Regenerating project files + +Prerequisites: `python`, `pip install mako` + +``` +# Regenerate the projects files using templates +tools/buildgen/generate_projects.sh +``` + # Quick justification We've approached the problem of the build system from a lot of different From 30f2b7ece1d04502ef9a4345b88a76844ced9f2c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 25 May 2017 10:55:53 -0700 Subject: [PATCH 50/65] Add more null checks to call methods --- src/node/ext/call.cc | 20 +++++++++++++++++--- src/node/ext/call.h | 1 + src/node/test/common_test.js | 1 - src/node/test/surface_test.js | 25 +++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc index 2cc9f63b659..e2185da1c54 100644 --- a/src/node/ext/call.cc +++ b/src/node/ext/call.cc @@ -562,10 +562,12 @@ void Call::DestroyCall() { Call::Call(grpc_call *call) : wrapped_call(call), pending_batches(0), has_final_op_completed(false) { + peer = grpc_call_get_peer(call); } Call::~Call() { DestroyCall(); + gpr_free(peer); } void Call::Init(Local exports) { @@ -794,6 +796,11 @@ NAN_METHOD(Call::Cancel) { return Nan::ThrowTypeError("cancel can only be called on Call objects"); } Call *call = ObjectWrap::Unwrap(info.This()); + if (call->wrapped_call == NULL) { + /* Cancel is supposed to be idempotent. If the call has already finished, + * cancel should just complete silently */ + return; + } grpc_call_error error = grpc_call_cancel(call->wrapped_call, NULL); if (error != GRPC_CALL_OK) { return Nan::ThrowError(nanErrorWithCode("cancel failed", error)); @@ -814,6 +821,11 @@ NAN_METHOD(Call::CancelWithStatus) { "cancelWithStatus's second argument must be a string"); } Call *call = ObjectWrap::Unwrap(info.This()); + if (call->wrapped_call == NULL) { + /* Cancel is supposed to be idempotent. If the call has already finished, + * cancel should just complete silently */ + return; + } grpc_status_code code = static_cast( Nan::To(info[0]).FromJust()); if (code == GRPC_STATUS_OK) { @@ -830,9 +842,7 @@ NAN_METHOD(Call::GetPeer) { return Nan::ThrowTypeError("getPeer can only be called on Call objects"); } Call *call = ObjectWrap::Unwrap(info.This()); - char *peer = grpc_call_get_peer(call->wrapped_call); - Local peer_value = Nan::New(peer).ToLocalChecked(); - gpr_free(peer); + Local peer_value = Nan::New(call->peer).ToLocalChecked(); info.GetReturnValue().Set(peer_value); } @@ -847,6 +857,10 @@ NAN_METHOD(Call::SetCredentials) { "setCredentials' first argument must be a CallCredentials"); } Call *call = ObjectWrap::Unwrap(info.This()); + if (call->wrapped_call == NULL) { + return Nan::ThrowError( + "Cannot set credentials on a call that has already started"); + } CallCredentials *creds_object = ObjectWrap::Unwrap( Nan::To(info[0]).ToLocalChecked()); grpc_call_credentials *creds = creds_object->GetWrappedCredentials(); diff --git a/src/node/ext/call.h b/src/node/ext/call.h index 340e32682b9..45b448e0b1b 100644 --- a/src/node/ext/call.h +++ b/src/node/ext/call.h @@ -97,6 +97,7 @@ class Call : public Nan::ObjectWrap { call, this is GRPC_OP_RECV_STATUS_ON_CLIENT and for a server call, this is GRPC_OP_SEND_STATUS_FROM_SERVER */ bool has_final_op_completed; + char *peer; }; class Op { diff --git a/src/node/test/common_test.js b/src/node/test/common_test.js index b7c2c6a8d66..db80207e223 100644 --- a/src/node/test/common_test.js +++ b/src/node/test/common_test.js @@ -100,7 +100,6 @@ describe('Proto message long int serialize and deserialize', function() { var longNumDeserialize = deserializeCls(messages_proto.LongValues, num_options); var serialized = longSerialize({int_64: pos_value}); - console.log(longDeserialize(serialized)); assert.strictEqual(typeof longDeserialize(serialized).int_64, 'string'); /* With the longsAsStrings option disabled, long values are represented as * objects with 3 keys: low, high, and unsigned */ diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js index d2f0511af2d..0696e7ae195 100644 --- a/src/node/test/surface_test.js +++ b/src/node/test/surface_test.js @@ -1110,6 +1110,18 @@ describe('Other conditions', function() { done(); }); }); + it('after the call has fully completed', function(done) { + var peer; + var call = client.unary({error: false}, function(err, data) { + assert.ifError(err); + setImmediate(function() { + assert.strictEqual(peer, call.getPeer()); + done(); + }); + }); + peer = call.getPeer(); + assert.strictEqual(typeof peer, 'string'); + }); }); }); describe('Call propagation', function() { @@ -1352,4 +1364,17 @@ describe('Cancelling surface client', function() { }); call.cancel(); }); + it('Should be idempotent', function(done) { + var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) { + assert.strictEqual(err.code, surface_client.status.CANCELLED); + // Call asynchronously to try cancelling after call is fully completed + setImmediate(function() { + assert.doesNotThrow(function() { + call.cancel(); + }); + done(); + }); + }); + call.cancel(); + }); }); From f3bb34935d9ccb45ef9c1568dc1dadc98aad1189 Mon Sep 17 00:00:00 2001 From: Ken Payson Date: Thu, 25 May 2017 12:12:13 -0700 Subject: [PATCH 51/65] Fix Python reflection arguments --- .../grpcio_reflection/grpc_reflection/v1alpha/reflection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py b/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py index cd896f32c3c..0f399f8f8d9 100644 --- a/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py +++ b/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py @@ -152,4 +152,4 @@ def enable_server_reflection(service_names, server, pool=None): pool: DescriptorPool object to use (descriptor_pool.Default() if None). """ reflection_pb2_grpc.add_ServerReflectionServicer_to_server( - ReflectionServicer(service_names), server, pool) + ReflectionServicer(service_names, pool), server) From cd6ab2212252db6543291121699451a9285a0c9a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 25 May 2017 15:45:32 -0700 Subject: [PATCH 52/65] Fix concurrent_connectivity_test --- test/core/surface/concurrent_connectivity_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/core/surface/concurrent_connectivity_test.c b/test/core/surface/concurrent_connectivity_test.c index 1f09311b1fa..7614696caed 100644 --- a/test/core/surface/concurrent_connectivity_test.c +++ b/test/core/surface/concurrent_connectivity_test.c @@ -254,7 +254,7 @@ int run_concurrent_connectivity_test() { void watches_with_short_timeouts(void *addr) { for (int i = 0; i < NUM_OUTER_LOOPS_SHORT_TIMEOUTS; ++i) { - grpc_completion_queue *cq = grpc_completion_queue_create(NULL); + grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL); grpc_channel *chan = grpc_insecure_channel_create((char *)addr, NULL, NULL); for (int j = 0; j < NUM_INNER_LOOPS_SHORT_TIMEOUTS; ++j) { From 7563641414f490f0f66a6991fc3901319ddb172c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 25 May 2017 16:36:01 -0700 Subject: [PATCH 53/65] Fix node cancellation tests --- src/node/test/surface_test.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js index 0696e7ae195..f8eaf62aaff 100644 --- a/src/node/test/surface_test.js +++ b/src/node/test/surface_test.js @@ -1334,14 +1334,14 @@ describe('Cancelling surface client', function() { }); it('Should correctly cancel a unary call', function(done) { var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) { - assert.strictEqual(err.code, surface_client.status.CANCELLED); + assert.strictEqual(err.code, grpc.status.CANCELLED); done(); }); call.cancel(); }); it('Should correctly cancel a client stream call', function(done) { var call = client.sum(function(err, resp) { - assert.strictEqual(err.code, surface_client.status.CANCELLED); + assert.strictEqual(err.code, grpc.status.CANCELLED); done(); }); call.cancel(); @@ -1350,7 +1350,7 @@ describe('Cancelling surface client', function() { var call = client.fib({'limit': 5}); call.on('data', function() {}); call.on('error', function(error) { - assert.strictEqual(error.code, surface_client.status.CANCELLED); + assert.strictEqual(error.code, grpc.status.CANCELLED); done(); }); call.cancel(); @@ -1359,14 +1359,14 @@ describe('Cancelling surface client', function() { var call = client.divMany(); call.on('data', function() {}); call.on('error', function(error) { - assert.strictEqual(error.code, surface_client.status.CANCELLED); + assert.strictEqual(error.code, grpc.status.CANCELLED); done(); }); call.cancel(); }); it('Should be idempotent', function(done) { var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) { - assert.strictEqual(err.code, surface_client.status.CANCELLED); + assert.strictEqual(err.code, grpc.status.CANCELLED); // Call asynchronously to try cancelling after call is fully completed setImmediate(function() { assert.doesNotThrow(function() { From ce0861185b3c282b5a1ea1b31f51a96285315f84 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Thu, 25 May 2017 21:41:37 -0700 Subject: [PATCH 54/65] add missing copyright headers --- src/core/ext/census/intrusive_hash_map.c | 37 +++++++++++++----- src/core/ext/census/intrusive_hash_map.h | 37 +++++++++++++----- .../ext/census/intrusive_hash_map_internal.h | 39 +++++++++++++------ test/core/census/intrusive_hash_map_test.c | 37 +++++++++++++----- 4 files changed, 109 insertions(+), 41 deletions(-) diff --git a/src/core/ext/census/intrusive_hash_map.c b/src/core/ext/census/intrusive_hash_map.c index e64e8086ca2..77512a3aac8 100644 --- a/src/core/ext/census/intrusive_hash_map.c +++ b/src/core/ext/census/intrusive_hash_map.c @@ -1,17 +1,34 @@ /* - * Copyright 2017 Google Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Copyright 2017, Google Inc. + * All rights reserved. * - * http://www.apache.org/licenses/LICENSE-2.0 + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ #include "src/core/ext/census/intrusive_hash_map.h" diff --git a/src/core/ext/census/intrusive_hash_map.h b/src/core/ext/census/intrusive_hash_map.h index 9a7fd07f20a..a7593060588 100644 --- a/src/core/ext/census/intrusive_hash_map.h +++ b/src/core/ext/census/intrusive_hash_map.h @@ -1,17 +1,34 @@ /* - * Copyright 2017 Google Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Copyright 2017, Google Inc. + * All rights reserved. * - * http://www.apache.org/licenses/LICENSE-2.0 + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ #ifndef GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H diff --git a/src/core/ext/census/intrusive_hash_map_internal.h b/src/core/ext/census/intrusive_hash_map_internal.h index c0a3c6f59a8..625c06c8411 100644 --- a/src/core/ext/census/intrusive_hash_map_internal.h +++ b/src/core/ext/census/intrusive_hash_map_internal.h @@ -1,17 +1,34 @@ /* - * Copyright 2017 Google Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Copyright 2017, Google Inc. + * All rights reserved. * - * http://www.apache.org/licenses/LICENSE-2.0 + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ #ifndef GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H @@ -43,4 +60,4 @@ typedef struct intrusive_hash_map { chunked_vector buckets; } intrusive_hash_map; -#endif // GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H +#endif // GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H diff --git a/test/core/census/intrusive_hash_map_test.c b/test/core/census/intrusive_hash_map_test.c index a0a46ebadfa..fe8d3a1675a 100644 --- a/test/core/census/intrusive_hash_map_test.c +++ b/test/core/census/intrusive_hash_map_test.c @@ -1,17 +1,34 @@ /* - * Copyright 2017 Google Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Copyright 2017, Google Inc. + * All rights reserved. * - * http://www.apache.org/licenses/LICENSE-2.0 + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ #include "src/core/ext/census/intrusive_hash_map.h" From e809bca022c5f2f72015db56250fdab19d2a4cbc Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Thu, 25 May 2017 21:42:04 -0700 Subject: [PATCH 55/65] rerun clang format code.sh --- src/core/ext/census/intrusive_hash_map.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ext/census/intrusive_hash_map.h b/src/core/ext/census/intrusive_hash_map.h index a7593060588..b898f45e90c 100644 --- a/src/core/ext/census/intrusive_hash_map.h +++ b/src/core/ext/census/intrusive_hash_map.h @@ -164,4 +164,4 @@ void intrusive_hash_map_clear(intrusive_hash_map *hash_map, void intrusive_hash_map_free(intrusive_hash_map *hash_map, void (*free_object)(void *)); -#endif // GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H +#endif // GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H From 4d381910d00f4e764edf9d308960f2563c323d02 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Thu, 25 May 2017 22:06:44 -0700 Subject: [PATCH 56/65] fix format of include guards --- src/core/ext/census/intrusive_hash_map.h | 2 +- src/core/ext/census/intrusive_hash_map_internal.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/ext/census/intrusive_hash_map.h b/src/core/ext/census/intrusive_hash_map.h index b898f45e90c..a8405517b89 100644 --- a/src/core/ext/census/intrusive_hash_map.h +++ b/src/core/ext/census/intrusive_hash_map.h @@ -164,4 +164,4 @@ void intrusive_hash_map_clear(intrusive_hash_map *hash_map, void intrusive_hash_map_free(intrusive_hash_map *hash_map, void (*free_object)(void *)); -#endif // GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H +#endif /* GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H */ diff --git a/src/core/ext/census/intrusive_hash_map_internal.h b/src/core/ext/census/intrusive_hash_map_internal.h index 625c06c8411..76a9a3a7224 100644 --- a/src/core/ext/census/intrusive_hash_map_internal.h +++ b/src/core/ext/census/intrusive_hash_map_internal.h @@ -60,4 +60,4 @@ typedef struct intrusive_hash_map { chunked_vector buckets; } intrusive_hash_map; -#endif // GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H +#endif /* GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H */ From 342e72c585315e6f6e74e1412b3d58cd746ec89f Mon Sep 17 00:00:00 2001 From: ncteisen Date: Fri, 26 May 2017 07:44:03 -0400 Subject: [PATCH 57/65] Remove uneeded ref/unref --- src/core/lib/http/httpcli.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/lib/http/httpcli.c b/src/core/lib/http/httpcli.c index f5588a9a767..7012ffe568d 100644 --- a/src/core/lib/http/httpcli.c +++ b/src/core/lib/http/httpcli.c @@ -105,7 +105,7 @@ static void finish(grpc_exec_ctx *exec_ctx, internal_request *req, grpc_error *error) { grpc_polling_entity_del_from_pollset_set(exec_ctx, req->pollent, req->context->pollset_set); - grpc_closure_sched(exec_ctx, req->on_done, GRPC_ERROR_REF(error)); + grpc_closure_sched(exec_ctx, req->on_done, error); grpc_http_parser_destroy(&req->parser); if (req->addresses != NULL) { grpc_resolved_addresses_destroy(req->addresses); @@ -120,7 +120,6 @@ static void finish(grpc_exec_ctx *exec_ctx, internal_request *req, grpc_slice_buffer_destroy_internal(exec_ctx, &req->incoming); grpc_slice_buffer_destroy_internal(exec_ctx, &req->outgoing); GRPC_ERROR_UNREF(req->overall_error); - GRPC_ERROR_UNREF(error); grpc_resource_quota_unref_internal(exec_ctx, req->resource_quota); gpr_free(req); } From 46356b72a011e02e7bd59bc390d358b887e84e7e Mon Sep 17 00:00:00 2001 From: Craig Tiller Date: Fri, 26 May 2017 15:22:08 +0000 Subject: [PATCH 58/65] Make jobset more eintr resilient --- tools/run_tests/python_utils/jobset.py | 62 ++++++++++++++------------ 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/tools/run_tests/python_utils/jobset.py b/tools/run_tests/python_utils/jobset.py index 37540353088..3ff773300f3 100755 --- a/tools/run_tests/python_utils/jobset.py +++ b/tools/run_tests/python_utils/jobset.py @@ -41,6 +41,7 @@ import subprocess import sys import tempfile import time +import errno # cpu cost measurement @@ -132,29 +133,44 @@ _TAG_COLOR = { _FORMAT = '%(asctime)-15s %(message)s' logging.basicConfig(level=logging.INFO, format=_FORMAT) + +def eintr_be_gone(fn): + """Run fn until it doesn't stop because of EINTR""" + while True: + try: + return fn() + except IOError, e: + if e.errno != errno.EINTR: + raise + + + def message(tag, msg, explanatory_text=None, do_newline=False): if message.old_tag == tag and message.old_msg == msg and not explanatory_text: return message.old_tag = tag message.old_msg = msg - try: - if platform_string() == 'windows' or not sys.stdout.isatty(): - if explanatory_text: - logging.info(explanatory_text) - logging.info('%s: %s', tag, msg) - else: - sys.stdout.write('%s%s%s\x1b[%d;%dm%s\x1b[0m: %s%s' % ( - _BEGINNING_OF_LINE, - _CLEAR_LINE, - '\n%s' % explanatory_text if explanatory_text is not None else '', - _COLORS[_TAG_COLOR[tag]][1], - _COLORS[_TAG_COLOR[tag]][0], - tag, - msg, - '\n' if do_newline or explanatory_text is not None else '')) - sys.stdout.flush() - except: - pass + while True: + try: + if platform_string() == 'windows' or not sys.stdout.isatty(): + if explanatory_text: + logging.info(explanatory_text) + logging.info('%s: %s', tag, msg) + else: + sys.stdout.write('%s%s%s\x1b[%d;%dm%s\x1b[0m: %s%s' % ( + _BEGINNING_OF_LINE, + _CLEAR_LINE, + '\n%s' % explanatory_text if explanatory_text is not None else '', + _COLORS[_TAG_COLOR[tag]][1], + _COLORS[_TAG_COLOR[tag]][0], + tag, + msg, + '\n' if do_newline or explanatory_text is not None else '')) + sys.stdout.flush() + return + except IOError, e: + if e.errno != errno.EINTR: + raise message.old_tag = '' message.old_msg = '' @@ -226,16 +242,6 @@ class JobResult(object): self.cpu_measured = 0 -def eintr_be_gone(fn): - """Run fn until it doesn't stop because of EINTR""" - while True: - try: - return fn() - except IOError, e: - if e.errno != errno.EINTR: - raise - - def read_from_start(f): f.seek(0) return f.read() From e22c902e6304f944463ea4a26a9733361f2c5314 Mon Sep 17 00:00:00 2001 From: Makarand Dharmapurikar Date: Fri, 26 May 2017 08:45:48 -0700 Subject: [PATCH 59/65] clang-format and include guard fix --- src/core/ext/census/intrusive_hash_map.h | 2 +- src/core/ext/census/intrusive_hash_map_internal.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/ext/census/intrusive_hash_map.h b/src/core/ext/census/intrusive_hash_map.h index 9a7fd07f20a..cb31cf65107 100644 --- a/src/core/ext/census/intrusive_hash_map.h +++ b/src/core/ext/census/intrusive_hash_map.h @@ -147,4 +147,4 @@ void intrusive_hash_map_clear(intrusive_hash_map *hash_map, void intrusive_hash_map_free(intrusive_hash_map *hash_map, void (*free_object)(void *)); -#endif // GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H +#endif /* GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H */ diff --git a/src/core/ext/census/intrusive_hash_map_internal.h b/src/core/ext/census/intrusive_hash_map_internal.h index c0a3c6f59a8..dba190cce5f 100644 --- a/src/core/ext/census/intrusive_hash_map_internal.h +++ b/src/core/ext/census/intrusive_hash_map_internal.h @@ -43,4 +43,4 @@ typedef struct intrusive_hash_map { chunked_vector buckets; } intrusive_hash_map; -#endif // GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H +#endif /* GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H */ From cce3ccc29ede38276628060ab9b819dbeaafe23f Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Fri, 26 May 2017 14:10:13 -0700 Subject: [PATCH 60/65] get rid of flakey asserts in num_watchers test --- .../core/surface/num_external_connectivity_watchers_test.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/core/surface/num_external_connectivity_watchers_test.c b/test/core/surface/num_external_connectivity_watchers_test.c index 96288ab60db..93944c9ad5b 100644 --- a/test/core/surface/num_external_connectivity_watchers_test.c +++ b/test/core/surface/num_external_connectivity_watchers_test.c @@ -92,15 +92,12 @@ static void run_timeouts_test(const test_fixture *fixture) { /* start 1 watcher and then let it time out */ channel_idle_start_watch(channel, cq); - GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 1); channel_idle_poll_for_timeout(channel, cq); GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 0); /* start 3 watchers and then let them all time out */ for (size_t i = 1; i <= 3; i++) { channel_idle_start_watch(channel, cq); - GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == - (int)i); } for (size_t i = 1; i <= 3; i++) { channel_idle_poll_for_timeout(channel, cq); @@ -111,14 +108,11 @@ static void run_timeouts_test(const test_fixture *fixture) { * time out */ for (size_t i = 1; i <= 3; i++) { channel_idle_start_watch(channel, cq); - GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == - (int)i); } channel_idle_poll_for_timeout(channel, cq); for (size_t i = 3; i <= 5; i++) { channel_idle_start_watch(channel, cq); } - GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) >= 3); for (size_t i = 1; i <= 5; i++) { channel_idle_poll_for_timeout(channel, cq); } @@ -160,7 +154,6 @@ static void run_channel_shutdown_before_timeout_test( grpc_channel_watch_connectivity_state(channel, GRPC_CHANNEL_IDLE, connect_deadline, cq, (void *)1); - GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 1); grpc_channel_destroy(channel); grpc_event ev = From c400cc5f8dcff7ff70a7030f085ebdd5c9359fa5 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 26 May 2017 14:44:34 -0700 Subject: [PATCH 61/65] address comments --- src/csharp/Grpc.Core/Internal/CompletionRegistry.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs index fc0ff72e6a1..075286d33ea 100644 --- a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs +++ b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs @@ -52,7 +52,7 @@ namespace Grpc.Core.Internal readonly GrpcEnvironment environment; readonly ConcurrentDictionary dict = new ConcurrentDictionary(new IntPtrComparer()); - IntPtr lastRegisteredKey; + IntPtr lastRegisteredKey; // only for testing public CompletionRegistry(GrpcEnvironment environment) { @@ -86,6 +86,9 @@ namespace Grpc.Core.Internal return value; } + /// + /// For testing purposes only. + /// public IntPtr LastRegisteredKey { get { return this.lastRegisteredKey; } From 93fdf611a571450964ad4512ff2ed33d7c39c47c Mon Sep 17 00:00:00 2001 From: Makarand Dharmapurikar Date: Tue, 30 May 2017 14:03:01 -0700 Subject: [PATCH 62/65] s/inline/__inline/. Visual studio incompatiblity. MS Visual studio '13 and before don't understand inline and throw Error C2054. Reference: https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx --- src/core/ext/census/intrusive_hash_map.c | 10 +++++----- src/core/ext/census/intrusive_hash_map.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/core/ext/census/intrusive_hash_map.c b/src/core/ext/census/intrusive_hash_map.c index 77512a3aac8..d147f23364d 100644 --- a/src/core/ext/census/intrusive_hash_map.c +++ b/src/core/ext/census/intrusive_hash_map.c @@ -37,7 +37,7 @@ extern bool hm_index_compare(const hm_index *A, const hm_index *B); /* Simple hashing function that takes lower 32 bits. */ -static inline uint32_t chunked_vector_hasher(uint64_t key) { +static __inline uint32_t chunked_vector_hasher(uint64_t key) { return (uint32_t)key; } @@ -45,7 +45,7 @@ static inline uint32_t chunked_vector_hasher(uint64_t key) { static const size_t VECTOR_CHUNK_SIZE = (1 << 20) / sizeof(void *); /* Helper functions which return buckets from the chunked vector. */ -static inline void **get_mutable_bucket(const chunked_vector *buckets, +static __inline void **get_mutable_bucket(const chunked_vector *buckets, uint32_t index) { if (index < VECTOR_CHUNK_SIZE) { return &buckets->first_[index]; @@ -54,7 +54,7 @@ static inline void **get_mutable_bucket(const chunked_vector *buckets, return &buckets->rest_[rest_index][index % VECTOR_CHUNK_SIZE]; } -static inline void *get_bucket(const chunked_vector *buckets, uint32_t index) { +static __inline void *get_bucket(const chunked_vector *buckets, uint32_t index) { if (index < VECTOR_CHUNK_SIZE) { return buckets->first_[index]; } @@ -63,7 +63,7 @@ static inline void *get_bucket(const chunked_vector *buckets, uint32_t index) { } /* Helper function. */ -static inline size_t RestSize(const chunked_vector *vec) { +static __inline size_t RestSize(const chunked_vector *vec) { return (vec->size_ <= VECTOR_CHUNK_SIZE) ? 0 : (vec->size_ - VECTOR_CHUNK_SIZE - 1) / VECTOR_CHUNK_SIZE + 1; @@ -222,7 +222,7 @@ hm_item *intrusive_hash_map_erase(intrusive_hash_map *hash_map, uint64_t key) { * array_size-1. Returns true if it is a new hm_item and false if the hm_item * already existed. */ -static inline bool intrusive_hash_map_internal_insert(chunked_vector *buckets, +static __inline bool intrusive_hash_map_internal_insert(chunked_vector *buckets, uint32_t hash_mask, hm_item *item) { const uint64_t key = item->key; diff --git a/src/core/ext/census/intrusive_hash_map.h b/src/core/ext/census/intrusive_hash_map.h index a8405517b89..e316bf4b161 100644 --- a/src/core/ext/census/intrusive_hash_map.h +++ b/src/core/ext/census/intrusive_hash_map.h @@ -101,7 +101,7 @@ typedef struct hm_index { /* Returns true if two hm_indices point to the same object within the hash map * and false otherwise. */ -inline bool hm_index_compare(const hm_index *A, const hm_index *B) { +__inline bool hm_index_compare(const hm_index *A, const hm_index *B) { return (A->item == B->item && A->bucket_index == B->bucket_index); } From aebcdbd732e9294c8a424d3167c028f02af5ef1c Mon Sep 17 00:00:00 2001 From: David Garcia Quintas Date: Tue, 30 May 2017 14:14:27 -0700 Subject: [PATCH 63/65] master bumped to 1.5.x --- BUILD | 4 ++-- CMakeLists.txt | 2 +- Makefile | 4 ++-- build.yaml | 2 +- gRPC-Core.podspec | 2 +- gRPC-ProtoRPC.podspec | 2 +- gRPC-RxLibrary.podspec | 2 +- gRPC.podspec | 2 +- package.json | 2 +- package.xml | 4 ++-- src/cpp/common/version_cc.cc | 2 +- src/csharp/Grpc.Core/Version.csproj.include | 2 +- src/csharp/Grpc.Core/VersionInfo.cs | 4 ++-- src/csharp/build_packages_dotnetcli.bat | 2 +- src/csharp/build_packages_dotnetcli.sh | 4 ++-- src/node/health_check/package.json | 4 ++-- src/node/tools/package.json | 2 +- src/objective-c/!ProtoCompiler-gRPCPlugin.podspec | 2 +- src/objective-c/GRPCClient/private/version.h | 2 +- src/php/composer.json | 2 +- src/php/ext/grpc/version.h | 2 +- src/python/grpcio/grpc/_grpcio_metadata.py | 2 +- src/python/grpcio/grpc_version.py | 2 +- src/python/grpcio_health_checking/grpc_version.py | 2 +- src/python/grpcio_reflection/grpc_version.py | 2 +- src/python/grpcio_tests/grpc_version.py | 2 +- src/ruby/lib/grpc/version.rb | 2 +- src/ruby/tools/version.rb | 2 +- tools/distrib/python/grpcio_tools/grpc_version.py | 2 +- tools/doxygen/Doxyfile.c++ | 2 +- tools/doxygen/Doxyfile.c++.internal | 2 +- 31 files changed, 37 insertions(+), 37 deletions(-) diff --git a/BUILD b/BUILD index bdea522ad15..d3a77808ea1 100644 --- a/BUILD +++ b/BUILD @@ -51,9 +51,9 @@ load( # This should be updated along with build.yaml g_stands_for = "gregarious" -core_version = "3.0.0-dev" +core_version = "4.0.0-dev" -version = "1.4.0-dev" +version = "1.5.0-dev" grpc_cc_library( name = "gpr", diff --git a/CMakeLists.txt b/CMakeLists.txt index fd53f621a65..11c6b047888 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ cmake_minimum_required(VERSION 2.8) set(PACKAGE_NAME "grpc") -set(PACKAGE_VERSION "1.4.0-dev") +set(PACKAGE_VERSION "1.5.0-dev") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/") diff --git a/Makefile b/Makefile index 82b2104b4a7..5e29711fb18 100644 --- a/Makefile +++ b/Makefile @@ -423,8 +423,8 @@ Q = @ endif CORE_VERSION = 4.0.0-dev -CPP_VERSION = 1.4.0-dev -CSHARP_VERSION = 1.4.0-dev +CPP_VERSION = 1.5.0-dev +CSHARP_VERSION = 1.5.0-dev CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES)) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) diff --git a/build.yaml b/build.yaml index 26144e33def..d1e61256e6e 100644 --- a/build.yaml +++ b/build.yaml @@ -14,7 +14,7 @@ settings: '#10': See the expand_version.py for all the quirks here core_version: 4.0.0-dev g_stands_for: gregarious - version: 1.4.0-dev + version: 1.5.0-dev filegroups: - name: census public_headers: diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index d9de2d78a05..e5e61df477f 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -37,7 +37,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-Core' - version = '1.4.0-dev' + version = '1.5.0-dev' s.version = version s.summary = 'Core cross-platform gRPC library, written in C' s.homepage = 'http://www.grpc.io' diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec index 62cb0d11a1c..6baef288855 100644 --- a/gRPC-ProtoRPC.podspec +++ b/gRPC-ProtoRPC.podspec @@ -36,7 +36,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-ProtoRPC' - version = '1.4.0-dev' + version = '1.5.0-dev' s.version = version s.summary = 'RPC library for Protocol Buffers, based on gRPC' s.homepage = 'http://www.grpc.io' diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec index 77ceb22123c..dfccc5d16c4 100644 --- a/gRPC-RxLibrary.podspec +++ b/gRPC-RxLibrary.podspec @@ -36,7 +36,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-RxLibrary' - version = '1.4.0-dev' + version = '1.5.0-dev' s.version = version s.summary = 'Reactive Extensions library for iOS/OSX.' s.homepage = 'http://www.grpc.io' diff --git a/gRPC.podspec b/gRPC.podspec index 10520bd3880..7f4886ab656 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -35,7 +35,7 @@ Pod::Spec.new do |s| s.name = 'gRPC' - version = '1.4.0-dev' + version = '1.5.0-dev' s.version = version s.summary = 'gRPC client library for iOS/OSX' s.homepage = 'http://www.grpc.io' diff --git a/package.json b/package.json index 1ed182ced93..a0d76c435b6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.4.0-dev", + "version": "1.5.0-dev", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "http://www.grpc.io/", diff --git a/package.xml b/package.xml index 9179ef238c9..817a0345d60 100644 --- a/package.xml +++ b/package.xml @@ -13,8 +13,8 @@ 2017-05-22 - 1.4.0dev - 1.4.0dev + 1.5.0dev + 1.5.0dev beta diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc index 72a4c4cf94a..e4f5cb8422e 100644 --- a/src/cpp/common/version_cc.cc +++ b/src/cpp/common/version_cc.cc @@ -37,5 +37,5 @@ #include namespace grpc { -grpc::string Version() { return "1.4.0-dev"; } +grpc::string Version() { return "1.5.0-dev"; } } diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include index 8388bfd9cca..81156452f3e 100755 --- a/src/csharp/Grpc.Core/Version.csproj.include +++ b/src/csharp/Grpc.Core/Version.csproj.include @@ -1,7 +1,7 @@ - 1.4.0-dev + 1.5.0-dev 3.3.0 diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs index 2e55d9d80eb..d507878c2df 100644 --- a/src/csharp/Grpc.Core/VersionInfo.cs +++ b/src/csharp/Grpc.Core/VersionInfo.cs @@ -48,11 +48,11 @@ namespace Grpc.Core /// /// Current AssemblyFileVersion of gRPC C# assemblies /// - public const string CurrentAssemblyFileVersion = "1.4.0.0"; + public const string CurrentAssemblyFileVersion = "1.5.0.0"; /// /// Current version of gRPC C# /// - public const string CurrentVersion = "1.4.0-dev"; + public const string CurrentVersion = "1.5.0-dev"; } } diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat index aa8a8d3b17b..35664cc762d 100755 --- a/src/csharp/build_packages_dotnetcli.bat +++ b/src/csharp/build_packages_dotnetcli.bat @@ -28,7 +28,7 @@ @rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @rem Current package versions -set VERSION=1.4.0-dev +set VERSION=1.5.0-dev @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh index d33923845c1..7dc07a220df 100755 --- a/src/csharp/build_packages_dotnetcli.sh +++ b/src/csharp/build_packages_dotnetcli.sh @@ -54,7 +54,7 @@ dotnet pack --configuration Release Grpc.Auth --output ../../../artifacts dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts -nuget pack Grpc.nuspec -Version "1.4.0-dev" -OutputDirectory ../../artifacts -nuget pack Grpc.Tools.nuspec -Version "1.4.0-dev" -OutputDirectory ../../artifacts +nuget pack Grpc.nuspec -Version "1.5.0-dev" -OutputDirectory ../../artifacts +nuget pack Grpc.Tools.nuspec -Version "1.5.0-dev" -OutputDirectory ../../artifacts (cd ../../artifacts && zip csharp_nugets_dotnetcli.zip *.nupkg) diff --git a/src/node/health_check/package.json b/src/node/health_check/package.json index 37c9b7a54f5..0922f54a394 100644 --- a/src/node/health_check/package.json +++ b/src/node/health_check/package.json @@ -1,6 +1,6 @@ { "name": "grpc-health-check", - "version": "1.4.0-dev", + "version": "1.5.0-dev", "author": "Google Inc.", "description": "Health check service for use with gRPC", "repository": { @@ -15,7 +15,7 @@ } ], "dependencies": { - "grpc": "^1.4.0-dev", + "grpc": "^1.5.0-dev", "lodash": "^3.9.3", "google-protobuf": "^3.0.0" }, diff --git a/src/node/tools/package.json b/src/node/tools/package.json index a81aa87f4bb..542d52d48bc 100644 --- a/src/node/tools/package.json +++ b/src/node/tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.4.0-dev", + "version": "1.5.0-dev", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "http://www.grpc.io/", diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec index 2f29058b59d..711814e7fa9 100644 --- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec +++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec @@ -42,7 +42,7 @@ Pod::Spec.new do |s| # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed # before them. s.name = '!ProtoCompiler-gRPCPlugin' - v = '1.4.0-dev' + v = '1.5.0-dev' s.version = v s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.' s.description = <<-DESC diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h index c846f4214c9..cacbce46448 100644 --- a/src/objective-c/GRPCClient/private/version.h +++ b/src/objective-c/GRPCClient/private/version.h @@ -38,4 +38,4 @@ // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.4.0-dev" +#define GRPC_OBJC_VERSION_STRING @"1.5.0-dev" diff --git a/src/php/composer.json b/src/php/composer.json index a4fba7e4f6a..3a97e5fb414 100644 --- a/src/php/composer.json +++ b/src/php/composer.json @@ -2,7 +2,7 @@ "name": "grpc/grpc-dev", "description": "gRPC library for PHP - for Developement use only", "license": "BSD-3-Clause", - "version": "1.4.0", + "version": "1.5.0", "require": { "php": ">=5.5.0", "google/protobuf": "^v3.3.0" diff --git a/src/php/ext/grpc/version.h b/src/php/ext/grpc/version.h index 993ef2de274..303a63ec364 100644 --- a/src/php/ext/grpc/version.h +++ b/src/php/ext/grpc/version.h @@ -35,6 +35,6 @@ #ifndef VERSION_H #define VERSION_H -#define PHP_GRPC_VERSION "1.4.0" +#define PHP_GRPC_VERSION "1.5.0" #endif /* VERSION_H */ diff --git a/src/python/grpcio/grpc/_grpcio_metadata.py b/src/python/grpcio/grpc/_grpcio_metadata.py index a0cb0dd067f..3ae2602d20c 100644 --- a/src/python/grpcio/grpc/_grpcio_metadata.py +++ b/src/python/grpcio/grpc/_grpcio_metadata.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!! -__version__ = """1.4.0.dev0""" +__version__ = """1.5.0.dev0""" diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py index ea4bc7ba207..f5bd29ff85c 100644 --- a/src/python/grpcio/grpc_version.py +++ b/src/python/grpcio/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!! -VERSION='1.4.0.dev0' +VERSION='1.5.0.dev0' diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py index 26aa555e14c..26a83018839 100644 --- a/src/python/grpcio_health_checking/grpc_version.py +++ b/src/python/grpcio_health_checking/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!! -VERSION='1.4.0.dev0' +VERSION='1.5.0.dev0' diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py index 978d6b4011f..f16737df80a 100644 --- a/src/python/grpcio_reflection/grpc_version.py +++ b/src/python/grpcio_reflection/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!! -VERSION='1.4.0.dev0' +VERSION='1.5.0.dev0' diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py index 5f0b0848846..28cf8a8a628 100644 --- a/src/python/grpcio_tests/grpc_version.py +++ b/src/python/grpcio_tests/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!! -VERSION='1.4.0.dev0' +VERSION='1.5.0.dev0' diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb index f30dff335f1..e2e784d19f2 100644 --- a/src/ruby/lib/grpc/version.rb +++ b/src/ruby/lib/grpc/version.rb @@ -29,5 +29,5 @@ # GRPC contains the General RPC module. module GRPC - VERSION = '1.4.0.dev' + VERSION = '1.5.0.dev' end diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb index 1f8d4afb95f..4f74238df79 100644 --- a/src/ruby/tools/version.rb +++ b/src/ruby/tools/version.rb @@ -29,6 +29,6 @@ module GRPC module Tools - VERSION = '1.4.0.dev' + VERSION = '1.5.0.dev' end end diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py index 1f2aa81c850..417722a4d24 100644 --- a/tools/distrib/python/grpcio_tools/grpc_version.py +++ b/tools/distrib/python/grpcio_tools/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!! -VERSION='1.4.0.dev0' +VERSION='1.5.0.dev0' diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 3861bdb85af..23746de1aa5 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.4.0-dev +PROJECT_NUMBER = 1.5.0-dev # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 5bab66c7d6a..52e722f56c9 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.4.0-dev +PROJECT_NUMBER = 1.5.0-dev # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From a9f94e9882e5c9978fb6376d94a7144f53ab1c4b Mon Sep 17 00:00:00 2001 From: Makarand Dharmapurikar Date: Tue, 30 May 2017 15:21:46 -0700 Subject: [PATCH 64/65] s/inline/__inline/ --- test/core/census/intrusive_hash_map_test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/core/census/intrusive_hash_map_test.c b/test/core/census/intrusive_hash_map_test.c index fe8d3a1675a..552546f9a31 100644 --- a/test/core/census/intrusive_hash_map_test.c +++ b/test/core/census/intrusive_hash_map_test.c @@ -49,7 +49,7 @@ static const uint32_t kInitialLog2Size = 4; typedef struct object { uint64_t val; } object; /* Helper function to allocate and initialize object. */ -static inline object *make_new_object(uint64_t val) { +static __inline object *make_new_object(uint64_t val) { object *obj = (object *)gpr_malloc(sizeof(object)); obj->val = val; return obj; @@ -63,7 +63,7 @@ typedef struct ptr_item { /* Helper function that creates a new hash map item. It is up to the user to * free the item that was allocated. */ -static inline ptr_item *make_ptr_item(uint64_t key, uint64_t value) { +static __inline ptr_item *make_ptr_item(uint64_t key, uint64_t value) { ptr_item *new_item = (ptr_item *)gpr_malloc(sizeof(ptr_item)); new_item->IHM_key = key; new_item->IHM_hash_link = NULL; From 7ed4a63512ca58ee608ed3f7fd6c2a6bbd1c2ffc Mon Sep 17 00:00:00 2001 From: Mak Dharma Date: Tue, 30 May 2017 20:04:36 -0700 Subject: [PATCH 65/65] clang-format --- src/core/ext/census/intrusive_hash_map.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/core/ext/census/intrusive_hash_map.c b/src/core/ext/census/intrusive_hash_map.c index d147f23364d..9f56b765e12 100644 --- a/src/core/ext/census/intrusive_hash_map.c +++ b/src/core/ext/census/intrusive_hash_map.c @@ -46,7 +46,7 @@ static const size_t VECTOR_CHUNK_SIZE = (1 << 20) / sizeof(void *); /* Helper functions which return buckets from the chunked vector. */ static __inline void **get_mutable_bucket(const chunked_vector *buckets, - uint32_t index) { + uint32_t index) { if (index < VECTOR_CHUNK_SIZE) { return &buckets->first_[index]; } @@ -54,7 +54,8 @@ static __inline void **get_mutable_bucket(const chunked_vector *buckets, return &buckets->rest_[rest_index][index % VECTOR_CHUNK_SIZE]; } -static __inline void *get_bucket(const chunked_vector *buckets, uint32_t index) { +static __inline void *get_bucket(const chunked_vector *buckets, + uint32_t index) { if (index < VECTOR_CHUNK_SIZE) { return buckets->first_[index]; } @@ -223,8 +224,8 @@ hm_item *intrusive_hash_map_erase(intrusive_hash_map *hash_map, uint64_t key) { * already existed. */ static __inline bool intrusive_hash_map_internal_insert(chunked_vector *buckets, - uint32_t hash_mask, - hm_item *item) { + uint32_t hash_mask, + hm_item *item) { const uint64_t key = item->key; uint32_t index = chunked_vector_hasher(key) & hash_mask; hm_item **slot = (hm_item **)get_mutable_bucket(buckets, index);