diff --git a/.gitignore b/.gitignore index cde82bc3d36..bc324b5f826 100644 --- a/.gitignore +++ b/.gitignore @@ -109,12 +109,14 @@ Podfile.lock # IDE specific folder for JetBrains IDEs .idea/ -# Blaze files +# Bazel files bazel-bin bazel-genfiles bazel-grpc bazel-out bazel-testlogs +bazel_format_virtual_environment/ +tools/bazel-* # Debug output gdb.txt @@ -134,3 +136,11 @@ bm_*.json # cmake build files /cmake/build + +# Visual Studio Code artifacts +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 700c61cceae..00000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "launch", - "name": "Mocha Tests", - "cwd": "${workspaceRoot}", - "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/mocha", - "windows": { - "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/mocha.cmd" - }, - "runtimeArgs": [ - "-u", - "tdd", - "--timeout", - "999999", - "--colors", - "${workspaceRoot}/src/node/test" - ], - "internalConsoleOptions": "openOnSessionStart" - }, - { - "type": "node", - "request": "attach", - "name": "Attach to Process", - "port": 5858 - } - ] -} diff --git a/BUILD b/BUILD index 1735961eb61..f079f9dcba0 100644 --- a/BUILD +++ b/BUILD @@ -74,11 +74,11 @@ config_setting( ) # This should be updated along with build.yaml -g_stands_for = "gandalf" +g_stands_for = "gale" core_version = "7.0.0" -version = "1.21.0-dev" +version = "1.22.0-dev" GPR_PUBLIC_HDRS = [ "include/grpc/support/alloc.h", @@ -141,6 +141,7 @@ GRPCXX_SRCS = [ "src/cpp/server/channel_argument_option.cc", "src/cpp/server/create_default_thread_pool.cc", "src/cpp/server/dynamic_thread_pool.cc", + "src/cpp/server/external_connection_acceptor_impl.cc", "src/cpp/server/health/default_health_check_service.cc", "src/cpp/server/health/health_check_service.cc", "src/cpp/server/health/health_check_service_server_builder_option.cc", @@ -160,6 +161,7 @@ GRPCXX_HDRS = [ "src/cpp/client/create_channel_internal.h", "src/cpp/common/channel_filter.h", "src/cpp/server/dynamic_thread_pool.h", + "src/cpp/server/external_connection_acceptor_impl.h", "src/cpp/server/health/default_health_check_service.h", "src/cpp/server/thread_pool_interface.h", "src/cpp/thread_manager/thread_manager.h", @@ -216,6 +218,7 @@ GRPCXX_PUBLIC_HDRS = [ "include/grpcpp/alarm.h", "include/grpcpp/alarm_impl.h", "include/grpcpp/channel.h", + "include/grpcpp/channel_impl.h", "include/grpcpp/client_context.h", "include/grpcpp/completion_queue.h", "include/grpcpp/create_channel.h", @@ -252,9 +255,11 @@ GRPCXX_PUBLIC_HDRS = [ "include/grpcpp/security/auth_metadata_processor.h", "include/grpcpp/security/auth_metadata_processor_impl.h", "include/grpcpp/security/credentials.h", + "include/grpcpp/security/credentials_impl.h", "include/grpcpp/security/server_credentials.h", "include/grpcpp/security/server_credentials_impl.h", "include/grpcpp/server.h", + "include/grpcpp/server_impl.h", "include/grpcpp/server_builder.h", "include/grpcpp/server_builder_impl.h", "include/grpcpp/server_context.h", @@ -264,6 +269,7 @@ GRPCXX_PUBLIC_HDRS = [ "include/grpcpp/support/async_unary_call.h", "include/grpcpp/support/byte_buffer.h", "include/grpcpp/support/channel_arguments.h", + "include/grpcpp/support/channel_arguments_impl.h", "include/grpcpp/support/client_callback.h", "include/grpcpp/support/client_interceptor.h", "include/grpcpp/support/config.h", @@ -430,6 +436,7 @@ grpc_cc_library( "src/compiler/config.h", "src/compiler/cpp_generator.h", "src/compiler/cpp_generator_helpers.h", + "src/compiler/cpp_plugin.h", "src/compiler/csharp_generator.h", "src/compiler/csharp_generator_helpers.h", "src/compiler/generator_helpers.h", @@ -541,7 +548,6 @@ grpc_cc_library( name = "gpr_base", srcs = [ "src/core/lib/gpr/alloc.cc", - "src/core/lib/gpr/arena.cc", "src/core/lib/gpr/atm.cc", "src/core/lib/gpr/cpu_iphone.cc", "src/core/lib/gpr/cpu_linux.cc", @@ -574,7 +580,9 @@ grpc_cc_library( "src/core/lib/gpr/tmpfile_posix.cc", "src/core/lib/gpr/tmpfile_windows.cc", "src/core/lib/gpr/wrap_memcpy.cc", + "src/core/lib/gprpp/arena.cc", "src/core/lib/gprpp/fork.cc", + "src/core/lib/gprpp/global_config_env.cc", "src/core/lib/gprpp/thd_posix.cc", "src/core/lib/gprpp/thd_windows.cc", "src/core/lib/profiling/basic_timers.cc", @@ -598,7 +606,13 @@ grpc_cc_library( "src/core/lib/gpr/tmpfile.h", "src/core/lib/gpr/useful.h", "src/core/lib/gprpp/abstract.h", + "src/core/lib/gprpp/arena.h", + "src/core/lib/gprpp/atomic.h", "src/core/lib/gprpp/fork.h", + "src/core/lib/gprpp/global_config_custom.h", + "src/core/lib/gprpp/global_config_env.h", + "src/core/lib/gprpp/global_config_generic.h", + "src/core/lib/gprpp/global_config.h", "src/core/lib/gprpp/manual_constructor.h", "src/core/lib/gprpp/map.h", "src/core/lib/gprpp/memory.h", @@ -985,6 +999,7 @@ grpc_cc_library( "src/core/lib/slice/slice_hash_table.h", "src/core/lib/slice/slice_internal.h", "src/core/lib/slice/slice_string_helpers.h", + "src/core/lib/slice/slice_utils.h", "src/core/lib/slice/slice_weak_hash_table.h", "src/core/lib/surface/api_trace.h", "src/core/lib/surface/call.h", @@ -1549,6 +1564,20 @@ grpc_cc_library( ], ) +grpc_cc_library( + name = "grpc_resolver_dns_selection", + srcs = [ + "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc", + ], + hdrs = [ + "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h", + ], + language = "c++", + deps = [ + "grpc_base", + ], +) + grpc_cc_library( name = "grpc_resolver_dns_native", srcs = [ @@ -1558,6 +1587,7 @@ grpc_cc_library( deps = [ "grpc_base", "grpc_client_channel", + "grpc_resolver_dns_selection", ], ) @@ -1566,10 +1596,12 @@ grpc_cc_library( srcs = [ "src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc", + "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc", + "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc", ], @@ -1585,6 +1617,7 @@ grpc_cc_library( deps = [ "grpc_base", "grpc_client_channel", + "grpc_resolver_dns_selection", ], ) @@ -2131,6 +2164,7 @@ grpc_cc_library( "include/grpcpp/impl/codegen/client_interceptor.h", "include/grpcpp/impl/codegen/client_unary_call.h", "include/grpcpp/impl/codegen/completion_queue.h", + "include/grpcpp/impl/codegen/completion_queue_impl.h", "include/grpcpp/impl/codegen/completion_queue_tag.h", "include/grpcpp/impl/codegen/config.h", "include/grpcpp/impl/codegen/core_codegen_interface.h", diff --git a/BUILD.gn b/BUILD.gn index 10b0f1a7fdd..c0ff5dc2417 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -131,7 +131,6 @@ config("grpc_config") { "include/grpc/support/time.h", "src/core/lib/gpr/alloc.cc", "src/core/lib/gpr/alloc.h", - "src/core/lib/gpr/arena.cc", "src/core/lib/gpr/arena.h", "src/core/lib/gpr/atm.cc", "src/core/lib/gpr/cpu_iphone.cc", @@ -180,9 +179,16 @@ config("grpc_config") { "src/core/lib/gpr/useful.h", "src/core/lib/gpr/wrap_memcpy.cc", "src/core/lib/gprpp/abstract.h", + "src/core/lib/gprpp/arena.cc", + "src/core/lib/gprpp/arena.h", "src/core/lib/gprpp/atomic.h", "src/core/lib/gprpp/fork.cc", "src/core/lib/gprpp/fork.h", + "src/core/lib/gprpp/global_config.h", + "src/core/lib/gprpp/global_config_custom.h", + "src/core/lib/gprpp/global_config_env.cc", + "src/core/lib/gprpp/global_config_env.h", + "src/core/lib/gprpp/global_config_generic.h", "src/core/lib/gprpp/manual_constructor.h", "src/core/lib/gprpp/map.h", "src/core/lib/gprpp/memory.h", @@ -309,13 +315,17 @@ config("grpc_config") { "src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h", + "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc", + "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc", + "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc", + "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h", "src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc", "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc", "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h", @@ -481,18 +491,24 @@ config("grpc_config") { "src/core/lib/iomgr/buffer_list.h", "src/core/lib/iomgr/call_combiner.cc", "src/core/lib/iomgr/call_combiner.h", + "src/core/lib/iomgr/cfstream_handle.cc", + "src/core/lib/iomgr/cfstream_handle.h", "src/core/lib/iomgr/closure.h", "src/core/lib/iomgr/combiner.cc", "src/core/lib/iomgr/combiner.h", "src/core/lib/iomgr/dynamic_annotations.h", "src/core/lib/iomgr/endpoint.cc", "src/core/lib/iomgr/endpoint.h", + "src/core/lib/iomgr/endpoint_cfstream.cc", + "src/core/lib/iomgr/endpoint_cfstream.h", "src/core/lib/iomgr/endpoint_pair.h", "src/core/lib/iomgr/endpoint_pair_posix.cc", "src/core/lib/iomgr/endpoint_pair_uv.cc", "src/core/lib/iomgr/endpoint_pair_windows.cc", "src/core/lib/iomgr/error.cc", "src/core/lib/iomgr/error.h", + "src/core/lib/iomgr/error_cfstream.cc", + "src/core/lib/iomgr/error_cfstream.h", "src/core/lib/iomgr/error_internal.h", "src/core/lib/iomgr/ev_epoll1_linux.cc", "src/core/lib/iomgr/ev_epoll1_linux.h", @@ -528,6 +544,7 @@ config("grpc_config") { "src/core/lib/iomgr/iomgr_internal.h", "src/core/lib/iomgr/iomgr_posix.cc", "src/core/lib/iomgr/iomgr_posix.h", + "src/core/lib/iomgr/iomgr_posix_cfstream.cc", "src/core/lib/iomgr/iomgr_uv.cc", "src/core/lib/iomgr/iomgr_windows.cc", "src/core/lib/iomgr/is_epollexclusive_available.cc", @@ -583,6 +600,7 @@ config("grpc_config") { "src/core/lib/iomgr/sys_epoll_wrapper.h", "src/core/lib/iomgr/tcp_client.cc", "src/core/lib/iomgr/tcp_client.h", + "src/core/lib/iomgr/tcp_client_cfstream.cc", "src/core/lib/iomgr/tcp_client_custom.cc", "src/core/lib/iomgr/tcp_client_posix.cc", "src/core/lib/iomgr/tcp_client_posix.h", @@ -719,6 +737,7 @@ config("grpc_config") { "src/core/lib/slice/slice_internal.h", "src/core/lib/slice/slice_string_helpers.cc", "src/core/lib/slice/slice_string_helpers.h", + "src/core/lib/slice/slice_utils.h", "src/core/lib/slice/slice_weak_hash_table.h", "src/core/lib/surface/api_trace.cc", "src/core/lib/surface/api_trace.h", @@ -1005,6 +1024,7 @@ config("grpc_config") { "include/grpcpp/alarm.h", "include/grpcpp/alarm_impl.h", "include/grpcpp/channel.h", + "include/grpcpp/channel_impl.h", "include/grpcpp/client_context.h", "include/grpcpp/completion_queue.h", "include/grpcpp/create_channel.h", @@ -1036,6 +1056,7 @@ config("grpc_config") { "include/grpcpp/impl/codegen/client_interceptor.h", "include/grpcpp/impl/codegen/client_unary_call.h", "include/grpcpp/impl/codegen/completion_queue.h", + "include/grpcpp/impl/codegen/completion_queue_impl.h", "include/grpcpp/impl/codegen/completion_queue_tag.h", "include/grpcpp/impl/codegen/config.h", "include/grpcpp/impl/codegen/config_protobuf.h", @@ -1087,18 +1108,21 @@ config("grpc_config") { "include/grpcpp/security/auth_metadata_processor.h", "include/grpcpp/security/auth_metadata_processor_impl.h", "include/grpcpp/security/credentials.h", + "include/grpcpp/security/credentials_impl.h", "include/grpcpp/security/server_credentials.h", "include/grpcpp/security/server_credentials_impl.h", "include/grpcpp/server.h", "include/grpcpp/server_builder.h", "include/grpcpp/server_builder_impl.h", "include/grpcpp/server_context.h", + "include/grpcpp/server_impl.h", "include/grpcpp/server_posix.h", "include/grpcpp/server_posix_impl.h", "include/grpcpp/support/async_stream.h", "include/grpcpp/support/async_unary_call.h", "include/grpcpp/support/byte_buffer.h", "include/grpcpp/support/channel_arguments.h", + "include/grpcpp/support/channel_arguments_impl.h", "include/grpcpp/support/client_callback.h", "include/grpcpp/support/client_interceptor.h", "include/grpcpp/support/config.h", @@ -1157,9 +1181,14 @@ config("grpc_config") { "src/core/lib/gpr/tmpfile.h", "src/core/lib/gpr/useful.h", "src/core/lib/gprpp/abstract.h", + "src/core/lib/gprpp/arena.h", "src/core/lib/gprpp/atomic.h", "src/core/lib/gprpp/debug_location.h", "src/core/lib/gprpp/fork.h", + "src/core/lib/gprpp/global_config.h", + "src/core/lib/gprpp/global_config_custom.h", + "src/core/lib/gprpp/global_config_env.h", + "src/core/lib/gprpp/global_config_generic.h", "src/core/lib/gprpp/inlined_vector.h", "src/core/lib/gprpp/manual_constructor.h", "src/core/lib/gprpp/map.h", @@ -1177,12 +1206,15 @@ config("grpc_config") { "src/core/lib/iomgr/block_annotate.h", "src/core/lib/iomgr/buffer_list.h", "src/core/lib/iomgr/call_combiner.h", + "src/core/lib/iomgr/cfstream_handle.h", "src/core/lib/iomgr/closure.h", "src/core/lib/iomgr/combiner.h", "src/core/lib/iomgr/dynamic_annotations.h", "src/core/lib/iomgr/endpoint.h", + "src/core/lib/iomgr/endpoint_cfstream.h", "src/core/lib/iomgr/endpoint_pair.h", "src/core/lib/iomgr/error.h", + "src/core/lib/iomgr/error_cfstream.h", "src/core/lib/iomgr/error_internal.h", "src/core/lib/iomgr/ev_epoll1_linux.h", "src/core/lib/iomgr/ev_epollex_linux.h", @@ -1250,6 +1282,7 @@ config("grpc_config") { "src/core/lib/slice/slice_hash_table.h", "src/core/lib/slice/slice_internal.h", "src/core/lib/slice/slice_string_helpers.h", + "src/core/lib/slice/slice_utils.h", "src/core/lib/slice/slice_weak_hash_table.h", "src/core/lib/surface/api_trace.h", "src/core/lib/surface/call.h", @@ -1311,6 +1344,8 @@ config("grpc_config") { "src/cpp/server/create_default_thread_pool.cc", "src/cpp/server/dynamic_thread_pool.cc", "src/cpp/server/dynamic_thread_pool.h", + "src/cpp/server/external_connection_acceptor_impl.cc", + "src/cpp/server/external_connection_acceptor_impl.h", "src/cpp/server/health/default_health_check_service.cc", "src/cpp/server/health/default_health_check_service.h", "src/cpp/server/health/health_check_service.cc", diff --git a/CMakeLists.txt b/CMakeLists.txt index 0edd7fd54ee..2f31f21702c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ cmake_minimum_required(VERSION 2.8) set(PACKAGE_NAME "grpc") -set(PACKAGE_VERSION "1.21.0-dev") +set(PACKAGE_VERSION "1.22.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/") @@ -556,6 +556,12 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) add_dependencies(buildtests_cxx bm_call_create) endif() if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) +add_dependencies(buildtests_cxx bm_callback_streaming_ping_pong) +endif() +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) +add_dependencies(buildtests_cxx bm_callback_unary_ping_pong) +endif() +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) add_dependencies(buildtests_cxx bm_channel) endif() if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) @@ -629,6 +635,8 @@ add_dependencies(buildtests_cxx error_details_test) add_dependencies(buildtests_cxx exception_test) add_dependencies(buildtests_cxx filter_end2end_test) add_dependencies(buildtests_cxx generic_end2end_test) +add_dependencies(buildtests_cxx global_config_env_test) +add_dependencies(buildtests_cxx global_config_test) add_dependencies(buildtests_cxx golden_file_test) add_dependencies(buildtests_cxx grpc_alts_credentials_options_test) add_dependencies(buildtests_cxx grpc_cli) @@ -668,6 +676,7 @@ add_dependencies(buildtests_cxx nonblocking_test) add_dependencies(buildtests_cxx noop-benchmark) add_dependencies(buildtests_cxx optional_test) add_dependencies(buildtests_cxx orphanable_test) +add_dependencies(buildtests_cxx port_sharing_end2end_test) add_dependencies(buildtests_cxx proto_server_reflection_test) add_dependencies(buildtests_cxx proto_utils_test) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) @@ -701,6 +710,7 @@ add_dependencies(buildtests_cxx server_crash_test_client) add_dependencies(buildtests_cxx server_early_return_test) add_dependencies(buildtests_cxx server_interceptors_end2end_test) add_dependencies(buildtests_cxx server_request_call_test) +add_dependencies(buildtests_cxx service_config_end2end_test) add_dependencies(buildtests_cxx service_config_test) add_dependencies(buildtests_cxx shutdown_test) add_dependencies(buildtests_cxx slice_hash_table_test) @@ -839,7 +849,6 @@ endif (gRPC_BUILD_TESTS) add_library(gpr src/core/lib/gpr/alloc.cc - src/core/lib/gpr/arena.cc src/core/lib/gpr/atm.cc src/core/lib/gpr/cpu_iphone.cc src/core/lib/gpr/cpu_linux.cc @@ -872,7 +881,9 @@ add_library(gpr src/core/lib/gpr/tmpfile_posix.cc src/core/lib/gpr/tmpfile_windows.cc src/core/lib/gpr/wrap_memcpy.cc + src/core/lib/gprpp/arena.cc src/core/lib/gprpp/fork.cc + src/core/lib/gprpp/global_config_env.cc src/core/lib/gprpp/thd_posix.cc src/core/lib/gprpp/thd_windows.cc src/core/lib/profiling/basic_timers.cc @@ -997,12 +1008,15 @@ add_library(grpc src/core/lib/http/parser.cc src/core/lib/iomgr/buffer_list.cc src/core/lib/iomgr/call_combiner.cc + src/core/lib/iomgr/cfstream_handle.cc src/core/lib/iomgr/combiner.cc src/core/lib/iomgr/endpoint.cc + src/core/lib/iomgr/endpoint_cfstream.cc src/core/lib/iomgr/endpoint_pair_posix.cc src/core/lib/iomgr/endpoint_pair_uv.cc src/core/lib/iomgr/endpoint_pair_windows.cc src/core/lib/iomgr/error.cc + src/core/lib/iomgr/error_cfstream.cc src/core/lib/iomgr/ev_epoll1_linux.cc src/core/lib/iomgr/ev_epollex_linux.cc src/core/lib/iomgr/ev_poll_posix.cc @@ -1023,6 +1037,7 @@ add_library(grpc src/core/lib/iomgr/iomgr_custom.cc src/core/lib/iomgr/iomgr_internal.cc src/core/lib/iomgr/iomgr_posix.cc + src/core/lib/iomgr/iomgr_posix_cfstream.cc src/core/lib/iomgr/iomgr_uv.cc src/core/lib/iomgr/iomgr_windows.cc src/core/lib/iomgr/is_epollexclusive_available.cc @@ -1051,6 +1066,7 @@ add_library(grpc src/core/lib/iomgr/socket_utils_windows.cc src/core/lib/iomgr/socket_windows.cc src/core/lib/iomgr/tcp_client.cc + src/core/lib/iomgr/tcp_client_cfstream.cc src/core/lib/iomgr/tcp_client_custom.cc src/core/lib/iomgr/tcp_client_posix.cc src/core/lib/iomgr/tcp_client_windows.cc @@ -1284,12 +1300,15 @@ add_library(grpc src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc + src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc + src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc + src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc src/core/ext/filters/census/grpc_context.cc @@ -1424,12 +1443,15 @@ add_library(grpc_cronet src/core/lib/http/parser.cc src/core/lib/iomgr/buffer_list.cc src/core/lib/iomgr/call_combiner.cc + src/core/lib/iomgr/cfstream_handle.cc src/core/lib/iomgr/combiner.cc src/core/lib/iomgr/endpoint.cc + src/core/lib/iomgr/endpoint_cfstream.cc src/core/lib/iomgr/endpoint_pair_posix.cc src/core/lib/iomgr/endpoint_pair_uv.cc src/core/lib/iomgr/endpoint_pair_windows.cc src/core/lib/iomgr/error.cc + src/core/lib/iomgr/error_cfstream.cc src/core/lib/iomgr/ev_epoll1_linux.cc src/core/lib/iomgr/ev_epollex_linux.cc src/core/lib/iomgr/ev_poll_posix.cc @@ -1450,6 +1472,7 @@ add_library(grpc_cronet src/core/lib/iomgr/iomgr_custom.cc src/core/lib/iomgr/iomgr_internal.cc src/core/lib/iomgr/iomgr_posix.cc + src/core/lib/iomgr/iomgr_posix_cfstream.cc src/core/lib/iomgr/iomgr_uv.cc src/core/lib/iomgr/iomgr_windows.cc src/core/lib/iomgr/is_epollexclusive_available.cc @@ -1478,6 +1501,7 @@ add_library(grpc_cronet src/core/lib/iomgr/socket_utils_windows.cc src/core/lib/iomgr/socket_windows.cc src/core/lib/iomgr/tcp_client.cc + src/core/lib/iomgr/tcp_client_cfstream.cc src/core/lib/iomgr/tcp_client_custom.cc src/core/lib/iomgr/tcp_client_posix.cc src/core/lib/iomgr/tcp_client_windows.cc @@ -1836,12 +1860,15 @@ add_library(grpc_test_util src/core/lib/http/parser.cc src/core/lib/iomgr/buffer_list.cc src/core/lib/iomgr/call_combiner.cc + src/core/lib/iomgr/cfstream_handle.cc src/core/lib/iomgr/combiner.cc src/core/lib/iomgr/endpoint.cc + src/core/lib/iomgr/endpoint_cfstream.cc src/core/lib/iomgr/endpoint_pair_posix.cc src/core/lib/iomgr/endpoint_pair_uv.cc src/core/lib/iomgr/endpoint_pair_windows.cc src/core/lib/iomgr/error.cc + src/core/lib/iomgr/error_cfstream.cc src/core/lib/iomgr/ev_epoll1_linux.cc src/core/lib/iomgr/ev_epollex_linux.cc src/core/lib/iomgr/ev_poll_posix.cc @@ -1862,6 +1889,7 @@ add_library(grpc_test_util src/core/lib/iomgr/iomgr_custom.cc src/core/lib/iomgr/iomgr_internal.cc src/core/lib/iomgr/iomgr_posix.cc + src/core/lib/iomgr/iomgr_posix_cfstream.cc src/core/lib/iomgr/iomgr_uv.cc src/core/lib/iomgr/iomgr_windows.cc src/core/lib/iomgr/is_epollexclusive_available.cc @@ -1890,6 +1918,7 @@ add_library(grpc_test_util src/core/lib/iomgr/socket_utils_windows.cc src/core/lib/iomgr/socket_windows.cc src/core/lib/iomgr/tcp_client.cc + src/core/lib/iomgr/tcp_client_cfstream.cc src/core/lib/iomgr/tcp_client_custom.cc src/core/lib/iomgr/tcp_client_posix.cc src/core/lib/iomgr/tcp_client_windows.cc @@ -2161,12 +2190,15 @@ add_library(grpc_test_util_unsecure src/core/lib/http/parser.cc src/core/lib/iomgr/buffer_list.cc src/core/lib/iomgr/call_combiner.cc + src/core/lib/iomgr/cfstream_handle.cc src/core/lib/iomgr/combiner.cc src/core/lib/iomgr/endpoint.cc + src/core/lib/iomgr/endpoint_cfstream.cc src/core/lib/iomgr/endpoint_pair_posix.cc src/core/lib/iomgr/endpoint_pair_uv.cc src/core/lib/iomgr/endpoint_pair_windows.cc src/core/lib/iomgr/error.cc + src/core/lib/iomgr/error_cfstream.cc src/core/lib/iomgr/ev_epoll1_linux.cc src/core/lib/iomgr/ev_epollex_linux.cc src/core/lib/iomgr/ev_poll_posix.cc @@ -2187,6 +2219,7 @@ add_library(grpc_test_util_unsecure src/core/lib/iomgr/iomgr_custom.cc src/core/lib/iomgr/iomgr_internal.cc src/core/lib/iomgr/iomgr_posix.cc + src/core/lib/iomgr/iomgr_posix_cfstream.cc src/core/lib/iomgr/iomgr_uv.cc src/core/lib/iomgr/iomgr_windows.cc src/core/lib/iomgr/is_epollexclusive_available.cc @@ -2215,6 +2248,7 @@ add_library(grpc_test_util_unsecure src/core/lib/iomgr/socket_utils_windows.cc src/core/lib/iomgr/socket_windows.cc src/core/lib/iomgr/tcp_client.cc + src/core/lib/iomgr/tcp_client_cfstream.cc src/core/lib/iomgr/tcp_client_custom.cc src/core/lib/iomgr/tcp_client_posix.cc src/core/lib/iomgr/tcp_client_windows.cc @@ -2462,12 +2496,15 @@ add_library(grpc_unsecure src/core/lib/http/parser.cc src/core/lib/iomgr/buffer_list.cc src/core/lib/iomgr/call_combiner.cc + src/core/lib/iomgr/cfstream_handle.cc src/core/lib/iomgr/combiner.cc src/core/lib/iomgr/endpoint.cc + src/core/lib/iomgr/endpoint_cfstream.cc src/core/lib/iomgr/endpoint_pair_posix.cc src/core/lib/iomgr/endpoint_pair_uv.cc src/core/lib/iomgr/endpoint_pair_windows.cc src/core/lib/iomgr/error.cc + src/core/lib/iomgr/error_cfstream.cc src/core/lib/iomgr/ev_epoll1_linux.cc src/core/lib/iomgr/ev_epollex_linux.cc src/core/lib/iomgr/ev_poll_posix.cc @@ -2488,6 +2525,7 @@ add_library(grpc_unsecure src/core/lib/iomgr/iomgr_custom.cc src/core/lib/iomgr/iomgr_internal.cc src/core/lib/iomgr/iomgr_posix.cc + src/core/lib/iomgr/iomgr_posix_cfstream.cc src/core/lib/iomgr/iomgr_uv.cc src/core/lib/iomgr/iomgr_windows.cc src/core/lib/iomgr/is_epollexclusive_available.cc @@ -2516,6 +2554,7 @@ add_library(grpc_unsecure src/core/lib/iomgr/socket_utils_windows.cc src/core/lib/iomgr/socket_windows.cc src/core/lib/iomgr/tcp_client.cc + src/core/lib/iomgr/tcp_client_cfstream.cc src/core/lib/iomgr/tcp_client_custom.cc src/core/lib/iomgr/tcp_client_posix.cc src/core/lib/iomgr/tcp_client_windows.cc @@ -2657,12 +2696,15 @@ add_library(grpc_unsecure src/core/ext/transport/inproc/inproc_transport.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc + src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc + src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc + src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc @@ -2871,6 +2913,110 @@ target_link_libraries(test_tcp_server ) +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) + +if (gRPC_BUILD_CODEGEN) +add_library(bm_callback_test_service_impl + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.pb.cc + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.grpc.pb.cc + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.pb.h + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.grpc.pb.h + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_mock.grpc.pb.h + test/cpp/microbenchmarks/callback_test_service.cc +) + +if(WIN32 AND MSVC) + set_target_properties(bm_callback_test_service_impl PROPERTIES COMPILE_PDB_NAME "bm_callback_test_service_impl" + COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" + ) + if (gRPC_INSTALL) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/bm_callback_test_service_impl.pdb + DESTINATION ${gRPC_INSTALL_LIBDIR} OPTIONAL + ) + endif() +endif() + +protobuf_generate_grpc_cpp( + src/proto/grpc/testing/echo.proto +) + +target_include_directories(bm_callback_test_service_impl + PUBLIC $ $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${_gRPC_SSL_INCLUDE_DIR} + PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR} + PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR} + PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR} + PRIVATE ${_gRPC_CARES_INCLUDE_DIR} + PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR} + PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR} + 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} +) +target_link_libraries(bm_callback_test_service_impl + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc_benchmark + ${_gRPC_BENCHMARK_LIBRARIES} + grpc++_test_util_unsecure + grpc_test_util_unsecure + grpc++_unsecure + grpc_unsecure + gpr + grpc++_test_config + ${_gRPC_GFLAGS_LIBRARIES} +) + +endif (gRPC_BUILD_CODEGEN) + +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) + +add_library(dns_test_util + test/cpp/naming/dns_test_util.cc +) + +if(WIN32 AND MSVC) + set_target_properties(dns_test_util PROPERTIES COMPILE_PDB_NAME "dns_test_util" + COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" + ) + if (gRPC_INSTALL) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dns_test_util.pdb + DESTINATION ${gRPC_INSTALL_LIBDIR} OPTIONAL + ) + endif() +endif() + + +target_include_directories(dns_test_util + PUBLIC $ $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${_gRPC_SSL_INCLUDE_DIR} + PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR} + PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR} + PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR} + PRIVATE ${_gRPC_CARES_INCLUDE_DIR} + PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR} + PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR} + 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} +) +target_link_libraries(dns_test_util + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + ${_gRPC_GFLAGS_LIBRARIES} +) + + endif (gRPC_BUILD_TESTS) add_library(grpc++ @@ -2902,6 +3048,7 @@ add_library(grpc++ src/cpp/server/channel_argument_option.cc src/cpp/server/create_default_thread_pool.cc src/cpp/server/dynamic_thread_pool.cc + src/cpp/server/external_connection_acceptor_impl.cc src/cpp/server/health/default_health_check_service.cc src/cpp/server/health/health_check_service.cc src/cpp/server/health/health_check_service_server_builder_option.cc @@ -3005,6 +3152,7 @@ foreach(_hdr include/grpcpp/alarm.h include/grpcpp/alarm_impl.h include/grpcpp/channel.h + include/grpcpp/channel_impl.h include/grpcpp/client_context.h include/grpcpp/completion_queue.h include/grpcpp/create_channel.h @@ -3039,18 +3187,21 @@ foreach(_hdr include/grpcpp/security/auth_metadata_processor.h include/grpcpp/security/auth_metadata_processor_impl.h include/grpcpp/security/credentials.h + include/grpcpp/security/credentials_impl.h include/grpcpp/security/server_credentials.h include/grpcpp/security/server_credentials_impl.h include/grpcpp/server.h include/grpcpp/server_builder.h include/grpcpp/server_builder_impl.h include/grpcpp/server_context.h + include/grpcpp/server_impl.h include/grpcpp/server_posix.h include/grpcpp/server_posix_impl.h include/grpcpp/support/async_stream.h include/grpcpp/support/async_unary_call.h include/grpcpp/support/byte_buffer.h include/grpcpp/support/channel_arguments.h + include/grpcpp/support/channel_arguments_impl.h include/grpcpp/support/client_callback.h include/grpcpp/support/client_interceptor.h include/grpcpp/support/config.h @@ -3163,6 +3314,7 @@ foreach(_hdr include/grpcpp/impl/codegen/client_interceptor.h include/grpcpp/impl/codegen/client_unary_call.h include/grpcpp/impl/codegen/completion_queue.h + include/grpcpp/impl/codegen/completion_queue_impl.h include/grpcpp/impl/codegen/completion_queue_tag.h include/grpcpp/impl/codegen/config.h include/grpcpp/impl/codegen/core_codegen_interface.h @@ -3293,6 +3445,7 @@ add_library(grpc++_cronet src/cpp/server/channel_argument_option.cc src/cpp/server/create_default_thread_pool.cc src/cpp/server/dynamic_thread_pool.cc + src/cpp/server/external_connection_acceptor_impl.cc src/cpp/server/health/default_health_check_service.cc src/cpp/server/health/health_check_service.cc src/cpp/server/health/health_check_service_server_builder_option.cc @@ -3364,12 +3517,15 @@ add_library(grpc++_cronet src/core/lib/http/parser.cc src/core/lib/iomgr/buffer_list.cc src/core/lib/iomgr/call_combiner.cc + src/core/lib/iomgr/cfstream_handle.cc src/core/lib/iomgr/combiner.cc src/core/lib/iomgr/endpoint.cc + src/core/lib/iomgr/endpoint_cfstream.cc src/core/lib/iomgr/endpoint_pair_posix.cc src/core/lib/iomgr/endpoint_pair_uv.cc src/core/lib/iomgr/endpoint_pair_windows.cc src/core/lib/iomgr/error.cc + src/core/lib/iomgr/error_cfstream.cc src/core/lib/iomgr/ev_epoll1_linux.cc src/core/lib/iomgr/ev_epollex_linux.cc src/core/lib/iomgr/ev_poll_posix.cc @@ -3390,6 +3546,7 @@ add_library(grpc++_cronet src/core/lib/iomgr/iomgr_custom.cc src/core/lib/iomgr/iomgr_internal.cc src/core/lib/iomgr/iomgr_posix.cc + src/core/lib/iomgr/iomgr_posix_cfstream.cc src/core/lib/iomgr/iomgr_uv.cc src/core/lib/iomgr/iomgr_windows.cc src/core/lib/iomgr/is_epollexclusive_available.cc @@ -3418,6 +3575,7 @@ add_library(grpc++_cronet src/core/lib/iomgr/socket_utils_windows.cc src/core/lib/iomgr/socket_windows.cc src/core/lib/iomgr/tcp_client.cc + src/core/lib/iomgr/tcp_client_cfstream.cc src/core/lib/iomgr/tcp_client_custom.cc src/core/lib/iomgr/tcp_client_posix.cc src/core/lib/iomgr/tcp_client_windows.cc @@ -3611,6 +3769,7 @@ foreach(_hdr include/grpcpp/alarm.h include/grpcpp/alarm_impl.h include/grpcpp/channel.h + include/grpcpp/channel_impl.h include/grpcpp/client_context.h include/grpcpp/completion_queue.h include/grpcpp/create_channel.h @@ -3645,18 +3804,21 @@ foreach(_hdr include/grpcpp/security/auth_metadata_processor.h include/grpcpp/security/auth_metadata_processor_impl.h include/grpcpp/security/credentials.h + include/grpcpp/security/credentials_impl.h include/grpcpp/security/server_credentials.h include/grpcpp/security/server_credentials_impl.h include/grpcpp/server.h include/grpcpp/server_builder.h include/grpcpp/server_builder_impl.h include/grpcpp/server_context.h + include/grpcpp/server_impl.h include/grpcpp/server_posix.h include/grpcpp/server_posix_impl.h include/grpcpp/support/async_stream.h include/grpcpp/support/async_unary_call.h include/grpcpp/support/byte_buffer.h include/grpcpp/support/channel_arguments.h + include/grpcpp/support/channel_arguments_impl.h include/grpcpp/support/client_callback.h include/grpcpp/support/client_interceptor.h include/grpcpp/support/config.h @@ -3769,6 +3931,7 @@ foreach(_hdr include/grpcpp/impl/codegen/client_interceptor.h include/grpcpp/impl/codegen/client_unary_call.h include/grpcpp/impl/codegen/completion_queue.h + include/grpcpp/impl/codegen/completion_queue_impl.h include/grpcpp/impl/codegen/completion_queue_tag.h include/grpcpp/impl/codegen/config.h include/grpcpp/impl/codegen/core_codegen_interface.h @@ -4203,6 +4366,7 @@ foreach(_hdr include/grpcpp/impl/codegen/client_interceptor.h include/grpcpp/impl/codegen/client_unary_call.h include/grpcpp/impl/codegen/completion_queue.h + include/grpcpp/impl/codegen/completion_queue_impl.h include/grpcpp/impl/codegen/completion_queue_tag.h include/grpcpp/impl/codegen/config.h include/grpcpp/impl/codegen/core_codegen_interface.h @@ -4401,6 +4565,7 @@ foreach(_hdr include/grpcpp/impl/codegen/client_interceptor.h include/grpcpp/impl/codegen/client_unary_call.h include/grpcpp/impl/codegen/completion_queue.h + include/grpcpp/impl/codegen/completion_queue_impl.h include/grpcpp/impl/codegen/completion_queue_tag.h include/grpcpp/impl/codegen/config.h include/grpcpp/impl/codegen/core_codegen_interface.h @@ -4492,6 +4657,7 @@ add_library(grpc++_unsecure src/cpp/server/channel_argument_option.cc src/cpp/server/create_default_thread_pool.cc src/cpp/server/dynamic_thread_pool.cc + src/cpp/server/external_connection_acceptor_impl.cc src/cpp/server/health/default_health_check_service.cc src/cpp/server/health/health_check_service.cc src/cpp/server/health/health_check_service_server_builder_option.cc @@ -4594,6 +4760,7 @@ foreach(_hdr include/grpcpp/alarm.h include/grpcpp/alarm_impl.h include/grpcpp/channel.h + include/grpcpp/channel_impl.h include/grpcpp/client_context.h include/grpcpp/completion_queue.h include/grpcpp/create_channel.h @@ -4628,18 +4795,21 @@ foreach(_hdr include/grpcpp/security/auth_metadata_processor.h include/grpcpp/security/auth_metadata_processor_impl.h include/grpcpp/security/credentials.h + include/grpcpp/security/credentials_impl.h include/grpcpp/security/server_credentials.h include/grpcpp/security/server_credentials_impl.h include/grpcpp/server.h include/grpcpp/server_builder.h include/grpcpp/server_builder_impl.h include/grpcpp/server_context.h + include/grpcpp/server_impl.h include/grpcpp/server_posix.h include/grpcpp/server_posix_impl.h include/grpcpp/support/async_stream.h include/grpcpp/support/async_unary_call.h include/grpcpp/support/byte_buffer.h include/grpcpp/support/channel_arguments.h + include/grpcpp/support/channel_arguments_impl.h include/grpcpp/support/client_callback.h include/grpcpp/support/client_interceptor.h include/grpcpp/support/config.h @@ -4752,6 +4922,7 @@ foreach(_hdr include/grpcpp/impl/codegen/client_interceptor.h include/grpcpp/impl/codegen/client_unary_call.h include/grpcpp/impl/codegen/completion_queue.h + include/grpcpp/impl/codegen/completion_queue_impl.h include/grpcpp/impl/codegen/completion_queue_tag.h include/grpcpp/impl/codegen/config.h include/grpcpp/impl/codegen/core_codegen_interface.h @@ -11449,6 +11620,98 @@ target_link_libraries(bm_call_create ) +endif() +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) + +add_executable(bm_callback_streaming_ping_pong + test/cpp/microbenchmarks/bm_callback_streaming_ping_pong.cc + third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc +) + + +target_include_directories(bm_callback_streaming_ping_pong + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + PRIVATE ${_gRPC_SSL_INCLUDE_DIR} + PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR} + PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR} + PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR} + PRIVATE ${_gRPC_CARES_INCLUDE_DIR} + PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR} + PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR} + 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} +) + +target_link_libraries(bm_callback_streaming_ping_pong + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc_benchmark + ${_gRPC_BENCHMARK_LIBRARIES} + grpc++_test_util_unsecure + grpc_test_util_unsecure + grpc++_unsecure + grpc_unsecure + gpr + grpc++_test_config + bm_callback_test_service_impl + ${_gRPC_GFLAGS_LIBRARIES} +) + + +endif() +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) + +add_executable(bm_callback_unary_ping_pong + test/cpp/microbenchmarks/bm_callback_unary_ping_pong.cc + third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc +) + + +target_include_directories(bm_callback_unary_ping_pong + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + PRIVATE ${_gRPC_SSL_INCLUDE_DIR} + PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR} + PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR} + PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR} + PRIVATE ${_gRPC_CARES_INCLUDE_DIR} + PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR} + PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR} + 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} +) + +target_link_libraries(bm_callback_unary_ping_pong + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc_benchmark + ${_gRPC_BENCHMARK_LIBRARIES} + grpc++_test_util_unsecure + grpc_test_util_unsecure + grpc++_unsecure + grpc_unsecure + gpr + grpc++_test_config + bm_callback_test_service_impl + ${_gRPC_GFLAGS_LIBRARIES} +) + + endif() endif (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS) @@ -12690,6 +12953,7 @@ target_include_directories(client_crash_test_server target_link_libraries(client_crash_test_server ${_gRPC_PROTOBUF_LIBRARIES} ${_gRPC_ALLTARGETS_LIBRARIES} + grpc++_test_config grpc++_test_util grpc_test_util grpc++ @@ -13391,6 +13655,80 @@ target_link_libraries(generic_end2end_test ) +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) + +add_executable(global_config_env_test + test/core/gprpp/global_config_env_test.cc + third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc +) + + +target_include_directories(global_config_env_test + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + PRIVATE ${_gRPC_SSL_INCLUDE_DIR} + PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR} + PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR} + PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR} + PRIVATE ${_gRPC_CARES_INCLUDE_DIR} + PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR} + PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR} + 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} +) + +target_link_libraries(global_config_env_test + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + gpr + grpc_test_util_unsecure + ${_gRPC_GFLAGS_LIBRARIES} +) + + +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) + +add_executable(global_config_test + test/core/gprpp/global_config_test.cc + third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc +) + + +target_include_directories(global_config_test + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + PRIVATE ${_gRPC_SSL_INCLUDE_DIR} + PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR} + PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR} + PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR} + PRIVATE ${_gRPC_CARES_INCLUDE_DIR} + PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR} + PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR} + 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} +) + +target_link_libraries(global_config_test + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + gpr + grpc_test_util_unsecure + ${_gRPC_GFLAGS_LIBRARIES} +) + + endif (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS) @@ -13429,6 +13767,7 @@ target_include_directories(golden_file_test target_link_libraries(golden_file_test ${_gRPC_PROTOBUF_LIBRARIES} ${_gRPC_ALLTARGETS_LIBRARIES} + grpc++_test_config grpc++ grpc gpr @@ -14790,6 +15129,47 @@ target_link_libraries(orphanable_test ) +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) + +add_executable(port_sharing_end2end_test + test/cpp/end2end/port_sharing_end2end_test.cc + third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc +) + + +target_include_directories(port_sharing_end2end_test + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + PRIVATE ${_gRPC_SSL_INCLUDE_DIR} + PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR} + PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR} + PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR} + PRIVATE ${_gRPC_CARES_INCLUDE_DIR} + PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR} + PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR} + 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} +) + +target_link_libraries(port_sharing_end2end_test + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + test_tcp_server + grpc++_test_util + grpc_test_util + grpc++ + grpc + gpr + ${_gRPC_GFLAGS_LIBRARIES} +) + + endif (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS) @@ -15673,6 +16053,7 @@ target_include_directories(server_crash_test_client target_link_libraries(server_crash_test_client ${_gRPC_PROTOBUF_LIBRARIES} ${_gRPC_ALLTARGETS_LIBRARIES} + grpc++_test_config grpc++_test_util grpc_test_util grpc++ @@ -15817,6 +16198,46 @@ target_link_libraries(server_request_call_test ) +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) + +add_executable(service_config_end2end_test + test/cpp/end2end/service_config_end2end_test.cc + third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc +) + + +target_include_directories(service_config_end2end_test + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + PRIVATE ${_gRPC_SSL_INCLUDE_DIR} + PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR} + PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR} + PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR} + PRIVATE ${_gRPC_CARES_INCLUDE_DIR} + PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR} + PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR} + 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} +) + +target_link_libraries(service_config_end2end_test + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc++_test_util + grpc_test_util + grpc++ + grpc + gpr + ${_gRPC_GFLAGS_LIBRARIES} +) + + endif (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS) @@ -18365,6 +18786,7 @@ target_include_directories(resolver_component_test_unsecure target_link_libraries(resolver_component_test_unsecure ${_gRPC_PROTOBUF_LIBRARIES} ${_gRPC_ALLTARGETS_LIBRARIES} + dns_test_util grpc++_test_util_unsecure grpc_test_util_unsecure grpc++_unsecure @@ -18406,6 +18828,7 @@ target_include_directories(resolver_component_test target_link_libraries(resolver_component_test ${_gRPC_PROTOBUF_LIBRARIES} ${_gRPC_ALLTARGETS_LIBRARIES} + dns_test_util grpc++_test_util grpc_test_util grpc++ @@ -18615,6 +19038,7 @@ target_include_directories(cancel_ares_query_test target_link_libraries(cancel_ares_query_test ${_gRPC_PROTOBUF_LIBRARIES} ${_gRPC_ALLTARGETS_LIBRARIES} + dns_test_util grpc++_test_util grpc_test_util grpc++ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1d14d5e0e3a..862a9019cce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -110,5 +110,16 @@ How to get your contributions merged smoothly and quickly. - Exceptions to the rules can be made if there's a compelling reason for doing so. - +## Obtaining Commit Access +We grant Commit Access to contributors based on the following criteria: +* Sustained contribution to the gRPC project. +* Deep understanding of the areas contributed to, and good consideration of various reliability, usability and performance tradeoffs. +* Contributions demonstrate that obtaining Commit Access will significantly reduce friction for the contributors or others. + +In addition to submitting PRs, a Contributor with Commit Access can: +* Review PRs and merge once other checks and criteria pass. +* Triage bugs and PRs and assign appropriate labels and reviewers. + +### Obtaining Commit Access without Code Contributions +The [gRPC organization](https://github.com/grpc) is comprised of multiple repositories and commit access is usually restricted to one or more of these repositories. Some repositories such as the [grpc.github.io](https://github.com/grpc/grpc.github.io/) do not have code, but the same principle of sustained, high quality contributions, with a good understanding of the fundamentals, apply. diff --git a/Makefile b/Makefile index 57530500b15..e3804df86d4 100644 --- a/Makefile +++ b/Makefile @@ -460,8 +460,8 @@ Q = @ endif CORE_VERSION = 7.0.0 -CPP_VERSION = 1.21.0-dev -CSHARP_VERSION = 1.21.0-dev +CPP_VERSION = 1.22.0-dev +CSHARP_VERSION = 1.22.0-dev CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES)) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) @@ -1162,6 +1162,8 @@ bm_alarm: $(BINDIR)/$(CONFIG)/bm_alarm bm_arena: $(BINDIR)/$(CONFIG)/bm_arena bm_byte_buffer: $(BINDIR)/$(CONFIG)/bm_byte_buffer bm_call_create: $(BINDIR)/$(CONFIG)/bm_call_create +bm_callback_streaming_ping_pong: $(BINDIR)/$(CONFIG)/bm_callback_streaming_ping_pong +bm_callback_unary_ping_pong: $(BINDIR)/$(CONFIG)/bm_callback_unary_ping_pong bm_channel: $(BINDIR)/$(CONFIG)/bm_channel bm_chttp2_hpack: $(BINDIR)/$(CONFIG)/bm_chttp2_hpack bm_chttp2_transport: $(BINDIR)/$(CONFIG)/bm_chttp2_transport @@ -1206,6 +1208,8 @@ error_details_test: $(BINDIR)/$(CONFIG)/error_details_test exception_test: $(BINDIR)/$(CONFIG)/exception_test filter_end2end_test: $(BINDIR)/$(CONFIG)/filter_end2end_test generic_end2end_test: $(BINDIR)/$(CONFIG)/generic_end2end_test +global_config_env_test: $(BINDIR)/$(CONFIG)/global_config_env_test +global_config_test: $(BINDIR)/$(CONFIG)/global_config_test golden_file_test: $(BINDIR)/$(CONFIG)/golden_file_test grpc_alts_credentials_options_test: $(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test grpc_cli: $(BINDIR)/$(CONFIG)/grpc_cli @@ -1240,6 +1244,7 @@ nonblocking_test: $(BINDIR)/$(CONFIG)/nonblocking_test noop-benchmark: $(BINDIR)/$(CONFIG)/noop-benchmark optional_test: $(BINDIR)/$(CONFIG)/optional_test orphanable_test: $(BINDIR)/$(CONFIG)/orphanable_test +port_sharing_end2end_test: $(BINDIR)/$(CONFIG)/port_sharing_end2end_test proto_server_reflection_test: $(BINDIR)/$(CONFIG)/proto_server_reflection_test proto_utils_test: $(BINDIR)/$(CONFIG)/proto_utils_test qps_interarrival_test: $(BINDIR)/$(CONFIG)/qps_interarrival_test @@ -1263,6 +1268,7 @@ server_crash_test_client: $(BINDIR)/$(CONFIG)/server_crash_test_client server_early_return_test: $(BINDIR)/$(CONFIG)/server_early_return_test server_interceptors_end2end_test: $(BINDIR)/$(CONFIG)/server_interceptors_end2end_test server_request_call_test: $(BINDIR)/$(CONFIG)/server_request_call_test +service_config_end2end_test: $(BINDIR)/$(CONFIG)/service_config_end2end_test service_config_test: $(BINDIR)/$(CONFIG)/service_config_test shutdown_test: $(BINDIR)/$(CONFIG)/shutdown_test slice_hash_table_test: $(BINDIR)/$(CONFIG)/slice_hash_table_test @@ -1409,9 +1415,9 @@ pc_cxx: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++.pc pc_cxx_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++_unsecure.pc ifeq ($(EMBED_OPENSSL),true) -privatelibs_cxx: $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libbenchmark.a +privatelibs_cxx: $(LIBDIR)/$(CONFIG)/libdns_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libbenchmark.a else -privatelibs_cxx: $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libbenchmark.a +privatelibs_cxx: $(LIBDIR)/$(CONFIG)/libdns_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_core_stats.a $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libbenchmark.a endif @@ -1638,6 +1644,8 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/bm_arena \ $(BINDIR)/$(CONFIG)/bm_byte_buffer \ $(BINDIR)/$(CONFIG)/bm_call_create \ + $(BINDIR)/$(CONFIG)/bm_callback_streaming_ping_pong \ + $(BINDIR)/$(CONFIG)/bm_callback_unary_ping_pong \ $(BINDIR)/$(CONFIG)/bm_channel \ $(BINDIR)/$(CONFIG)/bm_chttp2_hpack \ $(BINDIR)/$(CONFIG)/bm_chttp2_transport \ @@ -1682,6 +1690,8 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/exception_test \ $(BINDIR)/$(CONFIG)/filter_end2end_test \ $(BINDIR)/$(CONFIG)/generic_end2end_test \ + $(BINDIR)/$(CONFIG)/global_config_env_test \ + $(BINDIR)/$(CONFIG)/global_config_test \ $(BINDIR)/$(CONFIG)/golden_file_test \ $(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test \ $(BINDIR)/$(CONFIG)/grpc_cli \ @@ -1709,6 +1719,7 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/noop-benchmark \ $(BINDIR)/$(CONFIG)/optional_test \ $(BINDIR)/$(CONFIG)/orphanable_test \ + $(BINDIR)/$(CONFIG)/port_sharing_end2end_test \ $(BINDIR)/$(CONFIG)/proto_server_reflection_test \ $(BINDIR)/$(CONFIG)/proto_utils_test \ $(BINDIR)/$(CONFIG)/qps_interarrival_test \ @@ -1732,6 +1743,7 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/server_early_return_test \ $(BINDIR)/$(CONFIG)/server_interceptors_end2end_test \ $(BINDIR)/$(CONFIG)/server_request_call_test \ + $(BINDIR)/$(CONFIG)/service_config_end2end_test \ $(BINDIR)/$(CONFIG)/service_config_test \ $(BINDIR)/$(CONFIG)/shutdown_test \ $(BINDIR)/$(CONFIG)/slice_hash_table_test \ @@ -1782,6 +1794,8 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/bm_arena \ $(BINDIR)/$(CONFIG)/bm_byte_buffer \ $(BINDIR)/$(CONFIG)/bm_call_create \ + $(BINDIR)/$(CONFIG)/bm_callback_streaming_ping_pong \ + $(BINDIR)/$(CONFIG)/bm_callback_unary_ping_pong \ $(BINDIR)/$(CONFIG)/bm_channel \ $(BINDIR)/$(CONFIG)/bm_chttp2_hpack \ $(BINDIR)/$(CONFIG)/bm_chttp2_transport \ @@ -1826,6 +1840,8 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/exception_test \ $(BINDIR)/$(CONFIG)/filter_end2end_test \ $(BINDIR)/$(CONFIG)/generic_end2end_test \ + $(BINDIR)/$(CONFIG)/global_config_env_test \ + $(BINDIR)/$(CONFIG)/global_config_test \ $(BINDIR)/$(CONFIG)/golden_file_test \ $(BINDIR)/$(CONFIG)/grpc_alts_credentials_options_test \ $(BINDIR)/$(CONFIG)/grpc_cli \ @@ -1853,6 +1869,7 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/noop-benchmark \ $(BINDIR)/$(CONFIG)/optional_test \ $(BINDIR)/$(CONFIG)/orphanable_test \ + $(BINDIR)/$(CONFIG)/port_sharing_end2end_test \ $(BINDIR)/$(CONFIG)/proto_server_reflection_test \ $(BINDIR)/$(CONFIG)/proto_utils_test \ $(BINDIR)/$(CONFIG)/qps_interarrival_test \ @@ -1876,6 +1893,7 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/server_early_return_test \ $(BINDIR)/$(CONFIG)/server_interceptors_end2end_test \ $(BINDIR)/$(CONFIG)/server_request_call_test \ + $(BINDIR)/$(CONFIG)/service_config_end2end_test \ $(BINDIR)/$(CONFIG)/service_config_test \ $(BINDIR)/$(CONFIG)/shutdown_test \ $(BINDIR)/$(CONFIG)/slice_hash_table_test \ @@ -2232,6 +2250,10 @@ test_cxx: buildtests_cxx $(Q) $(BINDIR)/$(CONFIG)/bm_byte_buffer || ( echo test bm_byte_buffer failed ; exit 1 ) $(E) "[RUN] Testing bm_call_create" $(Q) $(BINDIR)/$(CONFIG)/bm_call_create || ( echo test bm_call_create failed ; exit 1 ) + $(E) "[RUN] Testing bm_callback_streaming_ping_pong" + $(Q) $(BINDIR)/$(CONFIG)/bm_callback_streaming_ping_pong || ( echo test bm_callback_streaming_ping_pong failed ; exit 1 ) + $(E) "[RUN] Testing bm_callback_unary_ping_pong" + $(Q) $(BINDIR)/$(CONFIG)/bm_callback_unary_ping_pong || ( echo test bm_callback_unary_ping_pong failed ; exit 1 ) $(E) "[RUN] Testing bm_channel" $(Q) $(BINDIR)/$(CONFIG)/bm_channel || ( echo test bm_channel failed ; exit 1 ) $(E) "[RUN] Testing bm_chttp2_hpack" @@ -2318,6 +2340,10 @@ test_cxx: buildtests_cxx $(Q) $(BINDIR)/$(CONFIG)/filter_end2end_test || ( echo test filter_end2end_test failed ; exit 1 ) $(E) "[RUN] Testing generic_end2end_test" $(Q) $(BINDIR)/$(CONFIG)/generic_end2end_test || ( echo test generic_end2end_test failed ; exit 1 ) + $(E) "[RUN] Testing global_config_env_test" + $(Q) $(BINDIR)/$(CONFIG)/global_config_env_test || ( echo test global_config_env_test failed ; exit 1 ) + $(E) "[RUN] Testing global_config_test" + $(Q) $(BINDIR)/$(CONFIG)/global_config_test || ( echo test global_config_test failed ; exit 1 ) $(E) "[RUN] Testing golden_file_test" $(Q) $(BINDIR)/$(CONFIG)/golden_file_test || ( echo test golden_file_test failed ; exit 1 ) $(E) "[RUN] Testing grpc_alts_credentials_options_test" @@ -2358,6 +2384,8 @@ test_cxx: buildtests_cxx $(Q) $(BINDIR)/$(CONFIG)/optional_test || ( echo test optional_test failed ; exit 1 ) $(E) "[RUN] Testing orphanable_test" $(Q) $(BINDIR)/$(CONFIG)/orphanable_test || ( echo test orphanable_test failed ; exit 1 ) + $(E) "[RUN] Testing port_sharing_end2end_test" + $(Q) $(BINDIR)/$(CONFIG)/port_sharing_end2end_test || ( echo test port_sharing_end2end_test failed ; exit 1 ) $(E) "[RUN] Testing proto_server_reflection_test" $(Q) $(BINDIR)/$(CONFIG)/proto_server_reflection_test || ( echo test proto_server_reflection_test failed ; exit 1 ) $(E) "[RUN] Testing proto_utils_test" @@ -2392,6 +2420,8 @@ test_cxx: buildtests_cxx $(Q) $(BINDIR)/$(CONFIG)/server_interceptors_end2end_test || ( echo test server_interceptors_end2end_test failed ; exit 1 ) $(E) "[RUN] Testing server_request_call_test" $(Q) $(BINDIR)/$(CONFIG)/server_request_call_test || ( echo test server_request_call_test failed ; exit 1 ) + $(E) "[RUN] Testing service_config_end2end_test" + $(Q) $(BINDIR)/$(CONFIG)/service_config_end2end_test || ( echo test service_config_end2end_test failed ; exit 1 ) $(E) "[RUN] Testing service_config_test" $(Q) $(BINDIR)/$(CONFIG)/service_config_test || ( echo test service_config_test failed ; exit 1 ) $(E) "[RUN] Testing shutdown_test" @@ -3320,7 +3350,6 @@ endif LIBGPR_SRC = \ src/core/lib/gpr/alloc.cc \ - src/core/lib/gpr/arena.cc \ src/core/lib/gpr/atm.cc \ src/core/lib/gpr/cpu_iphone.cc \ src/core/lib/gpr/cpu_linux.cc \ @@ -3353,7 +3382,9 @@ LIBGPR_SRC = \ src/core/lib/gpr/tmpfile_posix.cc \ src/core/lib/gpr/tmpfile_windows.cc \ src/core/lib/gpr/wrap_memcpy.cc \ + src/core/lib/gprpp/arena.cc \ src/core/lib/gprpp/fork.cc \ + src/core/lib/gprpp/global_config_env.cc \ src/core/lib/gprpp/thd_posix.cc \ src/core/lib/gprpp/thd_windows.cc \ src/core/lib/profiling/basic_timers.cc \ @@ -3457,12 +3488,15 @@ LIBGRPC_SRC = \ src/core/lib/http/parser.cc \ src/core/lib/iomgr/buffer_list.cc \ src/core/lib/iomgr/call_combiner.cc \ + src/core/lib/iomgr/cfstream_handle.cc \ src/core/lib/iomgr/combiner.cc \ src/core/lib/iomgr/endpoint.cc \ + src/core/lib/iomgr/endpoint_cfstream.cc \ src/core/lib/iomgr/endpoint_pair_posix.cc \ src/core/lib/iomgr/endpoint_pair_uv.cc \ src/core/lib/iomgr/endpoint_pair_windows.cc \ src/core/lib/iomgr/error.cc \ + src/core/lib/iomgr/error_cfstream.cc \ src/core/lib/iomgr/ev_epoll1_linux.cc \ src/core/lib/iomgr/ev_epollex_linux.cc \ src/core/lib/iomgr/ev_poll_posix.cc \ @@ -3483,6 +3517,7 @@ LIBGRPC_SRC = \ src/core/lib/iomgr/iomgr_custom.cc \ src/core/lib/iomgr/iomgr_internal.cc \ src/core/lib/iomgr/iomgr_posix.cc \ + src/core/lib/iomgr/iomgr_posix_cfstream.cc \ src/core/lib/iomgr/iomgr_uv.cc \ src/core/lib/iomgr/iomgr_windows.cc \ src/core/lib/iomgr/is_epollexclusive_available.cc \ @@ -3511,6 +3546,7 @@ LIBGRPC_SRC = \ src/core/lib/iomgr/socket_utils_windows.cc \ src/core/lib/iomgr/socket_windows.cc \ src/core/lib/iomgr/tcp_client.cc \ + src/core/lib/iomgr/tcp_client_cfstream.cc \ src/core/lib/iomgr/tcp_client_custom.cc \ src/core/lib/iomgr/tcp_client_posix.cc \ src/core/lib/iomgr/tcp_client_windows.cc \ @@ -3744,12 +3780,15 @@ LIBGRPC_SRC = \ src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc \ + src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc \ + src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc \ + src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc \ src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \ src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \ src/core/ext/filters/census/grpc_context.cc \ @@ -3878,12 +3917,15 @@ LIBGRPC_CRONET_SRC = \ src/core/lib/http/parser.cc \ src/core/lib/iomgr/buffer_list.cc \ src/core/lib/iomgr/call_combiner.cc \ + src/core/lib/iomgr/cfstream_handle.cc \ src/core/lib/iomgr/combiner.cc \ src/core/lib/iomgr/endpoint.cc \ + src/core/lib/iomgr/endpoint_cfstream.cc \ src/core/lib/iomgr/endpoint_pair_posix.cc \ src/core/lib/iomgr/endpoint_pair_uv.cc \ src/core/lib/iomgr/endpoint_pair_windows.cc \ src/core/lib/iomgr/error.cc \ + src/core/lib/iomgr/error_cfstream.cc \ src/core/lib/iomgr/ev_epoll1_linux.cc \ src/core/lib/iomgr/ev_epollex_linux.cc \ src/core/lib/iomgr/ev_poll_posix.cc \ @@ -3904,6 +3946,7 @@ LIBGRPC_CRONET_SRC = \ src/core/lib/iomgr/iomgr_custom.cc \ src/core/lib/iomgr/iomgr_internal.cc \ src/core/lib/iomgr/iomgr_posix.cc \ + src/core/lib/iomgr/iomgr_posix_cfstream.cc \ src/core/lib/iomgr/iomgr_uv.cc \ src/core/lib/iomgr/iomgr_windows.cc \ src/core/lib/iomgr/is_epollexclusive_available.cc \ @@ -3932,6 +3975,7 @@ LIBGRPC_CRONET_SRC = \ src/core/lib/iomgr/socket_utils_windows.cc \ src/core/lib/iomgr/socket_windows.cc \ src/core/lib/iomgr/tcp_client.cc \ + src/core/lib/iomgr/tcp_client_cfstream.cc \ src/core/lib/iomgr/tcp_client_custom.cc \ src/core/lib/iomgr/tcp_client_posix.cc \ src/core/lib/iomgr/tcp_client_windows.cc \ @@ -4283,12 +4327,15 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/lib/http/parser.cc \ src/core/lib/iomgr/buffer_list.cc \ src/core/lib/iomgr/call_combiner.cc \ + src/core/lib/iomgr/cfstream_handle.cc \ src/core/lib/iomgr/combiner.cc \ src/core/lib/iomgr/endpoint.cc \ + src/core/lib/iomgr/endpoint_cfstream.cc \ src/core/lib/iomgr/endpoint_pair_posix.cc \ src/core/lib/iomgr/endpoint_pair_uv.cc \ src/core/lib/iomgr/endpoint_pair_windows.cc \ src/core/lib/iomgr/error.cc \ + src/core/lib/iomgr/error_cfstream.cc \ src/core/lib/iomgr/ev_epoll1_linux.cc \ src/core/lib/iomgr/ev_epollex_linux.cc \ src/core/lib/iomgr/ev_poll_posix.cc \ @@ -4309,6 +4356,7 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/lib/iomgr/iomgr_custom.cc \ src/core/lib/iomgr/iomgr_internal.cc \ src/core/lib/iomgr/iomgr_posix.cc \ + src/core/lib/iomgr/iomgr_posix_cfstream.cc \ src/core/lib/iomgr/iomgr_uv.cc \ src/core/lib/iomgr/iomgr_windows.cc \ src/core/lib/iomgr/is_epollexclusive_available.cc \ @@ -4337,6 +4385,7 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/lib/iomgr/socket_utils_windows.cc \ src/core/lib/iomgr/socket_windows.cc \ src/core/lib/iomgr/tcp_client.cc \ + src/core/lib/iomgr/tcp_client_cfstream.cc \ src/core/lib/iomgr/tcp_client_custom.cc \ src/core/lib/iomgr/tcp_client_posix.cc \ src/core/lib/iomgr/tcp_client_windows.cc \ @@ -4595,12 +4644,15 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \ src/core/lib/http/parser.cc \ src/core/lib/iomgr/buffer_list.cc \ src/core/lib/iomgr/call_combiner.cc \ + src/core/lib/iomgr/cfstream_handle.cc \ src/core/lib/iomgr/combiner.cc \ src/core/lib/iomgr/endpoint.cc \ + src/core/lib/iomgr/endpoint_cfstream.cc \ src/core/lib/iomgr/endpoint_pair_posix.cc \ src/core/lib/iomgr/endpoint_pair_uv.cc \ src/core/lib/iomgr/endpoint_pair_windows.cc \ src/core/lib/iomgr/error.cc \ + src/core/lib/iomgr/error_cfstream.cc \ src/core/lib/iomgr/ev_epoll1_linux.cc \ src/core/lib/iomgr/ev_epollex_linux.cc \ src/core/lib/iomgr/ev_poll_posix.cc \ @@ -4621,6 +4673,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \ src/core/lib/iomgr/iomgr_custom.cc \ src/core/lib/iomgr/iomgr_internal.cc \ src/core/lib/iomgr/iomgr_posix.cc \ + src/core/lib/iomgr/iomgr_posix_cfstream.cc \ src/core/lib/iomgr/iomgr_uv.cc \ src/core/lib/iomgr/iomgr_windows.cc \ src/core/lib/iomgr/is_epollexclusive_available.cc \ @@ -4649,6 +4702,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \ src/core/lib/iomgr/socket_utils_windows.cc \ src/core/lib/iomgr/socket_windows.cc \ src/core/lib/iomgr/tcp_client.cc \ + src/core/lib/iomgr/tcp_client_cfstream.cc \ src/core/lib/iomgr/tcp_client_custom.cc \ src/core/lib/iomgr/tcp_client_posix.cc \ src/core/lib/iomgr/tcp_client_windows.cc \ @@ -4870,12 +4924,15 @@ LIBGRPC_UNSECURE_SRC = \ src/core/lib/http/parser.cc \ src/core/lib/iomgr/buffer_list.cc \ src/core/lib/iomgr/call_combiner.cc \ + src/core/lib/iomgr/cfstream_handle.cc \ src/core/lib/iomgr/combiner.cc \ src/core/lib/iomgr/endpoint.cc \ + src/core/lib/iomgr/endpoint_cfstream.cc \ src/core/lib/iomgr/endpoint_pair_posix.cc \ src/core/lib/iomgr/endpoint_pair_uv.cc \ src/core/lib/iomgr/endpoint_pair_windows.cc \ src/core/lib/iomgr/error.cc \ + src/core/lib/iomgr/error_cfstream.cc \ src/core/lib/iomgr/ev_epoll1_linux.cc \ src/core/lib/iomgr/ev_epollex_linux.cc \ src/core/lib/iomgr/ev_poll_posix.cc \ @@ -4896,6 +4953,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/lib/iomgr/iomgr_custom.cc \ src/core/lib/iomgr/iomgr_internal.cc \ src/core/lib/iomgr/iomgr_posix.cc \ + src/core/lib/iomgr/iomgr_posix_cfstream.cc \ src/core/lib/iomgr/iomgr_uv.cc \ src/core/lib/iomgr/iomgr_windows.cc \ src/core/lib/iomgr/is_epollexclusive_available.cc \ @@ -4924,6 +4982,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/lib/iomgr/socket_utils_windows.cc \ src/core/lib/iomgr/socket_windows.cc \ src/core/lib/iomgr/tcp_client.cc \ + src/core/lib/iomgr/tcp_client_cfstream.cc \ src/core/lib/iomgr/tcp_client_custom.cc \ src/core/lib/iomgr/tcp_client_posix.cc \ src/core/lib/iomgr/tcp_client_windows.cc \ @@ -5065,12 +5124,15 @@ LIBGRPC_UNSECURE_SRC = \ src/core/ext/transport/inproc/inproc_transport.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc \ + src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc \ + src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc \ + src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc \ src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \ src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \ @@ -5248,6 +5310,107 @@ endif endif +LIBBM_CALLBACK_TEST_SERVICE_IMPL_SRC = \ + $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc \ + test/cpp/microbenchmarks/callback_test_service.cc \ + +PUBLIC_HEADERS_CXX += \ + +LIBBM_CALLBACK_TEST_SERVICE_IMPL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBM_CALLBACK_TEST_SERVICE_IMPL_SRC)))) + +$(LIBBM_CALLBACK_TEST_SERVICE_IMPL_OBJS): CPPFLAGS += -Ithird_party/benchmark/include -DHAVE_POSIX_REGEX + +ifeq ($(NO_SECURE),true) + +# You can't build secure libraries if you don't have OpenSSL. + +$(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a: openssl_dep_error + + +else + +ifeq ($(NO_PROTOBUF),true) + +# You can't build a C++ library if you don't have protobuf - a bit overreached, but still okay. + +$(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a: protobuf_dep_error + + +else + +$(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBBM_CALLBACK_TEST_SERVICE_IMPL_OBJS) + $(E) "[AR] Creating $@" + $(Q) mkdir -p `dirname $@` + $(Q) rm -f $(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a + $(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a $(LIBBM_CALLBACK_TEST_SERVICE_IMPL_OBJS) +ifeq ($(SYSTEM),Darwin) + $(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a +endif + + + + +endif + +endif + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(LIBBM_CALLBACK_TEST_SERVICE_IMPL_OBJS:.o=.dep) +endif +endif +$(OBJDIR)/$(CONFIG)/test/cpp/microbenchmarks/callback_test_service.o: $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc + + +LIBDNS_TEST_UTIL_SRC = \ + test/cpp/naming/dns_test_util.cc \ + +PUBLIC_HEADERS_CXX += \ + +LIBDNS_TEST_UTIL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBDNS_TEST_UTIL_SRC)))) + + +ifeq ($(NO_SECURE),true) + +# You can't build secure libraries if you don't have OpenSSL. + +$(LIBDIR)/$(CONFIG)/libdns_test_util.a: openssl_dep_error + + +else + +ifeq ($(NO_PROTOBUF),true) + +# You can't build a C++ library if you don't have protobuf - a bit overreached, but still okay. + +$(LIBDIR)/$(CONFIG)/libdns_test_util.a: protobuf_dep_error + + +else + +$(LIBDIR)/$(CONFIG)/libdns_test_util.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(CARES_DEP) $(ADDRESS_SORTING_DEP) $(PROTOBUF_DEP) $(LIBDNS_TEST_UTIL_OBJS) + $(E) "[AR] Creating $@" + $(Q) mkdir -p `dirname $@` + $(Q) rm -f $(LIBDIR)/$(CONFIG)/libdns_test_util.a + $(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libdns_test_util.a $(LIBDNS_TEST_UTIL_OBJS) +ifeq ($(SYSTEM),Darwin) + $(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libdns_test_util.a +endif + + + + +endif + +endif + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(LIBDNS_TEST_UTIL_OBJS:.o=.dep) +endif +endif + + LIBGRPC++_SRC = \ src/cpp/client/insecure_credentials.cc \ src/cpp/client/secure_credentials.cc \ @@ -5277,6 +5440,7 @@ LIBGRPC++_SRC = \ src/cpp/server/channel_argument_option.cc \ src/cpp/server/create_default_thread_pool.cc \ src/cpp/server/dynamic_thread_pool.cc \ + src/cpp/server/external_connection_acceptor_impl.cc \ src/cpp/server/health/default_health_check_service.cc \ src/cpp/server/health/health_check_service.cc \ src/cpp/server/health/health_check_service_server_builder_option.cc \ @@ -5345,6 +5509,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/alarm.h \ include/grpcpp/alarm_impl.h \ include/grpcpp/channel.h \ + include/grpcpp/channel_impl.h \ include/grpcpp/client_context.h \ include/grpcpp/completion_queue.h \ include/grpcpp/create_channel.h \ @@ -5379,18 +5544,21 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/security/auth_metadata_processor.h \ include/grpcpp/security/auth_metadata_processor_impl.h \ include/grpcpp/security/credentials.h \ + include/grpcpp/security/credentials_impl.h \ include/grpcpp/security/server_credentials.h \ include/grpcpp/security/server_credentials_impl.h \ include/grpcpp/server.h \ include/grpcpp/server_builder.h \ include/grpcpp/server_builder_impl.h \ include/grpcpp/server_context.h \ + include/grpcpp/server_impl.h \ include/grpcpp/server_posix.h \ include/grpcpp/server_posix_impl.h \ include/grpcpp/support/async_stream.h \ include/grpcpp/support/async_unary_call.h \ include/grpcpp/support/byte_buffer.h \ include/grpcpp/support/channel_arguments.h \ + include/grpcpp/support/channel_arguments_impl.h \ include/grpcpp/support/client_callback.h \ include/grpcpp/support/client_interceptor.h \ include/grpcpp/support/config.h \ @@ -5503,6 +5671,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/client_interceptor.h \ include/grpcpp/impl/codegen/client_unary_call.h \ include/grpcpp/impl/codegen/completion_queue.h \ + include/grpcpp/impl/codegen/completion_queue_impl.h \ include/grpcpp/impl/codegen/completion_queue_tag.h \ include/grpcpp/impl/codegen/config.h \ include/grpcpp/impl/codegen/core_codegen_interface.h \ @@ -5677,6 +5846,7 @@ LIBGRPC++_CRONET_SRC = \ src/cpp/server/channel_argument_option.cc \ src/cpp/server/create_default_thread_pool.cc \ src/cpp/server/dynamic_thread_pool.cc \ + src/cpp/server/external_connection_acceptor_impl.cc \ src/cpp/server/health/default_health_check_service.cc \ src/cpp/server/health/health_check_service.cc \ src/cpp/server/health/health_check_service_server_builder_option.cc \ @@ -5748,12 +5918,15 @@ LIBGRPC++_CRONET_SRC = \ src/core/lib/http/parser.cc \ src/core/lib/iomgr/buffer_list.cc \ src/core/lib/iomgr/call_combiner.cc \ + src/core/lib/iomgr/cfstream_handle.cc \ src/core/lib/iomgr/combiner.cc \ src/core/lib/iomgr/endpoint.cc \ + src/core/lib/iomgr/endpoint_cfstream.cc \ src/core/lib/iomgr/endpoint_pair_posix.cc \ src/core/lib/iomgr/endpoint_pair_uv.cc \ src/core/lib/iomgr/endpoint_pair_windows.cc \ src/core/lib/iomgr/error.cc \ + src/core/lib/iomgr/error_cfstream.cc \ src/core/lib/iomgr/ev_epoll1_linux.cc \ src/core/lib/iomgr/ev_epollex_linux.cc \ src/core/lib/iomgr/ev_poll_posix.cc \ @@ -5774,6 +5947,7 @@ LIBGRPC++_CRONET_SRC = \ src/core/lib/iomgr/iomgr_custom.cc \ src/core/lib/iomgr/iomgr_internal.cc \ src/core/lib/iomgr/iomgr_posix.cc \ + src/core/lib/iomgr/iomgr_posix_cfstream.cc \ src/core/lib/iomgr/iomgr_uv.cc \ src/core/lib/iomgr/iomgr_windows.cc \ src/core/lib/iomgr/is_epollexclusive_available.cc \ @@ -5802,6 +5976,7 @@ LIBGRPC++_CRONET_SRC = \ src/core/lib/iomgr/socket_utils_windows.cc \ src/core/lib/iomgr/socket_windows.cc \ src/core/lib/iomgr/tcp_client.cc \ + src/core/lib/iomgr/tcp_client_cfstream.cc \ src/core/lib/iomgr/tcp_client_custom.cc \ src/core/lib/iomgr/tcp_client_posix.cc \ src/core/lib/iomgr/tcp_client_windows.cc \ @@ -5959,6 +6134,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/alarm.h \ include/grpcpp/alarm_impl.h \ include/grpcpp/channel.h \ + include/grpcpp/channel_impl.h \ include/grpcpp/client_context.h \ include/grpcpp/completion_queue.h \ include/grpcpp/create_channel.h \ @@ -5993,18 +6169,21 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/security/auth_metadata_processor.h \ include/grpcpp/security/auth_metadata_processor_impl.h \ include/grpcpp/security/credentials.h \ + include/grpcpp/security/credentials_impl.h \ include/grpcpp/security/server_credentials.h \ include/grpcpp/security/server_credentials_impl.h \ include/grpcpp/server.h \ include/grpcpp/server_builder.h \ include/grpcpp/server_builder_impl.h \ include/grpcpp/server_context.h \ + include/grpcpp/server_impl.h \ include/grpcpp/server_posix.h \ include/grpcpp/server_posix_impl.h \ include/grpcpp/support/async_stream.h \ include/grpcpp/support/async_unary_call.h \ include/grpcpp/support/byte_buffer.h \ include/grpcpp/support/channel_arguments.h \ + include/grpcpp/support/channel_arguments_impl.h \ include/grpcpp/support/client_callback.h \ include/grpcpp/support/client_interceptor.h \ include/grpcpp/support/config.h \ @@ -6117,6 +6296,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/client_interceptor.h \ include/grpcpp/impl/codegen/client_unary_call.h \ include/grpcpp/impl/codegen/completion_queue.h \ + include/grpcpp/impl/codegen/completion_queue_impl.h \ include/grpcpp/impl/codegen/completion_queue_tag.h \ include/grpcpp/impl/codegen/config.h \ include/grpcpp/impl/codegen/core_codegen_interface.h \ @@ -6523,6 +6703,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/client_interceptor.h \ include/grpcpp/impl/codegen/client_unary_call.h \ include/grpcpp/impl/codegen/completion_queue.h \ + include/grpcpp/impl/codegen/completion_queue_impl.h \ include/grpcpp/impl/codegen/completion_queue_tag.h \ include/grpcpp/impl/codegen/config.h \ include/grpcpp/impl/codegen/core_codegen_interface.h \ @@ -6692,6 +6873,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/client_interceptor.h \ include/grpcpp/impl/codegen/client_unary_call.h \ include/grpcpp/impl/codegen/completion_queue.h \ + include/grpcpp/impl/codegen/completion_queue_impl.h \ include/grpcpp/impl/codegen/completion_queue_tag.h \ include/grpcpp/impl/codegen/config.h \ include/grpcpp/impl/codegen/core_codegen_interface.h \ @@ -6823,6 +7005,7 @@ LIBGRPC++_UNSECURE_SRC = \ src/cpp/server/channel_argument_option.cc \ src/cpp/server/create_default_thread_pool.cc \ src/cpp/server/dynamic_thread_pool.cc \ + src/cpp/server/external_connection_acceptor_impl.cc \ src/cpp/server/health/default_health_check_service.cc \ src/cpp/server/health/health_check_service.cc \ src/cpp/server/health/health_check_service_server_builder_option.cc \ @@ -6891,6 +7074,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/alarm.h \ include/grpcpp/alarm_impl.h \ include/grpcpp/channel.h \ + include/grpcpp/channel_impl.h \ include/grpcpp/client_context.h \ include/grpcpp/completion_queue.h \ include/grpcpp/create_channel.h \ @@ -6925,18 +7109,21 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/security/auth_metadata_processor.h \ include/grpcpp/security/auth_metadata_processor_impl.h \ include/grpcpp/security/credentials.h \ + include/grpcpp/security/credentials_impl.h \ include/grpcpp/security/server_credentials.h \ include/grpcpp/security/server_credentials_impl.h \ include/grpcpp/server.h \ include/grpcpp/server_builder.h \ include/grpcpp/server_builder_impl.h \ include/grpcpp/server_context.h \ + include/grpcpp/server_impl.h \ include/grpcpp/server_posix.h \ include/grpcpp/server_posix_impl.h \ include/grpcpp/support/async_stream.h \ include/grpcpp/support/async_unary_call.h \ include/grpcpp/support/byte_buffer.h \ include/grpcpp/support/channel_arguments.h \ + include/grpcpp/support/channel_arguments_impl.h \ include/grpcpp/support/client_callback.h \ include/grpcpp/support/client_interceptor.h \ include/grpcpp/support/config.h \ @@ -7049,6 +7236,7 @@ PUBLIC_HEADERS_CXX += \ include/grpcpp/impl/codegen/client_interceptor.h \ include/grpcpp/impl/codegen/client_unary_call.h \ include/grpcpp/impl/codegen/completion_queue.h \ + include/grpcpp/impl/codegen/completion_queue_impl.h \ include/grpcpp/impl/codegen/completion_queue_tag.h \ include/grpcpp/impl/codegen/config.h \ include/grpcpp/impl/codegen/core_codegen_interface.h \ @@ -14377,6 +14565,94 @@ endif endif +BM_CALLBACK_STREAMING_PING_PONG_SRC = \ + test/cpp/microbenchmarks/bm_callback_streaming_ping_pong.cc \ + +BM_CALLBACK_STREAMING_PING_PONG_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BM_CALLBACK_STREAMING_PING_PONG_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/bm_callback_streaming_ping_pong: openssl_dep_error + +else + + + + +ifeq ($(NO_PROTOBUF),true) + +# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+. + +$(BINDIR)/$(CONFIG)/bm_callback_streaming_ping_pong: protobuf_dep_error + +else + +$(BINDIR)/$(CONFIG)/bm_callback_streaming_ping_pong: $(PROTOBUF_DEP) $(BM_CALLBACK_STREAMING_PING_PONG_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LDXX) $(LDFLAGS) $(BM_CALLBACK_STREAMING_PING_PONG_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/bm_callback_streaming_ping_pong + +endif + +endif + +$(BM_CALLBACK_STREAMING_PING_PONG_OBJS): CPPFLAGS += -Ithird_party/benchmark/include -DHAVE_POSIX_REGEX +$(OBJDIR)/$(CONFIG)/test/cpp/microbenchmarks/bm_callback_streaming_ping_pong.o: $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a + +deps_bm_callback_streaming_ping_pong: $(BM_CALLBACK_STREAMING_PING_PONG_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(BM_CALLBACK_STREAMING_PING_PONG_OBJS:.o=.dep) +endif +endif + + +BM_CALLBACK_UNARY_PING_PONG_SRC = \ + test/cpp/microbenchmarks/bm_callback_unary_ping_pong.cc \ + +BM_CALLBACK_UNARY_PING_PONG_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BM_CALLBACK_UNARY_PING_PONG_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/bm_callback_unary_ping_pong: openssl_dep_error + +else + + + + +ifeq ($(NO_PROTOBUF),true) + +# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+. + +$(BINDIR)/$(CONFIG)/bm_callback_unary_ping_pong: protobuf_dep_error + +else + +$(BINDIR)/$(CONFIG)/bm_callback_unary_ping_pong: $(PROTOBUF_DEP) $(BM_CALLBACK_UNARY_PING_PONG_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LDXX) $(LDFLAGS) $(BM_CALLBACK_UNARY_PING_PONG_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/bm_callback_unary_ping_pong + +endif + +endif + +$(BM_CALLBACK_UNARY_PING_PONG_OBJS): CPPFLAGS += -Ithird_party/benchmark/include -DHAVE_POSIX_REGEX +$(OBJDIR)/$(CONFIG)/test/cpp/microbenchmarks/bm_callback_unary_ping_pong.o: $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libbm_callback_test_service_impl.a + +deps_bm_callback_unary_ping_pong: $(BM_CALLBACK_UNARY_PING_PONG_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(BM_CALLBACK_UNARY_PING_PONG_OBJS:.o=.dep) +endif +endif + + BM_CHANNEL_SRC = \ test/cpp/microbenchmarks/bm_channel.cc \ @@ -15637,16 +15913,16 @@ $(BINDIR)/$(CONFIG)/client_crash_test_server: protobuf_dep_error else -$(BINDIR)/$(CONFIG)/client_crash_test_server: $(PROTOBUF_DEP) $(CLIENT_CRASH_TEST_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(BINDIR)/$(CONFIG)/client_crash_test_server: $(PROTOBUF_DEP) $(CLIENT_CRASH_TEST_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` - $(Q) $(LDXX) $(LDFLAGS) $(CLIENT_CRASH_TEST_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/client_crash_test_server + $(Q) $(LDXX) $(LDFLAGS) $(CLIENT_CRASH_TEST_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/client_crash_test_server endif endif -$(OBJDIR)/$(CONFIG)/test/cpp/end2end/client_crash_test_server.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(OBJDIR)/$(CONFIG)/test/cpp/end2end/client_crash_test_server.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a deps_client_crash_test_server: $(CLIENT_CRASH_TEST_SERVER_OBJS:.o=.dep) @@ -16360,6 +16636,92 @@ endif endif +GLOBAL_CONFIG_ENV_TEST_SRC = \ + test/core/gprpp/global_config_env_test.cc \ + +GLOBAL_CONFIG_ENV_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GLOBAL_CONFIG_ENV_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/global_config_env_test: openssl_dep_error + +else + + + + +ifeq ($(NO_PROTOBUF),true) + +# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+. + +$(BINDIR)/$(CONFIG)/global_config_env_test: protobuf_dep_error + +else + +$(BINDIR)/$(CONFIG)/global_config_env_test: $(PROTOBUF_DEP) $(GLOBAL_CONFIG_ENV_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LDXX) $(LDFLAGS) $(GLOBAL_CONFIG_ENV_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/global_config_env_test + +endif + +endif + +$(OBJDIR)/$(CONFIG)/test/core/gprpp/global_config_env_test.o: $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a + +deps_global_config_env_test: $(GLOBAL_CONFIG_ENV_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(GLOBAL_CONFIG_ENV_TEST_OBJS:.o=.dep) +endif +endif + + +GLOBAL_CONFIG_TEST_SRC = \ + test/core/gprpp/global_config_test.cc \ + +GLOBAL_CONFIG_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GLOBAL_CONFIG_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/global_config_test: openssl_dep_error + +else + + + + +ifeq ($(NO_PROTOBUF),true) + +# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+. + +$(BINDIR)/$(CONFIG)/global_config_test: protobuf_dep_error + +else + +$(BINDIR)/$(CONFIG)/global_config_test: $(PROTOBUF_DEP) $(GLOBAL_CONFIG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LDXX) $(LDFLAGS) $(GLOBAL_CONFIG_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/global_config_test + +endif + +endif + +$(OBJDIR)/$(CONFIG)/test/core/gprpp/global_config_test.o: $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a + +deps_global_config_test: $(GLOBAL_CONFIG_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(GLOBAL_CONFIG_TEST_OBJS:.o=.dep) +endif +endif + + GOLDEN_FILE_TEST_SRC = \ $(GENDIR)/src/proto/grpc/testing/compiler_test.pb.cc $(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc \ test/cpp/codegen/golden_file_test.cc \ @@ -16384,18 +16746,18 @@ $(BINDIR)/$(CONFIG)/golden_file_test: protobuf_dep_error else -$(BINDIR)/$(CONFIG)/golden_file_test: $(PROTOBUF_DEP) $(GOLDEN_FILE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(BINDIR)/$(CONFIG)/golden_file_test: $(PROTOBUF_DEP) $(GOLDEN_FILE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` - $(Q) $(LDXX) $(LDFLAGS) $(GOLDEN_FILE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/golden_file_test + $(Q) $(LDXX) $(LDFLAGS) $(GOLDEN_FILE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/golden_file_test endif endif -$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/compiler_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/compiler_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a -$(OBJDIR)/$(CONFIG)/test/cpp/codegen/golden_file_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(OBJDIR)/$(CONFIG)/test/cpp/codegen/golden_file_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a deps_golden_file_test: $(GOLDEN_FILE_TEST_OBJS:.o=.dep) @@ -17726,6 +18088,49 @@ endif endif +PORT_SHARING_END2END_TEST_SRC = \ + test/cpp/end2end/port_sharing_end2end_test.cc \ + +PORT_SHARING_END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(PORT_SHARING_END2END_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/port_sharing_end2end_test: openssl_dep_error + +else + + + + +ifeq ($(NO_PROTOBUF),true) + +# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+. + +$(BINDIR)/$(CONFIG)/port_sharing_end2end_test: protobuf_dep_error + +else + +$(BINDIR)/$(CONFIG)/port_sharing_end2end_test: $(PROTOBUF_DEP) $(PORT_SHARING_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LDXX) $(LDFLAGS) $(PORT_SHARING_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/port_sharing_end2end_test + +endif + +endif + +$(OBJDIR)/$(CONFIG)/test/cpp/end2end/port_sharing_end2end_test.o: $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_port_sharing_end2end_test: $(PORT_SHARING_END2END_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(PORT_SHARING_END2END_TEST_OBJS:.o=.dep) +endif +endif + + PROTO_SERVER_REFLECTION_TEST_SRC = \ test/cpp/end2end/proto_server_reflection_test.cc \ @@ -18600,16 +19005,16 @@ $(BINDIR)/$(CONFIG)/server_crash_test_client: protobuf_dep_error else -$(BINDIR)/$(CONFIG)/server_crash_test_client: $(PROTOBUF_DEP) $(SERVER_CRASH_TEST_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(BINDIR)/$(CONFIG)/server_crash_test_client: $(PROTOBUF_DEP) $(SERVER_CRASH_TEST_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` - $(Q) $(LDXX) $(LDFLAGS) $(SERVER_CRASH_TEST_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/server_crash_test_client + $(Q) $(LDXX) $(LDFLAGS) $(SERVER_CRASH_TEST_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/server_crash_test_client endif endif -$(OBJDIR)/$(CONFIG)/test/cpp/end2end/server_crash_test_client.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(OBJDIR)/$(CONFIG)/test/cpp/end2end/server_crash_test_client.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a deps_server_crash_test_client: $(SERVER_CRASH_TEST_CLIENT_OBJS:.o=.dep) @@ -18759,6 +19164,49 @@ endif $(OBJDIR)/$(CONFIG)/test/cpp/server/server_request_call_test.o: $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc +SERVICE_CONFIG_END2END_TEST_SRC = \ + test/cpp/end2end/service_config_end2end_test.cc \ + +SERVICE_CONFIG_END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(SERVICE_CONFIG_END2END_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/service_config_end2end_test: openssl_dep_error + +else + + + + +ifeq ($(NO_PROTOBUF),true) + +# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+. + +$(BINDIR)/$(CONFIG)/service_config_end2end_test: protobuf_dep_error + +else + +$(BINDIR)/$(CONFIG)/service_config_end2end_test: $(PROTOBUF_DEP) $(SERVICE_CONFIG_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LDXX) $(LDFLAGS) $(SERVICE_CONFIG_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/service_config_end2end_test + +endif + +endif + +$(OBJDIR)/$(CONFIG)/test/cpp/end2end/service_config_end2end_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_service_config_end2end_test: $(SERVICE_CONFIG_END2END_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(SERVICE_CONFIG_END2END_TEST_OBJS:.o=.dep) +endif +endif + + SERVICE_CONFIG_TEST_SRC = \ test/core/client_channel/service_config_test.cc \ @@ -21141,16 +21589,16 @@ $(BINDIR)/$(CONFIG)/resolver_component_test_unsecure: protobuf_dep_error else -$(BINDIR)/$(CONFIG)/resolver_component_test_unsecure: $(PROTOBUF_DEP) $(RESOLVER_COMPONENT_TEST_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a +$(BINDIR)/$(CONFIG)/resolver_component_test_unsecure: $(PROTOBUF_DEP) $(RESOLVER_COMPONENT_TEST_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libdns_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` - $(Q) $(LDXX) $(LDFLAGS) $(RESOLVER_COMPONENT_TEST_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/resolver_component_test_unsecure + $(Q) $(LDXX) $(LDFLAGS) $(RESOLVER_COMPONENT_TEST_UNSECURE_OBJS) $(LIBDIR)/$(CONFIG)/libdns_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/resolver_component_test_unsecure endif endif -$(OBJDIR)/$(CONFIG)/test/cpp/naming/resolver_component_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a +$(OBJDIR)/$(CONFIG)/test/cpp/naming/resolver_component_test.o: $(LIBDIR)/$(CONFIG)/libdns_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a deps_resolver_component_test_unsecure: $(RESOLVER_COMPONENT_TEST_UNSECURE_OBJS:.o=.dep) @@ -21184,16 +21632,16 @@ $(BINDIR)/$(CONFIG)/resolver_component_test: protobuf_dep_error else -$(BINDIR)/$(CONFIG)/resolver_component_test: $(PROTOBUF_DEP) $(RESOLVER_COMPONENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a +$(BINDIR)/$(CONFIG)/resolver_component_test: $(PROTOBUF_DEP) $(RESOLVER_COMPONENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libdns_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` - $(Q) $(LDXX) $(LDFLAGS) $(RESOLVER_COMPONENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/resolver_component_test + $(Q) $(LDXX) $(LDFLAGS) $(RESOLVER_COMPONENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libdns_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/resolver_component_test endif endif -$(OBJDIR)/$(CONFIG)/test/cpp/naming/resolver_component_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a +$(OBJDIR)/$(CONFIG)/test/cpp/naming/resolver_component_test.o: $(LIBDIR)/$(CONFIG)/libdns_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a deps_resolver_component_test: $(RESOLVER_COMPONENT_TEST_OBJS:.o=.dep) @@ -21399,16 +21847,16 @@ $(BINDIR)/$(CONFIG)/cancel_ares_query_test: protobuf_dep_error else -$(BINDIR)/$(CONFIG)/cancel_ares_query_test: $(PROTOBUF_DEP) $(CANCEL_ARES_QUERY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a +$(BINDIR)/$(CONFIG)/cancel_ares_query_test: $(PROTOBUF_DEP) $(CANCEL_ARES_QUERY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libdns_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` - $(Q) $(LDXX) $(LDFLAGS) $(CANCEL_ARES_QUERY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/cancel_ares_query_test + $(Q) $(LDXX) $(LDFLAGS) $(CANCEL_ARES_QUERY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libdns_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/cancel_ares_query_test endif endif -$(OBJDIR)/$(CONFIG)/test/cpp/naming/cancel_ares_query_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a +$(OBJDIR)/$(CONFIG)/test/cpp/naming/cancel_ares_query_test.o: $(LIBDIR)/$(CONFIG)/libdns_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a deps_cancel_ares_query_test: $(CANCEL_ARES_QUERY_TEST_OBJS:.o=.dep) @@ -22037,7 +22485,9 @@ test/cpp/interop/interop_client.cc: $(OPENSSL_DEP) test/cpp/interop/interop_server.cc: $(OPENSSL_DEP) test/cpp/interop/interop_server_bootstrap.cc: $(OPENSSL_DEP) test/cpp/interop/server_helper.cc: $(OPENSSL_DEP) +test/cpp/microbenchmarks/callback_test_service.cc: $(OPENSSL_DEP) test/cpp/microbenchmarks/helpers.cc: $(OPENSSL_DEP) +test/cpp/naming/dns_test_util.cc: $(OPENSSL_DEP) test/cpp/qps/benchmark_config.cc: $(OPENSSL_DEP) test/cpp/qps/client_async.cc: $(OPENSSL_DEP) test/cpp/qps/client_callback.cc: $(OPENSSL_DEP) diff --git a/WORKSPACE b/WORKSPACE index fcf5b5d6d10..2db3c5db2ff 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -18,13 +18,6 @@ register_toolchains( "//third_party/toolchains/bazel_0.23.2_rbe_windows:cc-toolchain-x64_windows", ) -# TODO(https://github.com/grpc/grpc/issues/18331): Move off of this dependency. -git_repository( - name = "org_pubref_rules_protobuf", - remote = "https://github.com/ghostwriternr/rules_protobuf", - tag = "v0.8.2.1-alpha", -) - git_repository( name = "io_bazel_rules_python", commit = "8b5d0683a7d878b28fffe464779c8a53659fc645", diff --git a/bazel/BUILD b/bazel/BUILD index 32402892cc3..c3c82c9c0c7 100644 --- a/bazel/BUILD +++ b/bazel/BUILD @@ -17,15 +17,3 @@ licenses(["notice"]) # Apache v2 package(default_visibility = ["//:__subpackages__"]) load(":cc_grpc_library.bzl", "cc_grpc_library") - -proto_library( - name = "well_known_protos_list", - srcs = ["@com_google_protobuf//:well_known_protos"], -) - -cc_grpc_library( - name = "well_known_protos", - srcs = "well_known_protos_list", - proto_only = True, - deps = [], -) diff --git a/bazel/cc_grpc_library.bzl b/bazel/cc_grpc_library.bzl index 6bfcd653f51..572af756176 100644 --- a/bazel/cc_grpc_library.bzl +++ b/bazel/cc_grpc_library.bzl @@ -1,71 +1,105 @@ """Generates and compiles C++ grpc stubs from proto_library rules.""" load("//bazel:generate_cc.bzl", "generate_cc") +load("//bazel:protobuf.bzl", "well_known_proto_libs") -def cc_grpc_library(name, srcs, deps, proto_only, well_known_protos, generate_mocks = False, use_external = False, **kwargs): - """Generates C++ grpc classes from a .proto file. +def cc_grpc_library( + name, + srcs, + deps, + proto_only = False, + well_known_protos = False, + generate_mocks = False, + use_external = False, + grpc_only = False, + **kwargs): + """Generates C++ grpc classes for services defined in a proto file. - Assumes the generated classes will be used in cc_api_version = 2. + If grpc_only is True, this rule is compatible with proto_library and + cc_proto_library native rules such that it expects proto_library target + as srcs argument and generates only grpc library classes, expecting + protobuf messages classes library (cc_proto_library target) to be passed in + deps argument. By default grpc_only is False which makes this rule to behave + in a backwards-compatible mode (trying to generate both proto and grpc + classes). - Arguments: - name: name of rule. - srcs: a single proto_library, which wraps the .proto files with services. - deps: a list of C++ proto_library (or cc_proto_library) which provides - the compiled code of any message that the services depend on. - well_known_protos: Should this library additionally depend on well known - protos - use_external: When True the grpc deps are prefixed with //external. This - allows grpc to be used as a dependency in other bazel projects. - generate_mocks: When True, Google Mock code for client stub is generated. - **kwargs: rest of arguments, e.g., compatible_with and visibility. - """ - if len(srcs) > 1: - fail("Only one srcs value supported", "srcs") + Assumes the generated classes will be used in cc_api_version = 2. - proto_target = "_" + name + "_only" - codegen_target = "_" + name + "_codegen" - codegen_grpc_target = "_" + name + "_grpc_codegen" - proto_deps = ["_" + dep + "_only" for dep in deps if dep.find(':') == -1] - proto_deps += [dep.split(':')[0] + ':' + "_" + dep.split(':')[1] + "_only" for dep in deps if dep.find(':') != -1] + Args: + name (str): Name of rule. + srcs (list): A single .proto file which contains services definitions, + or if grpc_only parameter is True, a single proto_library which + contains services descriptors. + deps (list): A list of C++ proto_library (or cc_proto_library) which + provides the compiled code of any message that the services depend on. + proto_only (bool): If True, create only C++ proto classes library, + avoid creating C++ grpc classes library (expect it in deps). + Deprecated, use native cc_proto_library instead. False by default. + well_known_protos (bool): Should this library additionally depend on + well known protos. Deprecated, the well known protos should be + specified as explicit dependencies of the proto_library target + (passed in srcs parameter) instead. False by default. + generate_mocks (bool): when True, Google Mock code for client stub is + generated. False by default. + use_external (bool): Not used. + grpc_only (bool): if True, generate only grpc library, expecting + protobuf messages library (cc_proto_library target) to be passed as + deps. False by default (will become True by default eventually). + **kwargs: rest of arguments, e.g., compatible_with and visibility + """ + if len(srcs) > 1: + fail("Only one srcs value supported", "srcs") + if grpc_only and proto_only: + fail("A mutualy exclusive configuration is specified: grpc_only = True and proto_only = True") - native.proto_library( - name = proto_target, - srcs = srcs, - deps = proto_deps, - **kwargs - ) + extra_deps = [] + proto_targets = [] - generate_cc( - name = codegen_target, - srcs = [proto_target], - well_known_protos = well_known_protos, - **kwargs - ) + if not grpc_only: + proto_target = "_" + name + "_only" + cc_proto_target = name if proto_only else "_" + name + "_cc_proto" - if not proto_only: - plugin = "@com_github_grpc_grpc//:grpc_cpp_plugin" - generate_cc( - name = codegen_grpc_target, - srcs = [proto_target], - plugin = plugin, - well_known_protos = well_known_protos, - generate_mocks = generate_mocks, - **kwargs - ) - grpc_deps = ["@com_github_grpc_grpc//:grpc++_codegen_proto", - "//external:protobuf"] - native.cc_library( - name = name, - srcs = [":" + codegen_grpc_target, ":" + codegen_target], - hdrs = [":" + codegen_grpc_target, ":" + codegen_target], - deps = deps + grpc_deps, - **kwargs - ) - else: - native.cc_library( - name = name, - srcs = [":" + codegen_target], - hdrs = [":" + codegen_target], - deps = deps + ["//external:protobuf"], - **kwargs - ) + proto_deps = ["_" + dep + "_only" for dep in deps if dep.find(":") == -1] + proto_deps += [dep.split(":")[0] + ":" + "_" + dep.split(":")[1] + "_only" for dep in deps if dep.find(":") != -1] + if well_known_protos: + proto_deps += well_known_proto_libs() + + native.proto_library( + name = proto_target, + srcs = srcs, + deps = proto_deps, + **kwargs + ) + + native.cc_proto_library( + name = cc_proto_target, + deps = [":" + proto_target], + **kwargs + ) + extra_deps.append(":" + cc_proto_target) + proto_targets.append(proto_target) + else: + if not srcs: + fail("srcs cannot be empty", "srcs") + proto_targets += srcs + + if not proto_only: + codegen_grpc_target = "_" + name + "_grpc_codegen" + generate_cc( + name = codegen_grpc_target, + srcs = proto_targets, + plugin = "@com_github_grpc_grpc//:grpc_cpp_plugin", + well_known_protos = well_known_protos, + generate_mocks = generate_mocks, + **kwargs + ) + + native.cc_library( + name = name, + srcs = [":" + codegen_grpc_target], + hdrs = [":" + codegen_grpc_target], + deps = deps + + extra_deps + + ["@com_github_grpc_grpc//:grpc++_codegen_proto"], + **kwargs + ) diff --git a/bazel/generate_cc.bzl b/bazel/generate_cc.bzl index 8f30c84f6b9..29a888f608f 100644 --- a/bazel/generate_cc.bzl +++ b/bazel/generate_cc.bzl @@ -4,81 +4,142 @@ This is an internal rule used by cc_grpc_library, and shouldn't be used directly. """ +load( + "//bazel:protobuf.bzl", + "get_include_protoc_args", + "get_plugin_args", + "get_proto_root", + "proto_path_to_generated_filename", +) + +_GRPC_PROTO_HEADER_FMT = "{}.grpc.pb.h" +_GRPC_PROTO_SRC_FMT = "{}.grpc.pb.cc" +_GRPC_PROTO_MOCK_HEADER_FMT = "{}_mock.grpc.pb.h" +_PROTO_HEADER_FMT = "{}.pb.h" +_PROTO_SRC_FMT = "{}.pb.cc" + +def _strip_package_from_path(label_package, file): + prefix_len = 0 + if not file.is_source and file.path.startswith(file.root.path): + prefix_len = len(file.root.path) + 1 + + path = file.path + if len(label_package) == 0: + return path + if not path.startswith(label_package + "/", prefix_len): + fail("'{}' does not lie within '{}'.".format(path, label_package)) + return path[prefix_len + len(label_package + "/"):] + +def _get_srcs_file_path(file): + if not file.is_source and file.path.startswith(file.root.path): + return file.path[len(file.root.path) + 1:] + return file.path + +def _join_directories(directories): + massaged_directories = [directory for directory in directories if len(directory) != 0] + return "/".join(massaged_directories) + def generate_cc_impl(ctx): - """Implementation of the generate_cc rule.""" - protos = [f for src in ctx.attr.srcs for f in src.proto.direct_sources] - includes = [f for src in ctx.attr.srcs for f in src.proto.transitive_imports] - outs = [] - # label_len is length of the path from WORKSPACE root to the location of this build file - label_len = 0 - # proto_root is the directory relative to which generated include paths should be - proto_root = "" - if ctx.label.package: - # The +1 is for the trailing slash. - label_len += len(ctx.label.package) + 1 - if ctx.label.workspace_root: - label_len += len(ctx.label.workspace_root) + 1 - proto_root = "/" + ctx.label.workspace_root - - if ctx.executable.plugin: - outs += [proto.path[label_len:-len(".proto")] + ".grpc.pb.h" for proto in protos] - outs += [proto.path[label_len:-len(".proto")] + ".grpc.pb.cc" for proto in protos] - if ctx.attr.generate_mocks: - outs += [proto.path[label_len:-len(".proto")] + "_mock.grpc.pb.h" for proto in protos] - else: - outs += [proto.path[label_len:-len(".proto")] + ".pb.h" for proto in protos] - outs += [proto.path[label_len:-len(".proto")] + ".pb.cc" for proto in protos] - out_files = [ctx.actions.declare_file(out) for out in outs] - dir_out = str(ctx.genfiles_dir.path + proto_root) - - arguments = [] - if ctx.executable.plugin: - arguments += ["--plugin=protoc-gen-PLUGIN=" + ctx.executable.plugin.path] - flags = list(ctx.attr.flags) - if ctx.attr.generate_mocks: - flags.append("generate_mock_code=true") - arguments += ["--PLUGIN_out=" + ",".join(flags) + ":" + dir_out] - tools = [ctx.executable.plugin] - else: - arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out] - tools = [] - - # Import protos relative to their workspace root so that protoc prints the - # right include paths. - for include in includes: - directory = include.path - if directory.startswith("external"): - external_sep = directory.find("/") - repository_sep = directory.find("/", external_sep + 1) - arguments += ["--proto_path=" + directory[:repository_sep]] + """Implementation of the generate_cc rule.""" + protos = [f for src in ctx.attr.srcs for f in src.proto.check_deps_sources] + includes = [ + f + for src in ctx.attr.srcs + for f in src.proto.transitive_imports + ] + outs = [] + proto_root = get_proto_root( + ctx.label.workspace_root, + ) + + label_package = _join_directories([ctx.label.workspace_root, ctx.label.package]) + if ctx.executable.plugin: + outs += [ + proto_path_to_generated_filename( + _strip_package_from_path(label_package, proto), + _GRPC_PROTO_HEADER_FMT, + ) + for proto in protos + ] + outs += [ + proto_path_to_generated_filename( + _strip_package_from_path(label_package, proto), + _GRPC_PROTO_SRC_FMT, + ) + for proto in protos + ] + if ctx.attr.generate_mocks: + outs += [ + proto_path_to_generated_filename( + _strip_package_from_path(label_package, proto), + _GRPC_PROTO_MOCK_HEADER_FMT, + ) + for proto in protos + ] else: - arguments += ["--proto_path=."] - # Include the output directory so that protoc puts the generated code in the - # right directory. - arguments += ["--proto_path={0}{1}".format(dir_out, proto_root)] - arguments += [proto.path for proto in protos] - - # create a list of well known proto files if the argument is non-None - well_known_proto_files = [] - if ctx.attr.well_known_protos: - f = ctx.attr.well_known_protos.files.to_list()[0].dirname - if f != "external/com_google_protobuf/src/google/protobuf": - print("Error: Only @com_google_protobuf//:well_known_protos is supported") + outs += [ + proto_path_to_generated_filename( + _strip_package_from_path(label_package, proto), + _PROTO_HEADER_FMT, + ) + for proto in protos + ] + outs += [ + proto_path_to_generated_filename( + _strip_package_from_path(label_package, proto), + _PROTO_SRC_FMT, + ) + for proto in protos + ] + out_files = [ctx.actions.declare_file(out) for out in outs] + dir_out = str(ctx.genfiles_dir.path + proto_root) + + arguments = [] + if ctx.executable.plugin: + arguments += get_plugin_args( + ctx.executable.plugin, + ctx.attr.flags, + dir_out, + ctx.attr.generate_mocks, + ) + tools = [ctx.executable.plugin] else: - # f points to "external/com_google_protobuf/src/google/protobuf" - # add -I argument to protoc so it knows where to look for the proto files. - arguments += ["-I{0}".format(f + "/../..")] - well_known_proto_files = [f for f in ctx.attr.well_known_protos.files] + arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out] + tools = [] + + arguments += get_include_protoc_args(includes) + + # Include the output directory so that protoc puts the generated code in the + # right directory. + arguments += ["--proto_path={0}{1}".format(dir_out, proto_root)] + arguments += [_get_srcs_file_path(proto) for proto in protos] + + # create a list of well known proto files if the argument is non-None + well_known_proto_files = [] + if ctx.attr.well_known_protos: + f = ctx.attr.well_known_protos.files.to_list()[0].dirname + if f != "external/com_google_protobuf/src/google/protobuf": + print( + "Error: Only @com_google_protobuf//:well_known_protos is supported", + ) + else: + # f points to "external/com_google_protobuf/src/google/protobuf" + # add -I argument to protoc so it knows where to look for the proto files. + arguments += ["-I{0}".format(f + "/../..")] + well_known_proto_files = [ + f + for f in ctx.attr.well_known_protos.files + ] - ctx.actions.run( - inputs = protos + includes + well_known_proto_files, - tools = tools, - outputs = out_files, - executable = ctx.executable._protoc, - arguments = arguments, - ) + ctx.actions.run( + inputs = protos + includes + well_known_proto_files, + tools = tools, + outputs = out_files, + executable = ctx.executable._protoc, + arguments = arguments, + ) - return struct(files=depset(out_files)) + return struct(files = depset(out_files)) _generate_cc = rule( attrs = { @@ -96,10 +157,8 @@ _generate_cc = rule( mandatory = False, allow_empty = True, ), - "well_known_protos" : attr.label( - mandatory = False, - ), - "generate_mocks" : attr.bool( + "well_known_protos": attr.label(mandatory = False), + "generate_mocks": attr.bool( default = False, mandatory = False, ), @@ -115,7 +174,10 @@ _generate_cc = rule( ) def generate_cc(well_known_protos, **kwargs): - if well_known_protos: - _generate_cc(well_known_protos="@com_google_protobuf//:well_known_protos", **kwargs) - else: - _generate_cc(**kwargs) + if well_known_protos: + _generate_cc( + well_known_protos = "@com_google_protobuf//:well_known_protos", + **kwargs + ) + else: + _generate_cc(**kwargs) diff --git a/bazel/grpc_python_deps.bzl b/bazel/grpc_python_deps.bzl index ec3df19e03a..91438f3927b 100644 --- a/bazel/grpc_python_deps.bzl +++ b/bazel/grpc_python_deps.bzl @@ -1,16 +1,8 @@ load("//third_party/py:python_configure.bzl", "python_configure") load("@io_bazel_rules_python//python:pip.bzl", "pip_repositories") load("@grpc_python_dependencies//:requirements.bzl", "pip_install") -load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_repositories") def grpc_python_deps(): - # TODO(https://github.com/grpc/grpc/issues/18256): Remove conditional. - if hasattr(native, "http_archive"): - python_configure(name = "local_config_python") - pip_repositories() - pip_install() - py_proto_repositories() - else: - print("Building Python gRPC with bazel 23.0+ is disabled pending " + - "resolution of https://github.com/grpc/grpc/issues/18256.") - + python_configure(name = "local_config_python") + pip_repositories() + pip_install() diff --git a/bazel/protobuf.bzl b/bazel/protobuf.bzl new file mode 100644 index 00000000000..f2df7bd87b2 --- /dev/null +++ b/bazel/protobuf.bzl @@ -0,0 +1,104 @@ +"""Utility functions for generating protobuf code.""" + +_PROTO_EXTENSION = ".proto" + +def well_known_proto_libs(): + return [ + "@com_google_protobuf//:any_proto", + "@com_google_protobuf//:api_proto", + "@com_google_protobuf//:compiler_plugin_proto", + "@com_google_protobuf//:descriptor_proto", + "@com_google_protobuf//:duration_proto", + "@com_google_protobuf//:empty_proto", + "@com_google_protobuf//:field_mask_proto", + "@com_google_protobuf//:source_context_proto", + "@com_google_protobuf//:struct_proto", + "@com_google_protobuf//:timestamp_proto", + "@com_google_protobuf//:type_proto", + "@com_google_protobuf//:wrappers_proto", + ] + +def get_proto_root(workspace_root): + """Gets the root protobuf directory. + + Args: + workspace_root: context.label.workspace_root + + Returns: + The directory relative to which generated include paths should be. + """ + if workspace_root: + return "/{}".format(workspace_root) + else: + return "" + +def _strip_proto_extension(proto_filename): + if not proto_filename.endswith(_PROTO_EXTENSION): + fail('"{}" does not end with "{}"'.format( + proto_filename, + _PROTO_EXTENSION, + )) + return proto_filename[:-len(_PROTO_EXTENSION)] + +def proto_path_to_generated_filename(proto_path, fmt_str): + """Calculates the name of a generated file for a protobuf path. + + For example, "examples/protos/helloworld.proto" might map to + "helloworld.pb.h". + + Args: + proto_path: The path to the .proto file. + fmt_str: A format string used to calculate the generated filename. For + example, "{}.pb.h" might be used to calculate a C++ header filename. + + Returns: + The generated filename. + """ + return fmt_str.format(_strip_proto_extension(proto_path)) + +def _get_include_directory(include): + directory = include.path + prefix_len = 0 + if not include.is_source and directory.startswith(include.root.path): + prefix_len = len(include.root.path) + 1 + + if directory.startswith("external", prefix_len): + external_separator = directory.find("/", prefix_len) + repository_separator = directory.find("/", external_separator + 1) + return directory[:repository_separator] + else: + return include.root.path if include.root.path else "." + +def get_include_protoc_args(includes): + """Returns protoc args that imports protos relative to their import root. + + Args: + includes: A list of included proto files. + + Returns: + A list of arguments to be passed to protoc. For example, ["--proto_path=."]. + """ + return [ + "--proto_path={}".format(_get_include_directory(include)) + for include in includes + ] + +def get_plugin_args(plugin, flags, dir_out, generate_mocks): + """Returns arguments configuring protoc to use a plugin for a language. + + Args: + plugin: An executable file to run as the protoc plugin. + flags: The plugin flags to be passed to protoc. + dir_out: The output directory for the plugin. + generate_mocks: A bool indicating whether to generate mocks. + + Returns: + A list of protoc arguments configuring the plugin. + """ + augmented_flags = list(flags) + if generate_mocks: + augmented_flags.append("generate_mock_code=true") + return [ + "--plugin=protoc-gen-PLUGIN=" + plugin.path, + "--PLUGIN_out=" + ",".join(augmented_flags) + ":" + dir_out, + ] diff --git a/bazel/python_rules.bzl b/bazel/python_rules.bzl new file mode 100644 index 00000000000..2f3b38af002 --- /dev/null +++ b/bazel/python_rules.bzl @@ -0,0 +1,186 @@ +"""Generates and compiles Python gRPC stubs from proto_library rules.""" + +load("@grpc_python_dependencies//:requirements.bzl", "requirement") +load( + "//bazel:protobuf.bzl", + "get_include_protoc_args", + "get_plugin_args", + "get_proto_root", + "proto_path_to_generated_filename", +) + +_GENERATED_PROTO_FORMAT = "{}_pb2.py" +_GENERATED_GRPC_PROTO_FORMAT = "{}_pb2_grpc.py" + +def _get_staged_proto_file(context, source_file): + if source_file.dirname == context.label.package: + return source_file + else: + copied_proto = context.actions.declare_file(source_file.basename) + context.actions.run_shell( + inputs = [source_file], + outputs = [copied_proto], + command = "cp {} {}".format(source_file.path, copied_proto.path), + mnemonic = "CopySourceProto", + ) + return copied_proto + +def _generate_py_impl(context): + protos = [] + for src in context.attr.deps: + for file in src.proto.direct_sources: + protos.append(_get_staged_proto_file(context, file)) + includes = [ + file + for src in context.attr.deps + for file in src.proto.transitive_imports + ] + proto_root = get_proto_root(context.label.workspace_root) + format_str = (_GENERATED_GRPC_PROTO_FORMAT if context.executable.plugin else _GENERATED_PROTO_FORMAT) + out_files = [ + context.actions.declare_file( + proto_path_to_generated_filename( + proto.basename, + format_str, + ), + ) + for proto in protos + ] + + arguments = [] + tools = [context.executable._protoc] + if context.executable.plugin: + arguments += get_plugin_args( + context.executable.plugin, + context.attr.flags, + context.genfiles_dir.path, + False, + ) + tools += [context.executable.plugin] + else: + arguments += [ + "--python_out={}:{}".format( + ",".join(context.attr.flags), + context.genfiles_dir.path, + ), + ] + + arguments += get_include_protoc_args(includes) + arguments += [ + "--proto_path={}".format(context.genfiles_dir.path) + for proto in protos + ] + for proto in protos: + massaged_path = proto.path + if massaged_path.startswith(context.genfiles_dir.path): + massaged_path = proto.path[len(context.genfiles_dir.path) + 1:] + arguments.append(massaged_path) + + well_known_proto_files = [] + if context.attr.well_known_protos: + well_known_proto_directory = context.attr.well_known_protos.files.to_list( + )[0].dirname + + arguments += ["-I{}".format(well_known_proto_directory + "/../..")] + well_known_proto_files = context.attr.well_known_protos.files.to_list() + + context.actions.run( + inputs = protos + includes + well_known_proto_files, + tools = tools, + outputs = out_files, + executable = context.executable._protoc, + arguments = arguments, + mnemonic = "ProtocInvocation", + ) + return struct(files = depset(out_files)) + +__generate_py = rule( + attrs = { + "deps": attr.label_list( + mandatory = True, + allow_empty = False, + providers = ["proto"], + ), + "plugin": attr.label( + executable = True, + providers = ["files_to_run"], + cfg = "host", + ), + "flags": attr.string_list( + mandatory = False, + allow_empty = True, + ), + "well_known_protos": attr.label(mandatory = False), + "_protoc": attr.label( + default = Label("//external:protocol_compiler"), + executable = True, + cfg = "host", + ), + }, + output_to_genfiles = True, + implementation = _generate_py_impl, +) + +def _generate_py(well_known_protos, **kwargs): + if well_known_protos: + __generate_py( + well_known_protos = "@com_google_protobuf//:well_known_protos", + **kwargs + ) + else: + __generate_py(**kwargs) + +def py_proto_library( + name, + deps, + well_known_protos = True, + proto_only = False, + **kwargs): + """Generate python code for a protobuf. + + Args: + name: The name of the target. + deps: A list of dependencies. Must contain a single element. + well_known_protos: A bool indicating whether or not to include well-known + protos. + proto_only: A bool indicating whether to generate vanilla protobuf code + or to also generate gRPC code. + """ + if len(deps) > 1: + fail("The supported length of 'deps' is 1.") + + codegen_target = "_{}_codegen".format(name) + codegen_grpc_target = "_{}_grpc_codegen".format(name) + + _generate_py( + name = codegen_target, + deps = deps, + well_known_protos = well_known_protos, + **kwargs + ) + + if not proto_only: + _generate_py( + name = codegen_grpc_target, + deps = deps, + plugin = "//:grpc_python_plugin", + well_known_protos = well_known_protos, + **kwargs + ) + + native.py_library( + name = name, + srcs = [ + ":{}".format(codegen_grpc_target), + ":{}".format(codegen_target), + ], + deps = [requirement("protobuf")], + **kwargs + ) + else: + native.py_library( + name = name, + srcs = [":{}".format(codegen_target), ":{}".format(codegen_target)], + deps = [requirement("protobuf")], + **kwargs + ) diff --git a/build.yaml b/build.yaml index 80519946295..86b8c406607 100644 --- a/build.yaml +++ b/build.yaml @@ -13,8 +13,8 @@ settings: '#09': Per-language overrides are possible with (eg) ruby_version tag here '#10': See the expand_version.py for all the quirks here core_version: 7.0.0 - g_stands_for: gandalf - version: 1.21.0-dev + g_stands_for: gale + version: 1.22.0-dev filegroups: - name: alts_proto headers: @@ -114,7 +114,6 @@ filegroups: - name: gpr_base src: - src/core/lib/gpr/alloc.cc - - src/core/lib/gpr/arena.cc - src/core/lib/gpr/atm.cc - src/core/lib/gpr/cpu_iphone.cc - src/core/lib/gpr/cpu_linux.cc @@ -147,7 +146,9 @@ filegroups: - src/core/lib/gpr/tmpfile_posix.cc - src/core/lib/gpr/tmpfile_windows.cc - src/core/lib/gpr/wrap_memcpy.cc + - src/core/lib/gprpp/arena.cc - src/core/lib/gprpp/fork.cc + - src/core/lib/gprpp/global_config_env.cc - src/core/lib/gprpp/thd_posix.cc - src/core/lib/gprpp/thd_windows.cc - src/core/lib/profiling/basic_timers.cc @@ -191,8 +192,13 @@ filegroups: - src/core/lib/gpr/tmpfile.h - src/core/lib/gpr/useful.h - src/core/lib/gprpp/abstract.h + - src/core/lib/gprpp/arena.h - src/core/lib/gprpp/atomic.h - src/core/lib/gprpp/fork.h + - src/core/lib/gprpp/global_config.h + - src/core/lib/gprpp/global_config_custom.h + - src/core/lib/gprpp/global_config_env.h + - src/core/lib/gprpp/global_config_generic.h - src/core/lib/gprpp/manual_constructor.h - src/core/lib/gprpp/map.h - src/core/lib/gprpp/memory.h @@ -258,12 +264,15 @@ filegroups: - src/core/lib/http/parser.cc - src/core/lib/iomgr/buffer_list.cc - src/core/lib/iomgr/call_combiner.cc + - src/core/lib/iomgr/cfstream_handle.cc - src/core/lib/iomgr/combiner.cc - src/core/lib/iomgr/endpoint.cc + - src/core/lib/iomgr/endpoint_cfstream.cc - src/core/lib/iomgr/endpoint_pair_posix.cc - src/core/lib/iomgr/endpoint_pair_uv.cc - src/core/lib/iomgr/endpoint_pair_windows.cc - src/core/lib/iomgr/error.cc + - src/core/lib/iomgr/error_cfstream.cc - src/core/lib/iomgr/ev_epoll1_linux.cc - src/core/lib/iomgr/ev_epollex_linux.cc - src/core/lib/iomgr/ev_poll_posix.cc @@ -284,6 +293,7 @@ filegroups: - src/core/lib/iomgr/iomgr_custom.cc - src/core/lib/iomgr/iomgr_internal.cc - src/core/lib/iomgr/iomgr_posix.cc + - src/core/lib/iomgr/iomgr_posix_cfstream.cc - src/core/lib/iomgr/iomgr_uv.cc - src/core/lib/iomgr/iomgr_windows.cc - src/core/lib/iomgr/is_epollexclusive_available.cc @@ -312,6 +322,7 @@ filegroups: - src/core/lib/iomgr/socket_utils_windows.cc - src/core/lib/iomgr/socket_windows.cc - src/core/lib/iomgr/tcp_client.cc + - src/core/lib/iomgr/tcp_client_cfstream.cc - src/core/lib/iomgr/tcp_client_custom.cc - src/core/lib/iomgr/tcp_client_posix.cc - src/core/lib/iomgr/tcp_client_windows.cc @@ -439,12 +450,15 @@ filegroups: - src/core/lib/iomgr/block_annotate.h - src/core/lib/iomgr/buffer_list.h - src/core/lib/iomgr/call_combiner.h + - src/core/lib/iomgr/cfstream_handle.h - src/core/lib/iomgr/closure.h - src/core/lib/iomgr/combiner.h - src/core/lib/iomgr/dynamic_annotations.h - src/core/lib/iomgr/endpoint.h + - src/core/lib/iomgr/endpoint_cfstream.h - src/core/lib/iomgr/endpoint_pair.h - src/core/lib/iomgr/error.h + - src/core/lib/iomgr/error_cfstream.h - src/core/lib/iomgr/error_internal.h - src/core/lib/iomgr/ev_epoll1_linux.h - src/core/lib/iomgr/ev_epollex_linux.h @@ -511,6 +525,7 @@ filegroups: - src/core/lib/slice/slice_hash_table.h - src/core/lib/slice/slice_internal.h - src/core/lib/slice/slice_string_helpers.h + - src/core/lib/slice/slice_utils.h - src/core/lib/slice/slice_weak_hash_table.h - src/core/lib/surface/api_trace.h - src/core/lib/surface/call.h @@ -545,20 +560,6 @@ filegroups: uses: - grpc_codegen - grpc_trace_headers -- name: grpc_cfstream - headers: - - src/core/lib/iomgr/cfstream_handle.h - - src/core/lib/iomgr/endpoint_cfstream.h - - src/core/lib/iomgr/error_cfstream.h - src: - - src/core/lib/iomgr/cfstream_handle.cc - - src/core/lib/iomgr/endpoint_cfstream.cc - - src/core/lib/iomgr/error_cfstream.cc - - src/core/lib/iomgr/iomgr_posix_cfstream.cc - - src/core/lib/iomgr/tcp_client_cfstream.cc - uses: - - grpc_base_headers - - gpr_base_headers - name: grpc_client_authority_filter headers: - src/core/ext/filters/http/client_authority_filter.h @@ -783,16 +784,19 @@ filegroups: src: - src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc + - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc + - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc - src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc plugin: grpc_resolver_dns_ares uses: - grpc_base - grpc_client_channel + - grpc_resolver_dns_selection - name: grpc_resolver_dns_native src: - src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc @@ -800,6 +804,14 @@ filegroups: uses: - grpc_base - grpc_client_channel + - grpc_resolver_dns_selection +- name: grpc_resolver_dns_selection + headers: + - src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h + src: + - src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc + uses: + - grpc_base - name: grpc_resolver_fake headers: - src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h @@ -1250,6 +1262,7 @@ filegroups: - include/grpcpp/impl/codegen/client_interceptor.h - include/grpcpp/impl/codegen/client_unary_call.h - include/grpcpp/impl/codegen/completion_queue.h + - include/grpcpp/impl/codegen/completion_queue_impl.h - include/grpcpp/impl/codegen/completion_queue_tag.h - include/grpcpp/impl/codegen/config.h - include/grpcpp/impl/codegen/core_codegen_interface.h @@ -1347,6 +1360,7 @@ filegroups: - include/grpcpp/alarm.h - include/grpcpp/alarm_impl.h - include/grpcpp/channel.h + - include/grpcpp/channel_impl.h - include/grpcpp/client_context.h - include/grpcpp/completion_queue.h - include/grpcpp/create_channel.h @@ -1381,18 +1395,21 @@ filegroups: - include/grpcpp/security/auth_metadata_processor.h - include/grpcpp/security/auth_metadata_processor_impl.h - include/grpcpp/security/credentials.h + - include/grpcpp/security/credentials_impl.h - include/grpcpp/security/server_credentials.h - include/grpcpp/security/server_credentials_impl.h - include/grpcpp/server.h - include/grpcpp/server_builder.h - include/grpcpp/server_builder_impl.h - include/grpcpp/server_context.h + - include/grpcpp/server_impl.h - include/grpcpp/server_posix.h - include/grpcpp/server_posix_impl.h - include/grpcpp/support/async_stream.h - include/grpcpp/support/async_unary_call.h - include/grpcpp/support/byte_buffer.h - include/grpcpp/support/channel_arguments.h + - include/grpcpp/support/channel_arguments_impl.h - include/grpcpp/support/client_callback.h - include/grpcpp/support/client_interceptor.h - include/grpcpp/support/config.h @@ -1413,6 +1430,7 @@ filegroups: - src/cpp/client/create_channel_internal.h - src/cpp/common/channel_filter.h - src/cpp/server/dynamic_thread_pool.h + - src/cpp/server/external_connection_acceptor_impl.h - src/cpp/server/health/default_health_check_service.h - src/cpp/server/thread_pool_interface.h - src/cpp/thread_manager/thread_manager.h @@ -1437,6 +1455,7 @@ filegroups: - src/cpp/server/channel_argument_option.cc - src/cpp/server/create_default_thread_pool.cc - src/cpp/server/dynamic_thread_pool.cc + - src/cpp/server/external_connection_acceptor_impl.cc - src/cpp/server/health/default_health_check_service.cc - src/cpp/server/health/health_check_service.cc - src/cpp/server/health/health_check_service_server_builder_option.cc @@ -1670,6 +1689,31 @@ libs: - grpc_test_util - grpc - gpr +- name: bm_callback_test_service_impl + build: test + language: c++ + headers: + - test/cpp/microbenchmarks/callback_test_service.h + src: + - src/proto/grpc/testing/echo.proto + - test/cpp/microbenchmarks/callback_test_service.cc + deps: + - grpc_benchmark + - benchmark + - grpc++_test_util_unsecure + - grpc_test_util_unsecure + - grpc++_unsecure + - grpc_unsecure + - gpr + - grpc++_test_config + defaults: benchmark +- name: dns_test_util + build: private + language: c++ + headers: + - test/cpp/naming/dns_test_util.h + src: + - test/cpp/naming/dns_test_util.cc - name: grpc++ build: all language: c++ @@ -4029,6 +4073,52 @@ targets: - linux - posix uses_polling: false +- name: bm_callback_streaming_ping_pong + build: test + language: c++ + headers: + - test/cpp/microbenchmarks/callback_streaming_ping_pong.h + src: + - test/cpp/microbenchmarks/bm_callback_streaming_ping_pong.cc + deps: + - grpc_benchmark + - benchmark + - grpc++_test_util_unsecure + - grpc_test_util_unsecure + - grpc++_unsecure + - grpc_unsecure + - gpr + - grpc++_test_config + - bm_callback_test_service_impl + benchmark: true + defaults: benchmark + platforms: + - mac + - linux + - posix +- name: bm_callback_unary_ping_pong + build: test + language: c++ + headers: + - test/cpp/microbenchmarks/callback_unary_ping_pong.h + src: + - test/cpp/microbenchmarks/bm_callback_unary_ping_pong.cc + deps: + - grpc_benchmark + - benchmark + - grpc++_test_util_unsecure + - grpc_test_util_unsecure + - grpc++_unsecure + - grpc_unsecure + - gpr + - grpc++_test_config + - bm_callback_test_service_impl + benchmark: true + defaults: benchmark + platforms: + - mac + - linux + - posix - name: bm_channel build: test language: c++ @@ -4522,6 +4612,7 @@ targets: src: - test/cpp/end2end/client_crash_test_server.cc deps: + - grpc++_test_config - grpc++_test_util - grpc_test_util - grpc++ @@ -4726,6 +4817,24 @@ targets: - grpc++ - grpc - gpr +- name: global_config_env_test + build: test + language: c++ + src: + - test/core/gprpp/global_config_env_test.cc + deps: + - gpr + - grpc_test_util_unsecure + uses_polling: false +- name: global_config_test + build: test + language: c++ + src: + - test/core/gprpp/global_config_test.cc + deps: + - gpr + - grpc_test_util_unsecure + uses_polling: false - name: golden_file_test gtest: true build: test @@ -4734,6 +4843,7 @@ targets: - src/proto/grpc/testing/compiler_test.proto - test/cpp/codegen/golden_file_test.cc deps: + - grpc++_test_config - grpc++ - grpc - gpr @@ -5159,6 +5269,19 @@ targets: - gpr uses: - grpc++_test +- name: port_sharing_end2end_test + gtest: true + build: test + language: c++ + src: + - test/cpp/end2end/port_sharing_end2end_test.cc + deps: + - test_tcp_server + - grpc++_test_util + - grpc_test_util + - grpc++ + - grpc + - gpr - name: proto_server_reflection_test gtest: true build: test @@ -5449,6 +5572,7 @@ targets: src: - test/cpp/end2end/server_crash_test_client.cc deps: + - grpc++_test_config - grpc++_test_util - grpc_test_util - grpc++ @@ -5496,6 +5620,18 @@ targets: - grpc++_unsecure - grpc_unsecure - gpr +- name: service_config_end2end_test + gtest: true + build: test + language: c++ + src: + - test/cpp/end2end/service_config_end2end_test.cc + deps: + - grpc++_test_util + - grpc_test_util + - grpc++ + - grpc + - gpr - name: service_config_test gtest: true build: test diff --git a/config.m4 b/config.m4 index ab2a717cbcd..bb30be56910 100644 --- a/config.m4 +++ b/config.m4 @@ -45,7 +45,6 @@ if test "$PHP_GRPC" != "no"; then third_party/address_sorting/address_sorting_posix.c \ third_party/address_sorting/address_sorting_windows.c \ src/core/lib/gpr/alloc.cc \ - src/core/lib/gpr/arena.cc \ src/core/lib/gpr/atm.cc \ src/core/lib/gpr/cpu_iphone.cc \ src/core/lib/gpr/cpu_linux.cc \ @@ -78,7 +77,9 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/gpr/tmpfile_posix.cc \ src/core/lib/gpr/tmpfile_windows.cc \ src/core/lib/gpr/wrap_memcpy.cc \ + src/core/lib/gprpp/arena.cc \ src/core/lib/gprpp/fork.cc \ + src/core/lib/gprpp/global_config_env.cc \ src/core/lib/gprpp/thd_posix.cc \ src/core/lib/gprpp/thd_windows.cc \ src/core/lib/profiling/basic_timers.cc \ @@ -110,12 +111,15 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/http/parser.cc \ src/core/lib/iomgr/buffer_list.cc \ src/core/lib/iomgr/call_combiner.cc \ + src/core/lib/iomgr/cfstream_handle.cc \ src/core/lib/iomgr/combiner.cc \ src/core/lib/iomgr/endpoint.cc \ + src/core/lib/iomgr/endpoint_cfstream.cc \ src/core/lib/iomgr/endpoint_pair_posix.cc \ src/core/lib/iomgr/endpoint_pair_uv.cc \ src/core/lib/iomgr/endpoint_pair_windows.cc \ src/core/lib/iomgr/error.cc \ + src/core/lib/iomgr/error_cfstream.cc \ src/core/lib/iomgr/ev_epoll1_linux.cc \ src/core/lib/iomgr/ev_epollex_linux.cc \ src/core/lib/iomgr/ev_poll_posix.cc \ @@ -136,6 +140,7 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/iomgr/iomgr_custom.cc \ src/core/lib/iomgr/iomgr_internal.cc \ src/core/lib/iomgr/iomgr_posix.cc \ + src/core/lib/iomgr/iomgr_posix_cfstream.cc \ src/core/lib/iomgr/iomgr_uv.cc \ src/core/lib/iomgr/iomgr_windows.cc \ src/core/lib/iomgr/is_epollexclusive_available.cc \ @@ -164,6 +169,7 @@ if test "$PHP_GRPC" != "no"; then src/core/lib/iomgr/socket_utils_windows.cc \ src/core/lib/iomgr/socket_windows.cc \ src/core/lib/iomgr/tcp_client.cc \ + src/core/lib/iomgr/tcp_client_cfstream.cc \ src/core/lib/iomgr/tcp_client_custom.cc \ src/core/lib/iomgr/tcp_client_posix.cc \ src/core/lib/iomgr/tcp_client_windows.cc \ @@ -397,12 +403,15 @@ if test "$PHP_GRPC" != "no"; then src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc \ + src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc \ + src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc \ + src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc \ src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \ src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \ src/core/ext/filters/census/grpc_context.cc \ @@ -686,6 +695,7 @@ if test "$PHP_GRPC" != "no"; then PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/pick_first) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/round_robin) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/xds) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns/c_ares) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns/native) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/fake) diff --git a/config.w32 b/config.w32 index 02eb773ebb8..c9faa8d9ac8 100644 --- a/config.w32 +++ b/config.w32 @@ -20,7 +20,6 @@ if (PHP_GRPC != "no") { "third_party\\address_sorting\\address_sorting_posix.c " + "third_party\\address_sorting\\address_sorting_windows.c " + "src\\core\\lib\\gpr\\alloc.cc " + - "src\\core\\lib\\gpr\\arena.cc " + "src\\core\\lib\\gpr\\atm.cc " + "src\\core\\lib\\gpr\\cpu_iphone.cc " + "src\\core\\lib\\gpr\\cpu_linux.cc " + @@ -53,7 +52,9 @@ if (PHP_GRPC != "no") { "src\\core\\lib\\gpr\\tmpfile_posix.cc " + "src\\core\\lib\\gpr\\tmpfile_windows.cc " + "src\\core\\lib\\gpr\\wrap_memcpy.cc " + + "src\\core\\lib\\gprpp\\arena.cc " + "src\\core\\lib\\gprpp\\fork.cc " + + "src\\core\\lib\\gprpp\\global_config_env.cc " + "src\\core\\lib\\gprpp\\thd_posix.cc " + "src\\core\\lib\\gprpp\\thd_windows.cc " + "src\\core\\lib\\profiling\\basic_timers.cc " + @@ -85,12 +86,15 @@ if (PHP_GRPC != "no") { "src\\core\\lib\\http\\parser.cc " + "src\\core\\lib\\iomgr\\buffer_list.cc " + "src\\core\\lib\\iomgr\\call_combiner.cc " + + "src\\core\\lib\\iomgr\\cfstream_handle.cc " + "src\\core\\lib\\iomgr\\combiner.cc " + "src\\core\\lib\\iomgr\\endpoint.cc " + + "src\\core\\lib\\iomgr\\endpoint_cfstream.cc " + "src\\core\\lib\\iomgr\\endpoint_pair_posix.cc " + "src\\core\\lib\\iomgr\\endpoint_pair_uv.cc " + "src\\core\\lib\\iomgr\\endpoint_pair_windows.cc " + "src\\core\\lib\\iomgr\\error.cc " + + "src\\core\\lib\\iomgr\\error_cfstream.cc " + "src\\core\\lib\\iomgr\\ev_epoll1_linux.cc " + "src\\core\\lib\\iomgr\\ev_epollex_linux.cc " + "src\\core\\lib\\iomgr\\ev_poll_posix.cc " + @@ -111,6 +115,7 @@ if (PHP_GRPC != "no") { "src\\core\\lib\\iomgr\\iomgr_custom.cc " + "src\\core\\lib\\iomgr\\iomgr_internal.cc " + "src\\core\\lib\\iomgr\\iomgr_posix.cc " + + "src\\core\\lib\\iomgr\\iomgr_posix_cfstream.cc " + "src\\core\\lib\\iomgr\\iomgr_uv.cc " + "src\\core\\lib\\iomgr\\iomgr_windows.cc " + "src\\core\\lib\\iomgr\\is_epollexclusive_available.cc " + @@ -139,6 +144,7 @@ if (PHP_GRPC != "no") { "src\\core\\lib\\iomgr\\socket_utils_windows.cc " + "src\\core\\lib\\iomgr\\socket_windows.cc " + "src\\core\\lib\\iomgr\\tcp_client.cc " + + "src\\core\\lib\\iomgr\\tcp_client_cfstream.cc " + "src\\core\\lib\\iomgr\\tcp_client_custom.cc " + "src\\core\\lib\\iomgr\\tcp_client_posix.cc " + "src\\core\\lib\\iomgr\\tcp_client_windows.cc " + @@ -372,12 +378,15 @@ if (PHP_GRPC != "no") { "src\\core\\ext\\filters\\client_channel\\lb_policy\\round_robin\\round_robin.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\dns_resolver_ares.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver.cc " + + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver_libuv.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver_posix.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver_windows.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_fallback.cc " + + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_libuv.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_posix.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_wrapper_windows.cc " + + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\dns_resolver_selection.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\native\\dns_resolver.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\sockaddr\\sockaddr_resolver.cc " + "src\\core\\ext\\filters\\census\\grpc_context.cc " + diff --git a/doc/environment_variables.md b/doc/environment_variables.md index 43dcd7616e7..778560d4273 100644 --- a/doc/environment_variables.md +++ b/doc/environment_variables.md @@ -50,6 +50,7 @@ some configuration as environment variables that can be set. resolver and load balancing policy interaction - compression - traces compression operations - connectivity_state - traces connectivity state changes to channels + - cronet - traces state in the cronet transport engine - executor - traces grpc's internal thread pool ('the executor') - fd_trace - traces fd create(), shutdown() and close() calls for channel fds. Also traces epoll fd create()/close() calls in epollex polling engine diff --git a/doc/g_stands_for.md b/doc/g_stands_for.md index b926db191de..90202b1b880 100644 --- a/doc/g_stands_for.md +++ b/doc/g_stands_for.md @@ -20,4 +20,5 @@ - 1.18 'g' stands for ['goose'](https://github.com/grpc/grpc/tree/v1.18.x) - 1.19 'g' stands for ['gold'](https://github.com/grpc/grpc/tree/v1.19.x) - 1.20 'g' stands for ['godric'](https://github.com/grpc/grpc/tree/v1.20.x) -- 1.21 'g' stands for ['gandalf'](https://github.com/grpc/grpc/tree/master) +- 1.21 'g' stands for ['gandalf'](https://github.com/grpc/grpc/tree/v1.21.x) +- 1.22 'g' stands for ['gale'](https://github.com/grpc/grpc/tree/master) diff --git a/doc/health-checking.md b/doc/health-checking.md index 7be8107b60f..22b6e1b4c09 100644 --- a/doc/health-checking.md +++ b/doc/health-checking.md @@ -43,6 +43,8 @@ message HealthCheckResponse { service Health { rpc Check(HealthCheckRequest) returns (HealthCheckResponse); + + rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse); } ``` @@ -68,3 +70,8 @@ matching semantics that both the client and server agree upon. A client can declare the server as unhealthy if the rpc is not finished after some amount of time. The client should be able to handle the case where server does not have the Health service. + +A client can call the `Watch` method to perform a streaming health-check. +The server will immediately send back a message indicating the current +serving status. It will then subsequently send a new message whenever +the service's serving status changes. diff --git a/doc/statuscodes.md b/doc/statuscodes.md index 3d4d87e931a..61e0d820b48 100644 --- a/doc/statuscodes.md +++ b/doc/statuscodes.md @@ -20,7 +20,7 @@ statuses are defined as such: | OUT_OF_RANGE | 11 | The operation was attempted past the valid range. E.g., seeking or reading past end-of-file. Unlike `INVALID_ARGUMENT`, this error indicates a problem that may be fixed if the system state changes. For example, a 32-bit file system will generate `INVALID_ARGUMENT` if asked to read at an offset that is not in the range [0,2^32-1], but it will generate `OUT_OF_RANGE` if asked to read from an offset past the current file size. There is a fair bit of overlap between `FAILED_PRECONDITION` and `OUT_OF_RANGE`. We recommend using `OUT_OF_RANGE` (the more specific error) when it applies so that callers who are iterating through a space can easily look for an `OUT_OF_RANGE` error to detect when they are done. | 400 Bad Request | | UNIMPLEMENTED | 12 | The operation is not implemented or is not supported/enabled in this service. | 501 Not Implemented | | INTERNAL | 13 | Internal errors. This means that some invariants expected by the underlying system have been broken. This error code is reserved for serious errors. | 500 Internal Server Error | -| UNAVAILABLE | 14 | The service is currently unavailable. This is most likely a transient condition, which can be corrected by retrying with a backoff. | 503 Service Unavailable | +| UNAVAILABLE | 14 | The service is currently unavailable. This is most likely a transient condition, which can be corrected by retrying with a backoff. Note that it is not always safe to retry non-idempotent operations. | 503 Service Unavailable | | DATA_LOSS | 15 | Unrecoverable data loss or corruption. | 500 Internal Server Error | All RPCs started at a client return a `status` object composed of an integer diff --git a/etc/roots.pem b/etc/roots.pem index be598710ddd..22bd2ab88dd 100644 --- a/etc/roots.pem +++ b/etc/roots.pem @@ -4552,3 +4552,149 @@ Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw 3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= -----END CERTIFICATE----- + +# Issuer: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI +# Subject: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI +# Label: "emSign Root CA - G1" +# Serial: 235931866688319308814040 +# MD5 Fingerprint: 9c:42:84:57:dd:cb:0b:a7:2e:95:ad:b6:f3:da:bc:ac +# SHA1 Fingerprint: 8a:c7:ad:8f:73:ac:4e:c1:b5:75:4d:a5:40:f4:fc:cf:7c:b5:8e:8c +# SHA256 Fingerprint: 40:f6:af:03:46:a9:9a:a1:cd:1d:55:5a:4e:9c:ce:62:c7:f9:63:46:03:ee:40:66:15:83:3d:c8:c8:d0:03:67 +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD +VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU +ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH +MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO +MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv +Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz +f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO +8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq +d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM +tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt +Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB +o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x +PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM +wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d +GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH +6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby +RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE----- + +# Issuer: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI +# Subject: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI +# Label: "emSign ECC Root CA - G3" +# Serial: 287880440101571086945156 +# MD5 Fingerprint: ce:0b:72:d1:9f:88:8e:d0:50:03:e8:e3:b8:8b:67:40 +# SHA1 Fingerprint: 30:43:fa:4f:f2:57:dc:a0:c3:80:ee:2e:58:ea:78:b2:3f:e6:bb:c1 +# SHA256 Fingerprint: 86:a1:ec:ba:08:9c:4a:8d:3b:be:27:34:c6:12:ba:34:1d:81:3e:04:3c:f9:e8:a8:62:cd:5c:57:a3:6b:be:6b +-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG +EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo +bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ +TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s +b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 +WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS +fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB +zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq +hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB +CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD ++JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE----- + +# Issuer: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI +# Subject: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI +# Label: "emSign Root CA - C1" +# Serial: 825510296613316004955058 +# MD5 Fingerprint: d8:e3:5d:01:21:fa:78:5a:b0:df:ba:d2:ee:2a:5f:68 +# SHA1 Fingerprint: e7:2e:f1:df:fc:b2:09:28:cf:5d:d4:d5:67:37:b1:51:cb:86:4f:01 +# SHA256 Fingerprint: 12:56:09:aa:30:1d:a0:a2:49:b9:7a:82:39:cb:6a:34:21:6f:44:dc:ac:9f:39:54:b1:42:92:f2:e8:c8:60:8f +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG +A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg +SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v +dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ +BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ +HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH +3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH +GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c +xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 +aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq +TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 +/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 +kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG +YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT ++xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo +WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= +-----END CERTIFICATE----- + +# Issuer: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI +# Subject: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI +# Label: "emSign ECC Root CA - C3" +# Serial: 582948710642506000014504 +# MD5 Fingerprint: 3e:53:b3:a3:81:ee:d7:10:f8:d3:b0:1d:17:92:f5:d5 +# SHA1 Fingerprint: b6:af:43:c2:9b:81:53:7d:f6:ef:6b:c3:1f:1f:60:15:0c:ee:48:66 +# SHA256 Fingerprint: bc:4d:80:9b:15:18:9d:78:db:3e:1d:8c:f4:f9:72:6a:79:5d:a1:64:3c:a5:f1:35:8e:1d:db:0e:dc:0d:7e:b3 +-----BEGIN CERTIFICATE----- +MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG +EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx +IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND +IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci +MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti +sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O +BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB +Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c +3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J +0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== +-----END CERTIFICATE----- + +# Issuer: CN=Hongkong Post Root CA 3 O=Hongkong Post +# Subject: CN=Hongkong Post Root CA 3 O=Hongkong Post +# Label: "Hongkong Post Root CA 3" +# Serial: 46170865288971385588281144162979347873371282084 +# MD5 Fingerprint: 11:fc:9f:bd:73:30:02:8a:fd:3f:f3:58:b9:cb:20:f0 +# SHA1 Fingerprint: 58:a2:d0:ec:20:52:81:5b:c1:f3:f8:64:02:24:4e:c2:8e:02:4b:02 +# SHA256 Fingerprint: 5a:2f:c0:3f:0c:83:b0:90:bb:fa:40:60:4b:09:88:44:6c:76:36:18:3d:f9:84:6e:17:10:1a:44:7f:b8:ef:d6 +-----BEGIN CERTIFICATE----- +MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQEL +BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ +SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n +a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwMjI5NDZaFw00MjA2MDMwMjI5 +NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT +CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMXSG9u +Z2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCziNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFO +dem1p+/l6TWZ5Mwc50tfjTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mI +VoBc+L0sPOFMV4i707mV78vH9toxdCim5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV +9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOesL4jpNrcyCse2m5FHomY +2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj0mRiikKY +vLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+Tt +bNe/JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZb +x39ri1UbSsUgYT2uy1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+ +l2oBlKN8W4UdKjk60FSh0Tlxnf0h+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YK +TE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsGxVd7GYYKecsAyVKvQv83j+Gj +Hno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwIDAQABo2MwYTAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e +i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEw +DQYJKoZIhvcNAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG +7BJ8dNVI0lkUmcDrudHr9EgwW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCk +MpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWldy8joRTnU+kLBEUx3XZL7av9YROXr +gZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov+BS5gLNdTaqX4fnk +GMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDceqFS +3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJm +Ozj/2ZQw9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+ +l6mc1X5VTMbeRRAc6uk7nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6c +JfTzPV4e0hz5sy229zdcxsshTrD3mUcYhcErulWuBurQB7Lcq9CClnXO0lD+mefP +L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa +LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG +mpv0 +-----END CERTIFICATE----- diff --git a/examples/BUILD b/examples/BUILD index d2b39b87f4d..a9dd94902a4 100644 --- a/examples/BUILD +++ b/examples/BUILD @@ -16,9 +16,9 @@ licenses(["notice"]) # 3-clause BSD package(default_visibility = ["//visibility:public"]) -load("@grpc_python_dependencies//:requirements.bzl", "requirement") load("//bazel:grpc_build_system.bzl", "grpc_proto_library") -load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library") +load("//bazel:cc_grpc_library.bzl", "cc_grpc_library") +load("//bazel:python_rules.bzl", "py_proto_library") grpc_proto_library( name = "auth_sample", @@ -30,11 +30,25 @@ grpc_proto_library( srcs = ["protos/hellostreamingworld.proto"], ) -grpc_proto_library( - name = "helloworld", +# The following three rules demonstrate the usage of the cc_grpc_library rule in +# in a mode compatible with the native proto_library and cc_proto_library rules. +proto_library( + name = "helloworld_proto", srcs = ["protos/helloworld.proto"], ) +cc_proto_library( + name = "helloworld_cc_proto", + deps = [":helloworld_proto"], +) + +cc_grpc_library( + name = "helloworld_cc_grpc", + srcs = [":helloworld_proto"], + grpc_only = True, + deps = [":helloworld_cc_proto"], +) + grpc_proto_library( name = "route_guide", srcs = ["protos/route_guide.proto"], @@ -45,11 +59,14 @@ grpc_proto_library( srcs = ["protos/keyvaluestore.proto"], ) +proto_library( + name = "helloworld_proto_descriptor", + srcs = ["protos/helloworld.proto"], +) + py_proto_library( name = "py_helloworld", - protos = ["protos/helloworld.proto"], - with_grpc = True, - deps = [requirement('protobuf'),], + deps = [":helloworld_proto_descriptor"], ) cc_binary( @@ -57,7 +74,7 @@ cc_binary( srcs = ["cpp/helloworld/greeter_client.cc"], defines = ["BAZEL_BUILD"], deps = [ - ":helloworld", + ":helloworld_cc_grpc", "//:grpc++", ], ) @@ -67,7 +84,7 @@ cc_binary( srcs = ["cpp/helloworld/greeter_async_client.cc"], defines = ["BAZEL_BUILD"], deps = [ - ":helloworld", + ":helloworld_cc_grpc", "//:grpc++", ], ) @@ -77,7 +94,7 @@ cc_binary( srcs = ["cpp/helloworld/greeter_async_client2.cc"], defines = ["BAZEL_BUILD"], deps = [ - ":helloworld", + ":helloworld_cc_grpc", "//:grpc++", ], ) @@ -87,7 +104,7 @@ cc_binary( srcs = ["cpp/helloworld/greeter_server.cc"], defines = ["BAZEL_BUILD"], deps = [ - ":helloworld", + ":helloworld_cc_grpc", "//:grpc++", ], ) @@ -97,7 +114,7 @@ cc_binary( srcs = ["cpp/helloworld/greeter_async_server.cc"], defines = ["BAZEL_BUILD"], deps = [ - ":helloworld", + ":helloworld_cc_grpc", "//:grpc++", ], ) @@ -107,7 +124,7 @@ cc_binary( srcs = ["cpp/metadata/greeter_client.cc"], defines = ["BAZEL_BUILD"], deps = [ - ":helloworld", + ":helloworld_cc_grpc", "//:grpc++", ], ) @@ -117,7 +134,7 @@ cc_binary( srcs = ["cpp/metadata/greeter_server.cc"], defines = ["BAZEL_BUILD"], deps = [ - ":helloworld", + ":helloworld_cc_grpc", "//:grpc++", ], ) @@ -127,7 +144,7 @@ cc_binary( srcs = ["cpp/load_balancing/greeter_client.cc"], defines = ["BAZEL_BUILD"], deps = [ - ":helloworld", + ":helloworld_cc_grpc", "//:grpc++", ], ) @@ -137,7 +154,7 @@ cc_binary( srcs = ["cpp/load_balancing/greeter_server.cc"], defines = ["BAZEL_BUILD"], deps = [ - ":helloworld", + ":helloworld_cc_grpc", "//:grpc++", ], ) @@ -147,7 +164,7 @@ cc_binary( srcs = ["cpp/compression/greeter_client.cc"], defines = ["BAZEL_BUILD"], deps = [ - ":helloworld", + ":helloworld_cc_grpc", "//:grpc++", ], ) @@ -157,15 +174,17 @@ cc_binary( srcs = ["cpp/compression/greeter_server.cc"], defines = ["BAZEL_BUILD"], deps = [ - ":helloworld", + ":helloworld_cc_grpc", "//:grpc++", ], ) cc_binary( name = "keyvaluestore_client", - srcs = ["cpp/keyvaluestore/caching_interceptor.h", - "cpp/keyvaluestore/client.cc"], + srcs = [ + "cpp/keyvaluestore/caching_interceptor.h", + "cpp/keyvaluestore/client.cc", + ], defines = ["BAZEL_BUILD"], deps = [ ":keyvaluestore", diff --git a/examples/python/errors/client.py b/examples/python/errors/client.py index a79b8fce1bd..c762d798dc2 100644 --- a/examples/python/errors/client.py +++ b/examples/python/errors/client.py @@ -20,8 +20,8 @@ import grpc from grpc_status import rpc_status from google.rpc import error_details_pb2 -from examples.protos import helloworld_pb2 -from examples.protos import helloworld_pb2_grpc +from examples import helloworld_pb2 +from examples import helloworld_pb2_grpc _LOGGER = logging.getLogger(__name__) diff --git a/examples/python/errors/server.py b/examples/python/errors/server.py index f49586b848a..50d4a2ac671 100644 --- a/examples/python/errors/server.py +++ b/examples/python/errors/server.py @@ -24,8 +24,8 @@ from grpc_status import rpc_status from google.protobuf import any_pb2 from google.rpc import code_pb2, status_pb2, error_details_pb2 -from examples.protos import helloworld_pb2 -from examples.protos import helloworld_pb2_grpc +from examples import helloworld_pb2 +from examples import helloworld_pb2_grpc _ONE_DAY_IN_SECONDS = 60 * 60 * 24 diff --git a/examples/python/errors/test/_error_handling_example_test.py b/examples/python/errors/test/_error_handling_example_test.py index a79ca45e2a1..9eb81ba3742 100644 --- a/examples/python/errors/test/_error_handling_example_test.py +++ b/examples/python/errors/test/_error_handling_example_test.py @@ -26,7 +26,7 @@ import logging import grpc -from examples.protos import helloworld_pb2_grpc +from examples import helloworld_pb2_grpc from examples.python.errors import client as error_handling_client from examples.python.errors import server as error_handling_server diff --git a/examples/python/multiprocessing/BUILD b/examples/python/multiprocessing/BUILD index 6de1e947d85..0e135f471f2 100644 --- a/examples/python/multiprocessing/BUILD +++ b/examples/python/multiprocessing/BUILD @@ -15,12 +15,17 @@ # limitations under the License. load("@grpc_python_dependencies//:requirements.bzl", "requirement") -load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library") +load("//bazel:python_rules.bzl", "py_proto_library") -py_proto_library( +proto_library( name = "prime_proto", - protos = ["prime.proto",], - deps = [requirement("protobuf")], + srcs = ["prime.proto"] +) + +py_proto_library( + name = "prime_proto_pb2", + deps = [":prime_proto"], + well_known_protos = False, ) py_binary( @@ -29,7 +34,7 @@ py_binary( srcs = ["client.py"], deps = [ "//src/python/grpcio/grpc:grpcio", - ":prime_proto", + ":prime_proto_pb2", ], default_python_version = "PY3", ) @@ -40,7 +45,7 @@ py_binary( srcs = ["server.py"], deps = [ "//src/python/grpcio/grpc:grpcio", - ":prime_proto" + ":prime_proto_pb2" ] + select({ "//conditions:default": [requirement("futures")], "//:python3": [], diff --git a/examples/python/wait_for_ready/wait_for_ready_example.py b/examples/python/wait_for_ready/wait_for_ready_example.py index 7c16b9bd4a1..a0f076e894a 100644 --- a/examples/python/wait_for_ready/wait_for_ready_example.py +++ b/examples/python/wait_for_ready/wait_for_ready_example.py @@ -22,8 +22,8 @@ import threading import grpc -from examples.protos import helloworld_pb2 -from examples.protos import helloworld_pb2_grpc +from examples import helloworld_pb2 +from examples import helloworld_pb2_grpc _LOGGER = logging.getLogger(__name__) _LOGGER.setLevel(logging.INFO) @@ -33,10 +33,13 @@ _ONE_DAY_IN_SECONDS = 60 * 60 * 24 @contextmanager def get_free_loopback_tcp_port(): - tcp_socket = socket.socket(socket.AF_INET6) + if socket.has_ipv6: + tcp_socket = socket.socket(socket.AF_INET6) + else: + tcp_socket = socket.socket(socket.AF_INET) tcp_socket.bind(('', 0)) address_tuple = tcp_socket.getsockname() - yield "[::1]:%s" % (address_tuple[1]) + yield "localhost:%s" % (address_tuple[1]) tcp_socket.close() diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index de1bb0ae57f..0e9a50ddcae 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -23,15 +23,15 @@ Pod::Spec.new do |s| s.name = 'gRPC-C++' # TODO (mxyan): use version that match gRPC version when pod is stabilized - # version = '1.21.0-dev' - version = '0.0.8-dev' + # version = '1.22.0-dev' + version = '0.0.9-dev' s.version = version s.summary = 'gRPC C++ library' s.homepage = 'https://grpc.io' s.license = 'Apache License, Version 2.0' s.authors = { 'The gRPC contributors' => 'grpc-packages@google.com' } - grpc_version = '1.21.0-dev' + grpc_version = '1.22.0-dev' s.source = { :git => 'https://github.com/grpc/grpc.git', @@ -72,7 +72,7 @@ Pod::Spec.new do |s| s.default_subspecs = 'Interface', 'Implementation' # Certificates, to be able to establish TLS connections: - s.resource_bundles = { 'gRPCCertificates' => ['etc/roots.pem'] } + s.resource_bundles = { 'gRPCCertificates-Cpp' => ['etc/roots.pem'] } s.header_mappings_dir = 'include/grpcpp' @@ -82,6 +82,7 @@ Pod::Spec.new do |s| ss.source_files = 'include/grpcpp/alarm.h', 'include/grpcpp/alarm_impl.h', 'include/grpcpp/channel.h', + 'include/grpcpp/channel_impl.h', 'include/grpcpp/client_context.h', 'include/grpcpp/completion_queue.h', 'include/grpcpp/create_channel.h', @@ -116,18 +117,21 @@ Pod::Spec.new do |s| 'include/grpcpp/security/auth_metadata_processor.h', 'include/grpcpp/security/auth_metadata_processor_impl.h', 'include/grpcpp/security/credentials.h', + 'include/grpcpp/security/credentials_impl.h', 'include/grpcpp/security/server_credentials.h', 'include/grpcpp/security/server_credentials_impl.h', 'include/grpcpp/server.h', 'include/grpcpp/server_builder.h', 'include/grpcpp/server_builder_impl.h', 'include/grpcpp/server_context.h', + 'include/grpcpp/server_impl.h', 'include/grpcpp/server_posix.h', 'include/grpcpp/server_posix_impl.h', 'include/grpcpp/support/async_stream.h', 'include/grpcpp/support/async_unary_call.h', 'include/grpcpp/support/byte_buffer.h', 'include/grpcpp/support/channel_arguments.h', + 'include/grpcpp/support/channel_arguments_impl.h', 'include/grpcpp/support/client_callback.h', 'include/grpcpp/support/client_interceptor.h', 'include/grpcpp/support/config.h', @@ -159,6 +163,7 @@ Pod::Spec.new do |s| 'include/grpcpp/impl/codegen/client_interceptor.h', 'include/grpcpp/impl/codegen/client_unary_call.h', 'include/grpcpp/impl/codegen/completion_queue.h', + 'include/grpcpp/impl/codegen/completion_queue_impl.h', 'include/grpcpp/impl/codegen/completion_queue_tag.h', 'include/grpcpp/impl/codegen/config.h', 'include/grpcpp/impl/codegen/core_codegen_interface.h', @@ -202,6 +207,7 @@ Pod::Spec.new do |s| 'src/cpp/client/create_channel_internal.h', 'src/cpp/common/channel_filter.h', 'src/cpp/server/dynamic_thread_pool.h', + 'src/cpp/server/external_connection_acceptor_impl.h', 'src/cpp/server/health/default_health_check_service.h', 'src/cpp/server/thread_pool_interface.h', 'src/cpp/thread_manager/thread_manager.h', @@ -233,6 +239,7 @@ Pod::Spec.new do |s| 'src/cpp/server/channel_argument_option.cc', 'src/cpp/server/create_default_thread_pool.cc', 'src/cpp/server/dynamic_thread_pool.cc', + 'src/cpp/server/external_connection_acceptor_impl.cc', 'src/cpp/server/health/default_health_check_service.cc', 'src/cpp/server/health/health_check_service.cc', 'src/cpp/server/health/health_check_service_server_builder_option.cc', @@ -264,8 +271,13 @@ Pod::Spec.new do |s| 'src/core/lib/gpr/tmpfile.h', 'src/core/lib/gpr/useful.h', 'src/core/lib/gprpp/abstract.h', + 'src/core/lib/gprpp/arena.h', 'src/core/lib/gprpp/atomic.h', 'src/core/lib/gprpp/fork.h', + 'src/core/lib/gprpp/global_config.h', + 'src/core/lib/gprpp/global_config_custom.h', + 'src/core/lib/gprpp/global_config_env.h', + 'src/core/lib/gprpp/global_config_generic.h', 'src/core/lib/gprpp/manual_constructor.h', 'src/core/lib/gprpp/map.h', 'src/core/lib/gprpp/memory.h', @@ -433,12 +445,15 @@ Pod::Spec.new do |s| 'src/core/lib/iomgr/block_annotate.h', 'src/core/lib/iomgr/buffer_list.h', 'src/core/lib/iomgr/call_combiner.h', + 'src/core/lib/iomgr/cfstream_handle.h', 'src/core/lib/iomgr/closure.h', 'src/core/lib/iomgr/combiner.h', 'src/core/lib/iomgr/dynamic_annotations.h', 'src/core/lib/iomgr/endpoint.h', + 'src/core/lib/iomgr/endpoint_cfstream.h', 'src/core/lib/iomgr/endpoint_pair.h', 'src/core/lib/iomgr/error.h', + 'src/core/lib/iomgr/error_cfstream.h', 'src/core/lib/iomgr/error_internal.h', 'src/core/lib/iomgr/ev_epoll1_linux.h', 'src/core/lib/iomgr/ev_epollex_linux.h', @@ -505,6 +520,7 @@ Pod::Spec.new do |s| 'src/core/lib/slice/slice_hash_table.h', 'src/core/lib/slice/slice_internal.h', 'src/core/lib/slice/slice_string_helpers.h', + 'src/core/lib/slice/slice_utils.h', 'src/core/lib/slice/slice_weak_hash_table.h', 'src/core/lib/surface/api_trace.h', 'src/core/lib/surface/call.h', @@ -549,6 +565,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h', + 'src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h', 'src/core/ext/filters/max_age/max_age_filter.h', 'src/core/ext/filters/message_size/message_size_filter.h', 'src/core/ext/filters/http/client_authority_filter.h', @@ -562,6 +579,7 @@ Pod::Spec.new do |s| 'src/cpp/client/create_channel_internal.h', 'src/cpp/common/channel_filter.h', 'src/cpp/server/dynamic_thread_pool.h', + 'src/cpp/server/external_connection_acceptor_impl.h', 'src/cpp/server/health/default_health_check_service.h', 'src/cpp/server/thread_pool_interface.h', 'src/cpp/thread_manager/thread_manager.h', @@ -582,8 +600,13 @@ Pod::Spec.new do |s| 'src/core/lib/gpr/tmpfile.h', 'src/core/lib/gpr/useful.h', 'src/core/lib/gprpp/abstract.h', + 'src/core/lib/gprpp/arena.h', 'src/core/lib/gprpp/atomic.h', 'src/core/lib/gprpp/fork.h', + 'src/core/lib/gprpp/global_config.h', + 'src/core/lib/gprpp/global_config_custom.h', + 'src/core/lib/gprpp/global_config_env.h', + 'src/core/lib/gprpp/global_config_generic.h', 'src/core/lib/gprpp/manual_constructor.h', 'src/core/lib/gprpp/map.h', 'src/core/lib/gprpp/memory.h', @@ -626,12 +649,15 @@ Pod::Spec.new do |s| 'src/core/lib/iomgr/block_annotate.h', 'src/core/lib/iomgr/buffer_list.h', 'src/core/lib/iomgr/call_combiner.h', + 'src/core/lib/iomgr/cfstream_handle.h', 'src/core/lib/iomgr/closure.h', 'src/core/lib/iomgr/combiner.h', 'src/core/lib/iomgr/dynamic_annotations.h', 'src/core/lib/iomgr/endpoint.h', + 'src/core/lib/iomgr/endpoint_cfstream.h', 'src/core/lib/iomgr/endpoint_pair.h', 'src/core/lib/iomgr/error.h', + 'src/core/lib/iomgr/error_cfstream.h', 'src/core/lib/iomgr/error_internal.h', 'src/core/lib/iomgr/ev_epoll1_linux.h', 'src/core/lib/iomgr/ev_epollex_linux.h', @@ -698,6 +724,7 @@ Pod::Spec.new do |s| 'src/core/lib/slice/slice_hash_table.h', 'src/core/lib/slice/slice_internal.h', 'src/core/lib/slice/slice_string_helpers.h', + 'src/core/lib/slice/slice_utils.h', 'src/core/lib/slice/slice_weak_hash_table.h', 'src/core/lib/surface/api_trace.h', 'src/core/lib/surface/call.h', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 5cf45c63cef..8ad00aad096 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -22,7 +22,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-Core' - version = '1.21.0-dev' + version = '1.22.0-dev' s.version = version s.summary = 'Core cross-platform gRPC library, written in C' s.homepage = 'https://grpc.io' @@ -205,8 +205,13 @@ Pod::Spec.new do |s| 'src/core/lib/gpr/tmpfile.h', 'src/core/lib/gpr/useful.h', 'src/core/lib/gprpp/abstract.h', + 'src/core/lib/gprpp/arena.h', 'src/core/lib/gprpp/atomic.h', 'src/core/lib/gprpp/fork.h', + 'src/core/lib/gprpp/global_config.h', + 'src/core/lib/gprpp/global_config_custom.h', + 'src/core/lib/gprpp/global_config_env.h', + 'src/core/lib/gprpp/global_config_generic.h', 'src/core/lib/gprpp/manual_constructor.h', 'src/core/lib/gprpp/map.h', 'src/core/lib/gprpp/memory.h', @@ -215,7 +220,6 @@ Pod::Spec.new do |s| 'src/core/lib/gprpp/thd.h', 'src/core/lib/profiling/timers.h', 'src/core/lib/gpr/alloc.cc', - 'src/core/lib/gpr/arena.cc', 'src/core/lib/gpr/atm.cc', 'src/core/lib/gpr/cpu_iphone.cc', 'src/core/lib/gpr/cpu_linux.cc', @@ -248,7 +252,9 @@ Pod::Spec.new do |s| 'src/core/lib/gpr/tmpfile_posix.cc', 'src/core/lib/gpr/tmpfile_windows.cc', 'src/core/lib/gpr/wrap_memcpy.cc', + 'src/core/lib/gprpp/arena.cc', 'src/core/lib/gprpp/fork.cc', + 'src/core/lib/gprpp/global_config_env.cc', 'src/core/lib/gprpp/thd_posix.cc', 'src/core/lib/gprpp/thd_windows.cc', 'src/core/lib/profiling/basic_timers.cc', @@ -413,12 +419,15 @@ Pod::Spec.new do |s| 'src/core/lib/iomgr/block_annotate.h', 'src/core/lib/iomgr/buffer_list.h', 'src/core/lib/iomgr/call_combiner.h', + 'src/core/lib/iomgr/cfstream_handle.h', 'src/core/lib/iomgr/closure.h', 'src/core/lib/iomgr/combiner.h', 'src/core/lib/iomgr/dynamic_annotations.h', 'src/core/lib/iomgr/endpoint.h', + 'src/core/lib/iomgr/endpoint_cfstream.h', 'src/core/lib/iomgr/endpoint_pair.h', 'src/core/lib/iomgr/error.h', + 'src/core/lib/iomgr/error_cfstream.h', 'src/core/lib/iomgr/error_internal.h', 'src/core/lib/iomgr/ev_epoll1_linux.h', 'src/core/lib/iomgr/ev_epollex_linux.h', @@ -485,6 +494,7 @@ Pod::Spec.new do |s| 'src/core/lib/slice/slice_hash_table.h', 'src/core/lib/slice/slice_internal.h', 'src/core/lib/slice/slice_string_helpers.h', + 'src/core/lib/slice/slice_utils.h', 'src/core/lib/slice/slice_weak_hash_table.h', 'src/core/lib/surface/api_trace.h', 'src/core/lib/surface/call.h', @@ -529,6 +539,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h', + 'src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h', 'src/core/ext/filters/max_age/max_age_filter.h', 'src/core/ext/filters/message_size/message_size_filter.h', 'src/core/ext/filters/http/client_authority_filter.h', @@ -561,12 +572,15 @@ Pod::Spec.new do |s| 'src/core/lib/http/parser.cc', 'src/core/lib/iomgr/buffer_list.cc', 'src/core/lib/iomgr/call_combiner.cc', + 'src/core/lib/iomgr/cfstream_handle.cc', 'src/core/lib/iomgr/combiner.cc', 'src/core/lib/iomgr/endpoint.cc', + 'src/core/lib/iomgr/endpoint_cfstream.cc', 'src/core/lib/iomgr/endpoint_pair_posix.cc', 'src/core/lib/iomgr/endpoint_pair_uv.cc', 'src/core/lib/iomgr/endpoint_pair_windows.cc', 'src/core/lib/iomgr/error.cc', + 'src/core/lib/iomgr/error_cfstream.cc', 'src/core/lib/iomgr/ev_epoll1_linux.cc', 'src/core/lib/iomgr/ev_epollex_linux.cc', 'src/core/lib/iomgr/ev_poll_posix.cc', @@ -587,6 +601,7 @@ Pod::Spec.new do |s| 'src/core/lib/iomgr/iomgr_custom.cc', 'src/core/lib/iomgr/iomgr_internal.cc', 'src/core/lib/iomgr/iomgr_posix.cc', + 'src/core/lib/iomgr/iomgr_posix_cfstream.cc', 'src/core/lib/iomgr/iomgr_uv.cc', 'src/core/lib/iomgr/iomgr_windows.cc', 'src/core/lib/iomgr/is_epollexclusive_available.cc', @@ -615,6 +630,7 @@ Pod::Spec.new do |s| 'src/core/lib/iomgr/socket_utils_windows.cc', 'src/core/lib/iomgr/socket_windows.cc', 'src/core/lib/iomgr/tcp_client.cc', + 'src/core/lib/iomgr/tcp_client_cfstream.cc', 'src/core/lib/iomgr/tcp_client_custom.cc', 'src/core/lib/iomgr/tcp_client_posix.cc', 'src/core/lib/iomgr/tcp_client_windows.cc', @@ -845,12 +861,15 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc', + 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc', + 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', + 'src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc', 'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', 'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', 'src/core/ext/filters/census/grpc_context.cc', @@ -859,15 +878,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/http/client_authority_filter.cc', 'src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc', 'src/core/ext/filters/workarounds/workaround_utils.cc', - 'src/core/plugin_registry/grpc_plugin_registry.cc', - 'src/core/lib/iomgr/cfstream_handle.cc', - 'src/core/lib/iomgr/endpoint_cfstream.cc', - 'src/core/lib/iomgr/error_cfstream.cc', - 'src/core/lib/iomgr/iomgr_posix_cfstream.cc', - 'src/core/lib/iomgr/tcp_client_cfstream.cc', - 'src/core/lib/iomgr/cfstream_handle.h', - 'src/core/lib/iomgr/endpoint_cfstream.h', - 'src/core/lib/iomgr/error_cfstream.h' + 'src/core/plugin_registry/grpc_plugin_registry.cc' ss.private_header_files = 'src/core/lib/gpr/alloc.h', 'src/core/lib/gpr/arena.h', @@ -886,8 +897,13 @@ Pod::Spec.new do |s| 'src/core/lib/gpr/tmpfile.h', 'src/core/lib/gpr/useful.h', 'src/core/lib/gprpp/abstract.h', + 'src/core/lib/gprpp/arena.h', 'src/core/lib/gprpp/atomic.h', 'src/core/lib/gprpp/fork.h', + 'src/core/lib/gprpp/global_config.h', + 'src/core/lib/gprpp/global_config_custom.h', + 'src/core/lib/gprpp/global_config_env.h', + 'src/core/lib/gprpp/global_config_generic.h', 'src/core/lib/gprpp/manual_constructor.h', 'src/core/lib/gprpp/map.h', 'src/core/lib/gprpp/memory.h', @@ -1055,12 +1071,15 @@ Pod::Spec.new do |s| 'src/core/lib/iomgr/block_annotate.h', 'src/core/lib/iomgr/buffer_list.h', 'src/core/lib/iomgr/call_combiner.h', + 'src/core/lib/iomgr/cfstream_handle.h', 'src/core/lib/iomgr/closure.h', 'src/core/lib/iomgr/combiner.h', 'src/core/lib/iomgr/dynamic_annotations.h', 'src/core/lib/iomgr/endpoint.h', + 'src/core/lib/iomgr/endpoint_cfstream.h', 'src/core/lib/iomgr/endpoint_pair.h', 'src/core/lib/iomgr/error.h', + 'src/core/lib/iomgr/error_cfstream.h', 'src/core/lib/iomgr/error_internal.h', 'src/core/lib/iomgr/ev_epoll1_linux.h', 'src/core/lib/iomgr/ev_epollex_linux.h', @@ -1127,6 +1146,7 @@ Pod::Spec.new do |s| 'src/core/lib/slice/slice_hash_table.h', 'src/core/lib/slice/slice_internal.h', 'src/core/lib/slice/slice_string_helpers.h', + 'src/core/lib/slice/slice_utils.h', 'src/core/lib/slice/slice_weak_hash_table.h', 'src/core/lib/surface/api_trace.h', 'src/core/lib/surface/call.h', @@ -1171,14 +1191,12 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h', + 'src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h', 'src/core/ext/filters/max_age/max_age_filter.h', 'src/core/ext/filters/message_size/message_size_filter.h', 'src/core/ext/filters/http/client_authority_filter.h', 'src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h', - 'src/core/ext/filters/workarounds/workaround_utils.h', - 'src/core/lib/iomgr/cfstream_handle.h', - 'src/core/lib/iomgr/endpoint_cfstream.h', - 'src/core/lib/iomgr/error_cfstream.h' + 'src/core/ext/filters/workarounds/workaround_utils.h' end # CFStream is now default. Leaving this subspec only for compatibility purpose. diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec index 0e905bd97bd..1cac59c6cc4 100644 --- a/gRPC-ProtoRPC.podspec +++ b/gRPC-ProtoRPC.podspec @@ -21,7 +21,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-ProtoRPC' - version = '1.21.0-dev' + version = '1.22.0-dev' s.version = version s.summary = 'RPC library for Protocol Buffers, based on gRPC' s.homepage = 'https://grpc.io' diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec index df86ef7ed34..6f033ea71b7 100644 --- a/gRPC-RxLibrary.podspec +++ b/gRPC-RxLibrary.podspec @@ -21,7 +21,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-RxLibrary' - version = '1.21.0-dev' + version = '1.22.0-dev' s.version = version s.summary = 'Reactive Extensions library for iOS/OSX.' s.homepage = 'https://grpc.io' diff --git a/gRPC.podspec b/gRPC.podspec index b3c7a55a2e1..e9c3fd7bee0 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -20,7 +20,7 @@ Pod::Spec.new do |s| s.name = 'gRPC' - version = '1.21.0-dev' + version = '1.22.0-dev' s.version = version s.summary = 'gRPC client library for iOS/OSX' s.homepage = 'https://grpc.io' diff --git a/grpc.gemspec b/grpc.gemspec index 15c26f11569..0bbf10fb361 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -99,8 +99,13 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/gpr/tmpfile.h ) s.files += %w( src/core/lib/gpr/useful.h ) s.files += %w( src/core/lib/gprpp/abstract.h ) + s.files += %w( src/core/lib/gprpp/arena.h ) s.files += %w( src/core/lib/gprpp/atomic.h ) s.files += %w( src/core/lib/gprpp/fork.h ) + s.files += %w( src/core/lib/gprpp/global_config.h ) + s.files += %w( src/core/lib/gprpp/global_config_custom.h ) + s.files += %w( src/core/lib/gprpp/global_config_env.h ) + s.files += %w( src/core/lib/gprpp/global_config_generic.h ) s.files += %w( src/core/lib/gprpp/manual_constructor.h ) s.files += %w( src/core/lib/gprpp/map.h ) s.files += %w( src/core/lib/gprpp/memory.h ) @@ -109,7 +114,6 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/gprpp/thd.h ) s.files += %w( src/core/lib/profiling/timers.h ) s.files += %w( src/core/lib/gpr/alloc.cc ) - s.files += %w( src/core/lib/gpr/arena.cc ) s.files += %w( src/core/lib/gpr/atm.cc ) s.files += %w( src/core/lib/gpr/cpu_iphone.cc ) s.files += %w( src/core/lib/gpr/cpu_linux.cc ) @@ -142,7 +146,9 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/gpr/tmpfile_posix.cc ) s.files += %w( src/core/lib/gpr/tmpfile_windows.cc ) s.files += %w( src/core/lib/gpr/wrap_memcpy.cc ) + s.files += %w( src/core/lib/gprpp/arena.cc ) s.files += %w( src/core/lib/gprpp/fork.cc ) + s.files += %w( src/core/lib/gprpp/global_config_env.cc ) s.files += %w( src/core/lib/gprpp/thd_posix.cc ) s.files += %w( src/core/lib/gprpp/thd_windows.cc ) s.files += %w( src/core/lib/profiling/basic_timers.cc ) @@ -347,12 +353,15 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/iomgr/block_annotate.h ) s.files += %w( src/core/lib/iomgr/buffer_list.h ) s.files += %w( src/core/lib/iomgr/call_combiner.h ) + s.files += %w( src/core/lib/iomgr/cfstream_handle.h ) s.files += %w( src/core/lib/iomgr/closure.h ) s.files += %w( src/core/lib/iomgr/combiner.h ) s.files += %w( src/core/lib/iomgr/dynamic_annotations.h ) s.files += %w( src/core/lib/iomgr/endpoint.h ) + s.files += %w( src/core/lib/iomgr/endpoint_cfstream.h ) s.files += %w( src/core/lib/iomgr/endpoint_pair.h ) s.files += %w( src/core/lib/iomgr/error.h ) + s.files += %w( src/core/lib/iomgr/error_cfstream.h ) s.files += %w( src/core/lib/iomgr/error_internal.h ) s.files += %w( src/core/lib/iomgr/ev_epoll1_linux.h ) s.files += %w( src/core/lib/iomgr/ev_epollex_linux.h ) @@ -419,6 +428,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/slice/slice_hash_table.h ) s.files += %w( src/core/lib/slice/slice_internal.h ) s.files += %w( src/core/lib/slice/slice_string_helpers.h ) + s.files += %w( src/core/lib/slice/slice_utils.h ) s.files += %w( src/core/lib/slice/slice_weak_hash_table.h ) s.files += %w( src/core/lib/surface/api_trace.h ) s.files += %w( src/core/lib/surface/call.h ) @@ -463,6 +473,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/filters/client_channel/lb_policy/subchannel_list.h ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h ) + s.files += %w( src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h ) s.files += %w( src/core/ext/filters/max_age/max_age_filter.h ) s.files += %w( src/core/ext/filters/message_size/message_size_filter.h ) s.files += %w( src/core/ext/filters/http/client_authority_filter.h ) @@ -495,12 +506,15 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/http/parser.cc ) s.files += %w( src/core/lib/iomgr/buffer_list.cc ) s.files += %w( src/core/lib/iomgr/call_combiner.cc ) + s.files += %w( src/core/lib/iomgr/cfstream_handle.cc ) s.files += %w( src/core/lib/iomgr/combiner.cc ) s.files += %w( src/core/lib/iomgr/endpoint.cc ) + s.files += %w( src/core/lib/iomgr/endpoint_cfstream.cc ) s.files += %w( src/core/lib/iomgr/endpoint_pair_posix.cc ) s.files += %w( src/core/lib/iomgr/endpoint_pair_uv.cc ) s.files += %w( src/core/lib/iomgr/endpoint_pair_windows.cc ) s.files += %w( src/core/lib/iomgr/error.cc ) + s.files += %w( src/core/lib/iomgr/error_cfstream.cc ) s.files += %w( src/core/lib/iomgr/ev_epoll1_linux.cc ) s.files += %w( src/core/lib/iomgr/ev_epollex_linux.cc ) s.files += %w( src/core/lib/iomgr/ev_poll_posix.cc ) @@ -521,6 +535,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/iomgr/iomgr_custom.cc ) s.files += %w( src/core/lib/iomgr/iomgr_internal.cc ) s.files += %w( src/core/lib/iomgr/iomgr_posix.cc ) + s.files += %w( src/core/lib/iomgr/iomgr_posix_cfstream.cc ) s.files += %w( src/core/lib/iomgr/iomgr_uv.cc ) s.files += %w( src/core/lib/iomgr/iomgr_windows.cc ) s.files += %w( src/core/lib/iomgr/is_epollexclusive_available.cc ) @@ -549,6 +564,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/iomgr/socket_utils_windows.cc ) s.files += %w( src/core/lib/iomgr/socket_windows.cc ) s.files += %w( src/core/lib/iomgr/tcp_client.cc ) + s.files += %w( src/core/lib/iomgr/tcp_client_cfstream.cc ) s.files += %w( src/core/lib/iomgr/tcp_client_custom.cc ) s.files += %w( src/core/lib/iomgr/tcp_client_posix.cc ) s.files += %w( src/core/lib/iomgr/tcp_client_windows.cc ) @@ -782,12 +798,15 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc ) + s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc ) + s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc ) + s.files += %w( src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc ) s.files += %w( src/core/ext/filters/census/grpc_context.cc ) diff --git a/grpc.gyp b/grpc.gyp index 40dc88d7474..eff5ab816b8 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -218,7 +218,6 @@ ], 'sources': [ 'src/core/lib/gpr/alloc.cc', - 'src/core/lib/gpr/arena.cc', 'src/core/lib/gpr/atm.cc', 'src/core/lib/gpr/cpu_iphone.cc', 'src/core/lib/gpr/cpu_linux.cc', @@ -251,7 +250,9 @@ 'src/core/lib/gpr/tmpfile_posix.cc', 'src/core/lib/gpr/tmpfile_windows.cc', 'src/core/lib/gpr/wrap_memcpy.cc', + 'src/core/lib/gprpp/arena.cc', 'src/core/lib/gprpp/fork.cc', + 'src/core/lib/gprpp/global_config_env.cc', 'src/core/lib/gprpp/thd_posix.cc', 'src/core/lib/gprpp/thd_windows.cc', 'src/core/lib/profiling/basic_timers.cc', @@ -292,12 +293,15 @@ 'src/core/lib/http/parser.cc', 'src/core/lib/iomgr/buffer_list.cc', 'src/core/lib/iomgr/call_combiner.cc', + 'src/core/lib/iomgr/cfstream_handle.cc', 'src/core/lib/iomgr/combiner.cc', 'src/core/lib/iomgr/endpoint.cc', + 'src/core/lib/iomgr/endpoint_cfstream.cc', 'src/core/lib/iomgr/endpoint_pair_posix.cc', 'src/core/lib/iomgr/endpoint_pair_uv.cc', 'src/core/lib/iomgr/endpoint_pair_windows.cc', 'src/core/lib/iomgr/error.cc', + 'src/core/lib/iomgr/error_cfstream.cc', 'src/core/lib/iomgr/ev_epoll1_linux.cc', 'src/core/lib/iomgr/ev_epollex_linux.cc', 'src/core/lib/iomgr/ev_poll_posix.cc', @@ -318,6 +322,7 @@ 'src/core/lib/iomgr/iomgr_custom.cc', 'src/core/lib/iomgr/iomgr_internal.cc', 'src/core/lib/iomgr/iomgr_posix.cc', + 'src/core/lib/iomgr/iomgr_posix_cfstream.cc', 'src/core/lib/iomgr/iomgr_uv.cc', 'src/core/lib/iomgr/iomgr_windows.cc', 'src/core/lib/iomgr/is_epollexclusive_available.cc', @@ -346,6 +351,7 @@ 'src/core/lib/iomgr/socket_utils_windows.cc', 'src/core/lib/iomgr/socket_windows.cc', 'src/core/lib/iomgr/tcp_client.cc', + 'src/core/lib/iomgr/tcp_client_cfstream.cc', 'src/core/lib/iomgr/tcp_client_custom.cc', 'src/core/lib/iomgr/tcp_client_posix.cc', 'src/core/lib/iomgr/tcp_client_windows.cc', @@ -579,12 +585,15 @@ 'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc', + 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc', + 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', + 'src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc', 'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', 'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', 'src/core/ext/filters/census/grpc_context.cc', @@ -660,12 +669,15 @@ 'src/core/lib/http/parser.cc', 'src/core/lib/iomgr/buffer_list.cc', 'src/core/lib/iomgr/call_combiner.cc', + 'src/core/lib/iomgr/cfstream_handle.cc', 'src/core/lib/iomgr/combiner.cc', 'src/core/lib/iomgr/endpoint.cc', + 'src/core/lib/iomgr/endpoint_cfstream.cc', 'src/core/lib/iomgr/endpoint_pair_posix.cc', 'src/core/lib/iomgr/endpoint_pair_uv.cc', 'src/core/lib/iomgr/endpoint_pair_windows.cc', 'src/core/lib/iomgr/error.cc', + 'src/core/lib/iomgr/error_cfstream.cc', 'src/core/lib/iomgr/ev_epoll1_linux.cc', 'src/core/lib/iomgr/ev_epollex_linux.cc', 'src/core/lib/iomgr/ev_poll_posix.cc', @@ -686,6 +698,7 @@ 'src/core/lib/iomgr/iomgr_custom.cc', 'src/core/lib/iomgr/iomgr_internal.cc', 'src/core/lib/iomgr/iomgr_posix.cc', + 'src/core/lib/iomgr/iomgr_posix_cfstream.cc', 'src/core/lib/iomgr/iomgr_uv.cc', 'src/core/lib/iomgr/iomgr_windows.cc', 'src/core/lib/iomgr/is_epollexclusive_available.cc', @@ -714,6 +727,7 @@ 'src/core/lib/iomgr/socket_utils_windows.cc', 'src/core/lib/iomgr/socket_windows.cc', 'src/core/lib/iomgr/tcp_client.cc', + 'src/core/lib/iomgr/tcp_client_cfstream.cc', 'src/core/lib/iomgr/tcp_client_custom.cc', 'src/core/lib/iomgr/tcp_client_posix.cc', 'src/core/lib/iomgr/tcp_client_windows.cc', @@ -905,12 +919,15 @@ 'src/core/lib/http/parser.cc', 'src/core/lib/iomgr/buffer_list.cc', 'src/core/lib/iomgr/call_combiner.cc', + 'src/core/lib/iomgr/cfstream_handle.cc', 'src/core/lib/iomgr/combiner.cc', 'src/core/lib/iomgr/endpoint.cc', + 'src/core/lib/iomgr/endpoint_cfstream.cc', 'src/core/lib/iomgr/endpoint_pair_posix.cc', 'src/core/lib/iomgr/endpoint_pair_uv.cc', 'src/core/lib/iomgr/endpoint_pair_windows.cc', 'src/core/lib/iomgr/error.cc', + 'src/core/lib/iomgr/error_cfstream.cc', 'src/core/lib/iomgr/ev_epoll1_linux.cc', 'src/core/lib/iomgr/ev_epollex_linux.cc', 'src/core/lib/iomgr/ev_poll_posix.cc', @@ -931,6 +948,7 @@ 'src/core/lib/iomgr/iomgr_custom.cc', 'src/core/lib/iomgr/iomgr_internal.cc', 'src/core/lib/iomgr/iomgr_posix.cc', + 'src/core/lib/iomgr/iomgr_posix_cfstream.cc', 'src/core/lib/iomgr/iomgr_uv.cc', 'src/core/lib/iomgr/iomgr_windows.cc', 'src/core/lib/iomgr/is_epollexclusive_available.cc', @@ -959,6 +977,7 @@ 'src/core/lib/iomgr/socket_utils_windows.cc', 'src/core/lib/iomgr/socket_windows.cc', 'src/core/lib/iomgr/tcp_client.cc', + 'src/core/lib/iomgr/tcp_client_cfstream.cc', 'src/core/lib/iomgr/tcp_client_custom.cc', 'src/core/lib/iomgr/tcp_client_posix.cc', 'src/core/lib/iomgr/tcp_client_windows.cc', @@ -1126,12 +1145,15 @@ 'src/core/lib/http/parser.cc', 'src/core/lib/iomgr/buffer_list.cc', 'src/core/lib/iomgr/call_combiner.cc', + 'src/core/lib/iomgr/cfstream_handle.cc', 'src/core/lib/iomgr/combiner.cc', 'src/core/lib/iomgr/endpoint.cc', + 'src/core/lib/iomgr/endpoint_cfstream.cc', 'src/core/lib/iomgr/endpoint_pair_posix.cc', 'src/core/lib/iomgr/endpoint_pair_uv.cc', 'src/core/lib/iomgr/endpoint_pair_windows.cc', 'src/core/lib/iomgr/error.cc', + 'src/core/lib/iomgr/error_cfstream.cc', 'src/core/lib/iomgr/ev_epoll1_linux.cc', 'src/core/lib/iomgr/ev_epollex_linux.cc', 'src/core/lib/iomgr/ev_poll_posix.cc', @@ -1152,6 +1174,7 @@ 'src/core/lib/iomgr/iomgr_custom.cc', 'src/core/lib/iomgr/iomgr_internal.cc', 'src/core/lib/iomgr/iomgr_posix.cc', + 'src/core/lib/iomgr/iomgr_posix_cfstream.cc', 'src/core/lib/iomgr/iomgr_uv.cc', 'src/core/lib/iomgr/iomgr_windows.cc', 'src/core/lib/iomgr/is_epollexclusive_available.cc', @@ -1180,6 +1203,7 @@ 'src/core/lib/iomgr/socket_utils_windows.cc', 'src/core/lib/iomgr/socket_windows.cc', 'src/core/lib/iomgr/tcp_client.cc', + 'src/core/lib/iomgr/tcp_client_cfstream.cc', 'src/core/lib/iomgr/tcp_client_custom.cc', 'src/core/lib/iomgr/tcp_client_posix.cc', 'src/core/lib/iomgr/tcp_client_windows.cc', @@ -1321,12 +1345,15 @@ 'src/core/ext/transport/inproc/inproc_transport.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc', + 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc', + 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', + 'src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc', 'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', 'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', @@ -1378,6 +1405,33 @@ 'test/core/util/test_tcp_server.cc', ], }, + { + 'target_name': 'bm_callback_test_service_impl', + 'type': 'static_library', + 'dependencies': [ + 'grpc_benchmark', + 'benchmark', + 'grpc++_test_util_unsecure', + 'grpc_test_util_unsecure', + 'grpc++_unsecure', + 'grpc_unsecure', + 'gpr', + 'grpc++_test_config', + ], + 'sources': [ + 'src/proto/grpc/testing/echo.proto', + 'test/cpp/microbenchmarks/callback_test_service.cc', + ], + }, + { + 'target_name': 'dns_test_util', + 'type': 'static_library', + 'dependencies': [ + ], + 'sources': [ + 'test/cpp/naming/dns_test_util.cc', + ], + }, { 'target_name': 'grpc++', 'type': 'static_library', @@ -1414,6 +1468,7 @@ 'src/cpp/server/channel_argument_option.cc', 'src/cpp/server/create_default_thread_pool.cc', 'src/cpp/server/dynamic_thread_pool.cc', + 'src/cpp/server/external_connection_acceptor_impl.cc', 'src/cpp/server/health/default_health_check_service.cc', 'src/cpp/server/health/health_check_service.cc', 'src/cpp/server/health/health_check_service_server_builder_option.cc', @@ -1569,6 +1624,7 @@ 'src/cpp/server/channel_argument_option.cc', 'src/cpp/server/create_default_thread_pool.cc', 'src/cpp/server/dynamic_thread_pool.cc', + 'src/cpp/server/external_connection_acceptor_impl.cc', 'src/cpp/server/health/default_health_check_service.cc', 'src/cpp/server/health/health_check_service.cc', 'src/cpp/server/health/health_check_service_server_builder_option.cc', diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index 53189097b9b..ebdf86b7d50 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -641,7 +641,7 @@ typedef struct grpc_tls_credentials_options grpc_tls_credentials_options; /** Create an empty TLS credentials options. It is used for * experimental purpose for now and subject to change. */ -GRPCAPI grpc_tls_credentials_options* grpc_tls_credentials_options_create(); +GRPCAPI grpc_tls_credentials_options* grpc_tls_credentials_options_create(void); /** Set grpc_ssl_client_certificate_request_type field in credentials options with the provided type. options should not be NULL. @@ -683,7 +683,8 @@ GRPCAPI int grpc_tls_credentials_options_set_server_authorization_check_config( /** Create an empty grpc_tls_key_materials_config instance. * It is used for experimental purpose for now and subject to change. */ -GRPCAPI grpc_tls_key_materials_config* grpc_tls_key_materials_config_create(); +GRPCAPI grpc_tls_key_materials_config* grpc_tls_key_materials_config_create( + void); /** Set grpc_tls_key_materials_config instance with provided a TLS certificate. config will take the ownership of pem_root_certs and pem_key_cert_pairs. diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h index 078db2b90a8..65582e6e85d 100644 --- a/include/grpc/impl/codegen/grpc_types.h +++ b/include/grpc/impl/codegen/grpc_types.h @@ -315,11 +315,11 @@ typedef struct { #define GRPC_ARG_GRPCLB_CALL_TIMEOUT_MS "grpc.grpclb_call_timeout_ms" /* Timeout in milliseconds to wait for the serverlist from the grpclb load balancer before using fallback backend addresses from the resolver. - If 0, fallback will never be used. Default value is 10000. */ + If 0, enter fallback mode immediately. Default value is 10000. */ #define GRPC_ARG_GRPCLB_FALLBACK_TIMEOUT_MS "grpc.grpclb_fallback_timeout_ms" /* Timeout in milliseconds to wait for the serverlist from the xDS load balancer before using fallback backend addresses from the resolver. - If 0, fallback will never be used. Default value is 10000. */ + If 0, enter fallback mode immediately. Default value is 10000. */ #define GRPC_ARG_XDS_FALLBACK_TIMEOUT_MS "grpc.xds_fallback_timeout_ms" /** If non-zero, grpc server's cronet compression workaround will be enabled */ #define GRPC_ARG_WORKAROUND_CRONET_COMPRESSION \ @@ -359,10 +359,12 @@ typedef struct { * load balancing policy. Note that this only works with the "ares" * DNS resolver, and isn't supported by the "native" DNS resolver. */ #define GRPC_ARG_DNS_ENABLE_SRV_QUERIES "grpc.dns_enable_srv_queries" -/** If set, determines the number of milliseconds that the c-ares based - * DNS resolver will wait on queries before cancelling them. The default value - * is 10000. Setting this to "0" will disable c-ares query timeouts - * entirely. */ +/** If set, determines an upper bound on the number of milliseconds that the + * c-ares based DNS resolver will wait on queries before cancelling them. + * The default value is 120,000. Setting this to "0" will disable the + * overall timeout entirely. Note that this doesn't include internal c-ares + * timeouts/backoff/retry logic, and so the actual DNS resolution may time out + * sooner than the value specified here. */ #define GRPC_ARG_DNS_ARES_QUERY_TIMEOUT_MS "grpc.dns_ares_query_timeout" /** If set, uses a local subchannel pool within the channel. Otherwise, uses the * global subchannel pool. */ @@ -494,7 +496,8 @@ typedef struct grpc_event { field is guaranteed to be 0 */ int success; /** The tag passed to grpc_call_start_batch etc to start this operation. - Only GRPC_OP_COMPLETE has a tag. */ + *Only* GRPC_OP_COMPLETE has a tag. For all other grpc_completion_type + values, tag is uninitialized. */ void* tag; } grpc_event; diff --git a/include/grpc/impl/codegen/status.h b/include/grpc/impl/codegen/status.h index 9bc3dc95609..dec3b8f340e 100644 --- a/include/grpc/impl/codegen/status.h +++ b/include/grpc/impl/codegen/status.h @@ -128,7 +128,8 @@ typedef enum { /** The service is currently unavailable. This is a most likely a transient condition and may be corrected by retrying with - a backoff. + a backoff. Note that it is not always safe to retry non-idempotent + operations. WARNING: Although data MIGHT not have been transmitted when this status occurs, there is NOT A GUARANTEE that the server has not seen diff --git a/include/grpcpp/channel.h b/include/grpcpp/channel.h index c4d5ab1177b..163c804ffbe 100644 --- a/include/grpcpp/channel.h +++ b/include/grpcpp/channel.h @@ -19,21 +19,12 @@ #ifndef GRPCPP_CHANNEL_H #define GRPCPP_CHANNEL_H -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -struct grpc_channel; +#include namespace grpc { +typedef ::grpc_impl::Channel Channel; + namespace experimental { /// Resets the channel's connection backoff. /// TODO(roth): Once we see whether this proves useful, either create a gRFC @@ -41,75 +32,6 @@ namespace experimental { void ChannelResetConnectionBackoff(Channel* channel); } // namespace experimental -/// Channels represent a connection to an endpoint. Created by \a CreateChannel. -class Channel final : public ChannelInterface, - public internal::CallHook, - public std::enable_shared_from_this, - private GrpcLibraryCodegen { - public: - ~Channel(); - - /// Get the current channel state. If the channel is in IDLE and - /// \a try_to_connect is set to true, try to connect. - grpc_connectivity_state GetState(bool try_to_connect) override; - - /// Returns the LB policy name, or the empty string if not yet available. - grpc::string GetLoadBalancingPolicyName() const; - - /// Returns the service config in JSON form, or the empty string if - /// not available. - grpc::string GetServiceConfigJSON() const; - - private: - template - friend class internal::BlockingUnaryCallImpl; - friend void experimental::ChannelResetConnectionBackoff(Channel* channel); - friend std::shared_ptr CreateChannelInternal( - const grpc::string& host, grpc_channel* c_channel, - std::vector< - std::unique_ptr> - interceptor_creators); - friend class internal::InterceptedChannel; - Channel(const grpc::string& host, grpc_channel* c_channel, - std::vector< - std::unique_ptr> - interceptor_creators); - - internal::Call CreateCall(const internal::RpcMethod& method, - ClientContext* context, - CompletionQueue* cq) override; - void PerformOpsOnCall(internal::CallOpSetInterface* ops, - internal::Call* call) override; - void* RegisterMethod(const char* method) override; - - void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed, - gpr_timespec deadline, CompletionQueue* cq, - void* tag) override; - bool WaitForStateChangeImpl(grpc_connectivity_state last_observed, - gpr_timespec deadline) override; - - CompletionQueue* CallbackCQ() override; - - internal::Call CreateCallInternal(const internal::RpcMethod& method, - ClientContext* context, CompletionQueue* cq, - size_t interceptor_pos) override; - - const grpc::string host_; - grpc_channel* const c_channel_; // owned - - // mu_ protects callback_cq_ (the per-channel callbackable completion queue) - grpc::internal::Mutex mu_; - - // callback_cq_ references the callbackable completion queue associated - // with this channel (if any). It is set on the first call to CallbackCQ(). - // It is _not owned_ by the channel; ownership belongs with its internal - // shutdown callback tag (invoked when the CQ is fully shutdown). - CompletionQueue* callback_cq_ = nullptr; - - std::vector> - interceptor_creators_; -}; - } // namespace grpc #endif // GRPCPP_CHANNEL_H diff --git a/include/grpcpp/channel_impl.h b/include/grpcpp/channel_impl.h new file mode 100644 index 00000000000..39917d2eb74 --- /dev/null +++ b/include/grpcpp/channel_impl.h @@ -0,0 +1,125 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * 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 GRPCPP_CHANNEL_IMPL_H +#define GRPCPP_CHANNEL_IMPL_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +struct grpc_channel; + +namespace grpc { + +std::shared_ptr<::grpc_impl::Channel> CreateChannelInternal( + const grpc::string& host, grpc_channel* c_channel, + std::vector< + std::unique_ptr> + interceptor_creators); +} // namespace grpc +namespace grpc_impl { + +namespace experimental { +/// Resets the channel's connection backoff. +/// TODO(roth): Once we see whether this proves useful, either create a gRFC +/// and change this to be a method of the Channel class, or remove it. +void ChannelResetConnectionBackoff(Channel* channel); +} // namespace experimental + +/// Channels represent a connection to an endpoint. Created by \a CreateChannel. +class Channel final : public ::grpc::ChannelInterface, + public ::grpc::internal::CallHook, + public std::enable_shared_from_this, + private ::grpc::GrpcLibraryCodegen { + public: + ~Channel(); + + /// Get the current channel state. If the channel is in IDLE and + /// \a try_to_connect is set to true, try to connect. + grpc_connectivity_state GetState(bool try_to_connect) override; + + /// Returns the LB policy name, or the empty string if not yet available. + grpc::string GetLoadBalancingPolicyName() const; + + /// Returns the service config in JSON form, or the empty string if + /// not available. + grpc::string GetServiceConfigJSON() const; + + private: + template + friend class ::grpc::internal::BlockingUnaryCallImpl; + friend void experimental::ChannelResetConnectionBackoff(Channel* channel); + friend std::shared_ptr grpc::CreateChannelInternal( + const grpc::string& host, grpc_channel* c_channel, + std::vector> + interceptor_creators); + friend class ::grpc::internal::InterceptedChannel; + Channel(const grpc::string& host, grpc_channel* c_channel, + std::vector> + interceptor_creators); + + ::grpc::internal::Call CreateCall(const ::grpc::internal::RpcMethod& method, + ::grpc::ClientContext* context, + ::grpc::CompletionQueue* cq) override; + void PerformOpsOnCall(::grpc::internal::CallOpSetInterface* ops, + ::grpc::internal::Call* call) override; + void* RegisterMethod(const char* method) override; + + void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed, + gpr_timespec deadline, + ::grpc::CompletionQueue* cq, void* tag) override; + bool WaitForStateChangeImpl(grpc_connectivity_state last_observed, + gpr_timespec deadline) override; + + ::grpc::CompletionQueue* CallbackCQ() override; + + ::grpc::internal::Call CreateCallInternal( + const ::grpc::internal::RpcMethod& method, ::grpc::ClientContext* context, + ::grpc::CompletionQueue* cq, size_t interceptor_pos) override; + + const grpc::string host_; + grpc_channel* const c_channel_; // owned + + // mu_ protects callback_cq_ (the per-channel callbackable completion queue) + grpc::internal::Mutex mu_; + + // callback_cq_ references the callbackable completion queue associated + // with this channel (if any). It is set on the first call to CallbackCQ(). + // It is _not owned_ by the channel; ownership belongs with its internal + // shutdown callback tag (invoked when the CQ is fully shutdown). + ::grpc::CompletionQueue* callback_cq_ = nullptr; + + std::vector< + std::unique_ptr<::grpc::experimental::ClientInterceptorFactoryInterface>> + interceptor_creators_; +}; + +} // namespace grpc_impl + +#endif // GRPCPP_CHANNEL_IMPL_H diff --git a/include/grpcpp/create_channel.h b/include/grpcpp/create_channel.h index 6d444be9803..9b257ace945 100644 --- a/include/grpcpp/create_channel.h +++ b/include/grpcpp/create_channel.h @@ -20,25 +20,27 @@ #define GRPCPP_CREATE_CHANNEL_H #include +#include namespace grpc { -static inline std::shared_ptr CreateChannel( +static inline std::shared_ptr<::grpc::Channel> CreateChannel( const grpc::string& target, const std::shared_ptr& creds) { - return ::grpc_impl::CreateChannel(target, creds); + return ::grpc_impl::CreateChannelImpl(target, creds); } -static inline std::shared_ptr CreateCustomChannel( +static inline std::shared_ptr<::grpc::Channel> CreateCustomChannel( const grpc::string& target, const std::shared_ptr& creds, const ChannelArguments& args) { - return ::grpc_impl::CreateCustomChannel(target, creds, args); + return ::grpc_impl::CreateCustomChannelImpl(target, creds, args); } namespace experimental { -static inline std::shared_ptr CreateCustomChannelWithInterceptors( +static inline std::shared_ptr<::grpc::Channel> +CreateCustomChannelWithInterceptors( const grpc::string& target, const std::shared_ptr& creds, const ChannelArguments& args, diff --git a/include/grpcpp/create_channel_impl.h b/include/grpcpp/create_channel_impl.h index 214a537a3cb..02896e66444 100644 --- a/include/grpcpp/create_channel_impl.h +++ b/include/grpcpp/create_channel_impl.h @@ -28,16 +28,15 @@ #include namespace grpc_impl { - /// Create a new \a Channel pointing to \a target. /// /// \param target The URI of the endpoint to connect to. /// \param creds Credentials to use for the created channel. If it does not /// hold an object or is invalid, a lame channel (one on which all operations /// fail) is returned. -std::shared_ptr CreateChannel( +std::shared_ptr<::grpc::Channel> CreateChannelImpl( const grpc::string& target, - const std::shared_ptr& creds); + const std::shared_ptr<::grpc::ChannelCredentials>& creds); /// Create a new \em custom \a Channel pointing to \a target. /// @@ -49,10 +48,10 @@ std::shared_ptr CreateChannel( /// hold an object or is invalid, a lame channel (one on which all operations /// fail) is returned. /// \param args Options for channel creation. -std::shared_ptr CreateCustomChannel( +std::shared_ptr<::grpc::Channel> CreateCustomChannelImpl( const grpc::string& target, - const std::shared_ptr& creds, - const grpc::ChannelArguments& args); + const std::shared_ptr<::grpc::ChannelCredentials>& creds, + const ::grpc::ChannelArguments& args); namespace experimental { /// Create a new \em custom \a Channel pointing to \a target with \a @@ -66,10 +65,10 @@ namespace experimental { /// hold an object or is invalid, a lame channel (one on which all operations /// fail) is returned. /// \param args Options for channel creation. -std::shared_ptr CreateCustomChannelWithInterceptors( +std::shared_ptr<::grpc::Channel> CreateCustomChannelWithInterceptors( const grpc::string& target, const std::shared_ptr& creds, - const grpc::ChannelArguments& args, + const ::grpc::ChannelArguments& args, std::vector< std::unique_ptr> interceptor_creators); diff --git a/include/grpcpp/generic/generic_stub_impl.h b/include/grpcpp/generic/generic_stub_impl.h index 0a7338228c1..90414611cbd 100644 --- a/include/grpcpp/generic/generic_stub_impl.h +++ b/include/grpcpp/generic/generic_stub_impl.h @@ -29,12 +29,12 @@ namespace grpc { -class CompletionQueue; typedef ClientAsyncReaderWriter GenericClientAsyncReaderWriter; typedef ClientAsyncResponseReader GenericClientAsyncResponseReader; } // namespace grpc namespace grpc_impl { +class CompletionQueue; /// Generic stubs provide a type-unsafe interface to call gRPC methods /// by name. diff --git a/include/grpcpp/impl/codegen/async_generic_service.h b/include/grpcpp/impl/codegen/async_generic_service.h index 759f6683bf4..46d09121a7b 100644 --- a/include/grpcpp/impl/codegen/async_generic_service.h +++ b/include/grpcpp/impl/codegen/async_generic_service.h @@ -39,7 +39,7 @@ class GenericServerContext final : public ServerContext { const grpc::string& host() const { return host_; } private: - friend class Server; + friend class grpc_impl::Server; friend class ServerInterface; void Clear() { @@ -79,8 +79,8 @@ class AsyncGenericService final { ServerCompletionQueue* notification_cq, void* tag); private: - friend class Server; - Server* server_; + friend class grpc_impl::Server; + grpc_impl::Server* server_; }; namespace experimental { @@ -135,14 +135,14 @@ class CallbackGenericService { } private: - friend class ::grpc::Server; + friend class ::grpc_impl::Server; internal::CallbackBidiHandler* Handler() { return new internal::CallbackBidiHandler( [this] { return CreateReactor(); }); } - Server* server_{nullptr}; + grpc_impl::Server* server_{nullptr}; }; } // namespace experimental } // namespace grpc diff --git a/include/grpcpp/impl/codegen/async_stream.h b/include/grpcpp/impl/codegen/async_stream.h index e7b361caa6b..f95772650a2 100644 --- a/include/grpcpp/impl/codegen/async_stream.h +++ b/include/grpcpp/impl/codegen/async_stream.h @@ -28,8 +28,6 @@ namespace grpc { -class CompletionQueue; - namespace internal { /// Common interface for all client side asynchronous streaming. class ClientAsyncStreamingInterface { @@ -1099,7 +1097,7 @@ class ServerAsyncReaderWriter final } private: - friend class ::grpc::Server; + friend class ::grpc_impl::Server; void BindCall(::grpc::internal::Call* call) override { call_ = *call; } diff --git a/include/grpcpp/impl/codegen/async_unary_call.h b/include/grpcpp/impl/codegen/async_unary_call.h index 89dcb124189..4b97cf29018 100644 --- a/include/grpcpp/impl/codegen/async_unary_call.h +++ b/include/grpcpp/impl/codegen/async_unary_call.h @@ -29,7 +29,6 @@ namespace grpc { -class CompletionQueue; extern CoreCodegenInterface* g_core_codegen_interface; /// An interface relevant for async client side unary RPCs (which send diff --git a/include/grpcpp/impl/codegen/byte_buffer.h b/include/grpcpp/impl/codegen/byte_buffer.h index 7b82f49a84e..e2ba9344bcb 100644 --- a/include/grpcpp/impl/codegen/byte_buffer.h +++ b/include/grpcpp/impl/codegen/byte_buffer.h @@ -51,6 +51,7 @@ template class CallbackServerStreamingHandler; template class ErrorMethodHandler; +class ExternalConnectionAcceptorImpl; template class DeserializeFuncType; class GrpcByteBufferPeer; @@ -185,6 +186,7 @@ class ByteBuffer final { friend class ProtoBufferReader; friend class ProtoBufferWriter; friend class internal::GrpcByteBufferPeer; + friend class internal::ExternalConnectionAcceptorImpl; grpc_byte_buffer* buffer_; diff --git a/include/grpcpp/impl/codegen/call.h b/include/grpcpp/impl/codegen/call.h index c040c30dd9d..eefa4a7f9cd 100644 --- a/include/grpcpp/impl/codegen/call.h +++ b/include/grpcpp/impl/codegen/call.h @@ -21,9 +21,11 @@ #include #include -namespace grpc { +namespace grpc_impl { class CompletionQueue; +} +namespace grpc { namespace experimental { class ClientRpcInfo; class ServerRpcInfo; @@ -41,13 +43,13 @@ class Call final { call_(nullptr), max_receive_message_size_(-1) {} /** call is owned by the caller */ - Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq) + Call(grpc_call* call, CallHook* call_hook, ::grpc_impl::CompletionQueue* cq) : call_hook_(call_hook), cq_(cq), call_(call), max_receive_message_size_(-1) {} - Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq, + Call(grpc_call* call, CallHook* call_hook, ::grpc_impl::CompletionQueue* cq, experimental::ClientRpcInfo* rpc_info) : call_hook_(call_hook), cq_(cq), @@ -55,7 +57,7 @@ class Call final { max_receive_message_size_(-1), client_rpc_info_(rpc_info) {} - Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq, + Call(grpc_call* call, CallHook* call_hook, ::grpc_impl::CompletionQueue* cq, int max_receive_message_size, experimental::ServerRpcInfo* rpc_info) : call_hook_(call_hook), cq_(cq), @@ -68,7 +70,7 @@ class Call final { } grpc_call* call() const { return call_; } - CompletionQueue* cq() const { return cq_; } + ::grpc_impl::CompletionQueue* cq() const { return cq_; } int max_receive_message_size() const { return max_receive_message_size_; } @@ -82,7 +84,7 @@ class Call final { private: CallHook* call_hook_; - CompletionQueue* cq_; + ::grpc_impl::CompletionQueue* cq_; grpc_call* call_; int max_receive_message_size_; experimental::ClientRpcInfo* client_rpc_info_ = nullptr; diff --git a/include/grpcpp/impl/codegen/call_op_set.h b/include/grpcpp/impl/codegen/call_op_set.h index 4ca87a99fca..d810625b3e4 100644 --- a/include/grpcpp/impl/codegen/call_op_set.h +++ b/include/grpcpp/impl/codegen/call_op_set.h @@ -48,7 +48,6 @@ namespace grpc { -class CompletionQueue; extern CoreCodegenInterface* g_core_codegen_interface; namespace internal { diff --git a/include/grpcpp/impl/codegen/channel_interface.h b/include/grpcpp/impl/codegen/channel_interface.h index 57555285e18..9df233b5500 100644 --- a/include/grpcpp/impl/codegen/channel_interface.h +++ b/include/grpcpp/impl/codegen/channel_interface.h @@ -24,10 +24,13 @@ #include #include +namespace grpc_impl { +class CompletionQueue; +} + namespace grpc { class ChannelInterface; class ClientContext; -class CompletionQueue; template class ClientReader; @@ -74,7 +77,7 @@ class ChannelInterface { /// deadline expires. \a GetState needs to called to get the current state. template void NotifyOnStateChange(grpc_connectivity_state last_observed, T deadline, - CompletionQueue* cq, void* tag) { + ::grpc_impl::CompletionQueue* cq, void* tag) { TimePoint deadline_tp(deadline); NotifyOnStateChangeImpl(last_observed, deadline_tp.raw_time(), cq, tag); } @@ -127,13 +130,14 @@ class ChannelInterface { friend class ::grpc::internal::InterceptedChannel; virtual internal::Call CreateCall(const internal::RpcMethod& method, ClientContext* context, - CompletionQueue* cq) = 0; + ::grpc_impl::CompletionQueue* cq) = 0; virtual void PerformOpsOnCall(internal::CallOpSetInterface* ops, internal::Call* call) = 0; virtual void* RegisterMethod(const char* method) = 0; virtual void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed, gpr_timespec deadline, - CompletionQueue* cq, void* tag) = 0; + ::grpc_impl::CompletionQueue* cq, + void* tag) = 0; virtual bool WaitForStateChangeImpl(grpc_connectivity_state last_observed, gpr_timespec deadline) = 0; @@ -146,7 +150,7 @@ class ChannelInterface { // change (even though this is private and non-API) virtual internal::Call CreateCallInternal(const internal::RpcMethod& method, ClientContext* context, - CompletionQueue* cq, + ::grpc_impl::CompletionQueue* cq, size_t interceptor_pos) { return internal::Call(); } @@ -159,7 +163,7 @@ class ChannelInterface { // Returns nullptr (rather than being pure) since this is a post-1.0 method // and adding a new pure method to an interface would be a breaking change // (even though this is private and non-API) - virtual CompletionQueue* CallbackCQ() { return nullptr; } + virtual ::grpc_impl::CompletionQueue* CallbackCQ() { return nullptr; } }; } // namespace grpc diff --git a/include/grpcpp/impl/codegen/client_callback.h b/include/grpcpp/impl/codegen/client_callback.h index e973e23f891..dda9aec29f3 100644 --- a/include/grpcpp/impl/codegen/client_callback.h +++ b/include/grpcpp/impl/codegen/client_callback.h @@ -29,11 +29,13 @@ #include #include +namespace grpc_impl { +class Channel; +} + namespace grpc { -class Channel; class ClientContext; -class CompletionQueue; namespace internal { class RpcMethod; @@ -174,6 +176,8 @@ class ClientCallbackUnary { // StartWrite, or AddHold operations on the streaming object. Note that none of // the classes are pure; all reactions have a default empty reaction so that the // user class only needs to override those classes that it cares about. +// The reactor must be passed to the stub invocation before any of the below +// operations can be called. /// \a ClientBidiReactor is the interface for a bidirectional streaming RPC. template diff --git a/include/grpcpp/impl/codegen/client_context.h b/include/grpcpp/impl/codegen/client_context.h index 7f6956a0da4..999d8fcbfe7 100644 --- a/include/grpcpp/impl/codegen/client_context.h +++ b/include/grpcpp/impl/codegen/client_context.h @@ -57,12 +57,15 @@ struct census_context; struct grpc_call; -namespace grpc { +namespace grpc_impl { +class CallCredentials; class Channel; -class ChannelInterface; class CompletionQueue; -class CallCredentials; +} // namespace grpc_impl +namespace grpc { + +class ChannelInterface; class ClientContext; namespace internal { @@ -306,7 +309,8 @@ class ClientContext { /// call. /// /// \see https://grpc.io/docs/guides/auth.html - void set_credentials(const std::shared_ptr& creds) { + void set_credentials( + const std::shared_ptr& creds) { creds_ = creds; } @@ -393,7 +397,7 @@ class ClientContext { friend class ::grpc::testing::InteropClientContextInspector; friend class ::grpc::internal::CallOpClientRecvStatus; friend class ::grpc::internal::CallOpRecvInitialMetadata; - friend class Channel; + friend class ::grpc_impl::Channel; template friend class ::grpc::ClientReader; template @@ -426,7 +430,8 @@ class ClientContext { } grpc_call* call() const { return call_; } - void set_call(grpc_call* call, const std::shared_ptr& channel); + void set_call(grpc_call* call, + const std::shared_ptr<::grpc_impl::Channel>& channel); experimental::ClientRpcInfo* set_client_rpc_info( const char* method, internal::RpcMethod::RpcType type, @@ -459,13 +464,13 @@ class ClientContext { bool wait_for_ready_explicitly_set_; bool idempotent_; bool cacheable_; - std::shared_ptr channel_; + std::shared_ptr<::grpc_impl::Channel> channel_; grpc::internal::Mutex mu_; grpc_call* call_; bool call_canceled_; gpr_timespec deadline_; grpc::string authority_; - std::shared_ptr creds_; + std::shared_ptr creds_; mutable std::shared_ptr auth_context_; struct census_context* census_context_; std::multimap send_initial_metadata_; diff --git a/include/grpcpp/impl/codegen/client_interceptor.h b/include/grpcpp/impl/codegen/client_interceptor.h index 19106545089..a4c85a76da5 100644 --- a/include/grpcpp/impl/codegen/client_interceptor.h +++ b/include/grpcpp/impl/codegen/client_interceptor.h @@ -26,10 +26,14 @@ #include #include +namespace grpc_impl { + +class Channel; +} + namespace grpc { class ClientContext; -class Channel; namespace internal { class InterceptorBatchMethodsImpl; diff --git a/include/grpcpp/impl/codegen/client_unary_call.h b/include/grpcpp/impl/codegen/client_unary_call.h index b9f8e1663f1..e0f692b1783 100644 --- a/include/grpcpp/impl/codegen/client_unary_call.h +++ b/include/grpcpp/impl/codegen/client_unary_call.h @@ -27,9 +27,7 @@ namespace grpc { -class Channel; class ClientContext; -class CompletionQueue; namespace internal { class RpcMethod; diff --git a/include/grpcpp/impl/codegen/completion_queue.h b/include/grpcpp/impl/codegen/completion_queue.h index 49c281b807d..f67a3780979 100644 --- a/include/grpcpp/impl/codegen/completion_queue.h +++ b/include/grpcpp/impl/codegen/completion_queue.h @@ -16,401 +16,15 @@ * */ -/// A completion queue implements a concurrent producer-consumer queue, with -/// two main API-exposed methods: \a Next and \a AsyncNext. These -/// methods are the essential component of the gRPC C++ asynchronous API. -/// There is also a \a Shutdown method to indicate that a given completion queue -/// will no longer have regular events. This must be called before the -/// completion queue is destroyed. -/// All completion queue APIs are thread-safe and may be used concurrently with -/// any other completion queue API invocation; it is acceptable to have -/// multiple threads calling \a Next or \a AsyncNext on the same or different -/// completion queues, or to call these methods concurrently with a \a Shutdown -/// elsewhere. -/// \remark{All other API calls on completion queue should be completed before -/// a completion queue destructor is called.} #ifndef GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_H #define GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_H -#include -#include -#include -#include -#include -#include +#include -struct grpc_completion_queue; - -namespace grpc_impl { - -class ServerBuilder; -} namespace grpc { -template -class ClientReader; -template -class ClientWriter; -template -class ClientReaderWriter; -template -class ServerReader; -template -class ServerWriter; -namespace internal { -template -class ServerReaderWriterBody; -} // namespace internal - -class Channel; -class ChannelInterface; -class ClientContext; -class CompletionQueue; -class Server; -class ServerContext; -class ServerInterface; - -namespace internal { -class CompletionQueueTag; -class RpcMethod; -template -class RpcMethodHandler; -template -class ClientStreamingHandler; -template -class ServerStreamingHandler; -template -class BidiStreamingHandler; -template -class TemplatedBidiStreamingHandler; -template -class ErrorMethodHandler; -template -class BlockingUnaryCallImpl; -template -class CallOpSet; -} // namespace internal - -extern CoreCodegenInterface* g_core_codegen_interface; - -/// A thin wrapper around \ref grpc_completion_queue (see \ref -/// src/core/lib/surface/completion_queue.h). -/// See \ref doc/cpp/perf_notes.md for notes on best practices for high -/// performance servers. -class CompletionQueue : private GrpcLibraryCodegen { - public: - /// Default constructor. Implicitly creates a \a grpc_completion_queue - /// instance. - CompletionQueue() - : CompletionQueue(grpc_completion_queue_attributes{ - GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, GRPC_CQ_DEFAULT_POLLING, - nullptr}) {} - - /// Wrap \a take, taking ownership of the instance. - /// - /// \param take The completion queue instance to wrap. Ownership is taken. - explicit CompletionQueue(grpc_completion_queue* take); - - /// Destructor. Destroys the owned wrapped completion queue / instance. - ~CompletionQueue() { - g_core_codegen_interface->grpc_completion_queue_destroy(cq_); - } - - /// Tri-state return for AsyncNext: SHUTDOWN, GOT_EVENT, TIMEOUT. - enum NextStatus { - SHUTDOWN, ///< The completion queue has been shutdown and fully-drained - GOT_EVENT, ///< Got a new event; \a tag will be filled in with its - ///< associated value; \a ok indicating its success. - TIMEOUT ///< deadline was reached. - }; - - /// Read from the queue, blocking until an event is available or the queue is - /// shutting down. - /// - /// \param tag [out] Updated to point to the read event's tag. - /// \param ok [out] true if read a successful event, false otherwise. - /// - /// Note that each tag sent to the completion queue (through RPC operations - /// or alarms) will be delivered out of the completion queue by a call to - /// Next (or a related method), regardless of whether the operation succeeded - /// or not. Success here means that this operation completed in the normal - /// valid manner. - /// - /// Server-side RPC request: \a ok indicates that the RPC has indeed - /// been started. If it is false, the server has been Shutdown - /// before this particular call got matched to an incoming RPC. - /// - /// Client-side StartCall/RPC invocation: \a ok indicates that the RPC is - /// going to go to the wire. If it is false, it not going to the wire. This - /// would happen if the channel is either permanently broken or - /// transiently broken but with the fail-fast option. (Note that async unary - /// RPCs don't post a CQ tag at this point, nor do client-streaming - /// or bidi-streaming RPCs that have the initial metadata corked option set.) - /// - /// Client-side Write, Client-side WritesDone, Server-side Write, - /// Server-side Finish, Server-side SendInitialMetadata (which is - /// typically included in Write or Finish when not done explicitly): - /// \a ok means that the data/metadata/status/etc is going to go to the - /// wire. If it is false, it not going to the wire because the call - /// is already dead (i.e., canceled, deadline expired, other side - /// dropped the channel, etc). - /// - /// Client-side Read, Server-side Read, Client-side - /// RecvInitialMetadata (which is typically included in Read if not - /// done explicitly): \a ok indicates whether there is a valid message - /// that got read. If not, you know that there are certainly no more - /// messages that can ever be read from this stream. For the client-side - /// operations, this only happens because the call is dead. For the - /// server-sider operation, though, this could happen because the client - /// has done a WritesDone already. - /// - /// Client-side Finish: \a ok should always be true - /// - /// Server-side AsyncNotifyWhenDone: \a ok should always be true - /// - /// Alarm: \a ok is true if it expired, false if it was canceled - /// - /// \return true if got an event, false if the queue is fully drained and - /// shut down. - bool Next(void** tag, bool* ok) { - return (AsyncNextInternal(tag, ok, - g_core_codegen_interface->gpr_inf_future( - GPR_CLOCK_REALTIME)) != SHUTDOWN); - } - - /// Read from the queue, blocking up to \a deadline (or the queue's shutdown). - /// Both \a tag and \a ok are updated upon success (if an event is available - /// within the \a deadline). A \a tag points to an arbitrary location usually - /// employed to uniquely identify an event. - /// - /// \param tag [out] Upon success, updated to point to the event's tag. - /// \param ok [out] Upon success, true if a successful event, false otherwise - /// See documentation for CompletionQueue::Next for explanation of ok - /// \param deadline [in] How long to block in wait for an event. - /// - /// \return The type of event read. - template - NextStatus AsyncNext(void** tag, bool* ok, const T& deadline) { - TimePoint deadline_tp(deadline); - return AsyncNextInternal(tag, ok, deadline_tp.raw_time()); - } - - /// EXPERIMENTAL - /// First executes \a F, then reads from the queue, blocking up to - /// \a deadline (or the queue's shutdown). - /// Both \a tag and \a ok are updated upon success (if an event is available - /// within the \a deadline). A \a tag points to an arbitrary location usually - /// employed to uniquely identify an event. - /// - /// \param f [in] Function to execute before calling AsyncNext on this queue. - /// \param tag [out] Upon success, updated to point to the event's tag. - /// \param ok [out] Upon success, true if read a regular event, false - /// otherwise. - /// \param deadline [in] How long to block in wait for an event. - /// - /// \return The type of event read. - template - NextStatus DoThenAsyncNext(F&& f, void** tag, bool* ok, const T& deadline) { - CompletionQueueTLSCache cache = CompletionQueueTLSCache(this); - f(); - if (cache.Flush(tag, ok)) { - return GOT_EVENT; - } else { - return AsyncNext(tag, ok, deadline); - } - } - - /// Request the shutdown of the queue. - /// - /// \warning This method must be called at some point if this completion queue - /// is accessed with Next or AsyncNext. \a Next will not return false - /// until this method has been called and all pending tags have been drained. - /// (Likewise for \a AsyncNext returning \a NextStatus::SHUTDOWN .) - /// Only once either one of these methods does that (that is, once the queue - /// has been \em drained) can an instance of this class be destroyed. - /// Also note that applications must ensure that no work is enqueued on this - /// completion queue after this method is called. - void Shutdown(); - - /// Returns a \em raw pointer to the underlying \a grpc_completion_queue - /// instance. - /// - /// \warning Remember that the returned instance is owned. No transfer of - /// owership is performed. - grpc_completion_queue* cq() { return cq_; } - - protected: - /// Private constructor of CompletionQueue only visible to friend classes - CompletionQueue(const grpc_completion_queue_attributes& attributes) { - cq_ = g_core_codegen_interface->grpc_completion_queue_create( - g_core_codegen_interface->grpc_completion_queue_factory_lookup( - &attributes), - &attributes, NULL); - InitialAvalanching(); // reserve this for the future shutdown - } - - private: - // Friend synchronous wrappers so that they can access Pluck(), which is - // a semi-private API geared towards the synchronous implementation. - template - friend class ::grpc::ClientReader; - template - friend class ::grpc::ClientWriter; - template - friend class ::grpc::ClientReaderWriter; - template - friend class ::grpc::ServerReader; - template - friend class ::grpc::ServerWriter; - template - friend class ::grpc::internal::ServerReaderWriterBody; - template - friend class ::grpc::internal::RpcMethodHandler; - template - friend class ::grpc::internal::ClientStreamingHandler; - template - friend class ::grpc::internal::ServerStreamingHandler; - template - friend class ::grpc::internal::TemplatedBidiStreamingHandler; - template - friend class ::grpc::internal::ErrorMethodHandler; - friend class ::grpc::Server; - friend class ::grpc::ServerContext; - friend class ::grpc::ServerInterface; - template - friend class ::grpc::internal::BlockingUnaryCallImpl; - - // Friends that need access to constructor for callback CQ - friend class ::grpc::Channel; - - // For access to Register/CompleteAvalanching - template - friend class ::grpc::internal::CallOpSet; - - /// EXPERIMENTAL - /// Creates a Thread Local cache to store the first event - /// On this completion queue queued from this thread. Once - /// initialized, it must be flushed on the same thread. - class CompletionQueueTLSCache { - public: - CompletionQueueTLSCache(CompletionQueue* cq); - ~CompletionQueueTLSCache(); - bool Flush(void** tag, bool* ok); - - private: - CompletionQueue* cq_; - bool flushed_; - }; - - NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline); - - /// Wraps \a grpc_completion_queue_pluck. - /// \warning Must not be mixed with calls to \a Next. - bool Pluck(internal::CompletionQueueTag* tag) { - auto deadline = - g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME); - while (true) { - auto ev = g_core_codegen_interface->grpc_completion_queue_pluck( - cq_, tag, deadline, nullptr); - bool ok = ev.success != 0; - void* ignored = tag; - if (tag->FinalizeResult(&ignored, &ok)) { - GPR_CODEGEN_ASSERT(ignored == tag); - return ok; - } - } - } - - /// Performs a single polling pluck on \a tag. - /// \warning Must not be mixed with calls to \a Next. - /// - /// TODO: sreek - This calls tag->FinalizeResult() even if the cq_ is already - /// shutdown. This is most likely a bug and if it is a bug, then change this - /// implementation to simple call the other TryPluck function with a zero - /// timeout. i.e: - /// TryPluck(tag, gpr_time_0(GPR_CLOCK_REALTIME)) - void TryPluck(internal::CompletionQueueTag* tag) { - auto deadline = g_core_codegen_interface->gpr_time_0(GPR_CLOCK_REALTIME); - auto ev = g_core_codegen_interface->grpc_completion_queue_pluck( - cq_, tag, deadline, nullptr); - if (ev.type == GRPC_QUEUE_TIMEOUT) return; - bool ok = ev.success != 0; - void* ignored = tag; - // the tag must be swallowed if using TryPluck - GPR_CODEGEN_ASSERT(!tag->FinalizeResult(&ignored, &ok)); - } - - /// Performs a single polling pluck on \a tag. Calls tag->FinalizeResult if - /// the pluck() was successful and returned the tag. - /// - /// This exects tag->FinalizeResult (if called) to return 'false' i.e expects - /// that the tag is internal not something that is returned to the user. - void TryPluck(internal::CompletionQueueTag* tag, gpr_timespec deadline) { - auto ev = g_core_codegen_interface->grpc_completion_queue_pluck( - cq_, tag, deadline, nullptr); - if (ev.type == GRPC_QUEUE_TIMEOUT || ev.type == GRPC_QUEUE_SHUTDOWN) { - return; - } - - bool ok = ev.success != 0; - void* ignored = tag; - GPR_CODEGEN_ASSERT(!tag->FinalizeResult(&ignored, &ok)); - } - - /// Manage state of avalanching operations : completion queue tags that - /// trigger other completion queue operations. The underlying core completion - /// queue should not really shutdown until all avalanching operations have - /// been finalized. Note that we maintain the requirement that an avalanche - /// registration must take place before CQ shutdown (which must be maintained - /// elsewhere) - void InitialAvalanching() { - gpr_atm_rel_store(&avalanches_in_flight_, static_cast(1)); - } - void RegisterAvalanching() { - gpr_atm_no_barrier_fetch_add(&avalanches_in_flight_, - static_cast(1)); - } - void CompleteAvalanching() { - if (gpr_atm_no_barrier_fetch_add(&avalanches_in_flight_, - static_cast(-1)) == 1) { - g_core_codegen_interface->grpc_completion_queue_shutdown(cq_); - } - } - - grpc_completion_queue* cq_; // owned - - gpr_atm avalanches_in_flight_; -}; - -/// A specific type of completion queue used by the processing of notifications -/// by servers. Instantiated by \a ServerBuilder. -class ServerCompletionQueue : public CompletionQueue { - public: - bool IsFrequentlyPolled() { return polling_type_ != GRPC_CQ_NON_LISTENING; } - - protected: - /// Default constructor - ServerCompletionQueue() : polling_type_(GRPC_CQ_DEFAULT_POLLING) {} - - private: - /// \param completion_type indicates whether this is a NEXT or CALLBACK - /// completion queue. - /// \param polling_type Informs the GRPC library about the type of polling - /// allowed on this completion queue. See grpc_cq_polling_type's description - /// in grpc_types.h for more details. - /// \param shutdown_cb is the shutdown callback used for CALLBACK api queues - ServerCompletionQueue(grpc_cq_completion_type completion_type, - grpc_cq_polling_type polling_type, - grpc_experimental_completion_queue_functor* shutdown_cb) - : CompletionQueue(grpc_completion_queue_attributes{ - GRPC_CQ_CURRENT_VERSION, completion_type, polling_type, - shutdown_cb}), - polling_type_(polling_type) {} - - grpc_cq_polling_type polling_type_; - friend class ::grpc_impl::ServerBuilder; - friend class Server; -}; +typedef ::grpc_impl::CompletionQueue CompletionQueue; +typedef ::grpc_impl::ServerCompletionQueue ServerCompletionQueue; } // namespace grpc diff --git a/include/grpcpp/impl/codegen/completion_queue_impl.h b/include/grpcpp/impl/codegen/completion_queue_impl.h new file mode 100644 index 00000000000..d5c4bb0f201 --- /dev/null +++ b/include/grpcpp/impl/codegen/completion_queue_impl.h @@ -0,0 +1,422 @@ +/* + * + * Copyright 2015-2016 gRPC authors. + * + * 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. + * + */ + +/// A completion queue implements a concurrent producer-consumer queue, with +/// two main API-exposed methods: \a Next and \a AsyncNext. These +/// methods are the essential component of the gRPC C++ asynchronous API. +/// There is also a \a Shutdown method to indicate that a given completion queue +/// will no longer have regular events. This must be called before the +/// completion queue is destroyed. +/// All completion queue APIs are thread-safe and may be used concurrently with +/// any other completion queue API invocation; it is acceptable to have +/// multiple threads calling \a Next or \a AsyncNext on the same or different +/// completion queues, or to call these methods concurrently with a \a Shutdown +/// elsewhere. +/// \remark{All other API calls on completion queue should be completed before +/// a completion queue destructor is called.} +#ifndef GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_IMPL_H +#define GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_IMPL_H + +#include +#include +#include +#include +#include +#include + +struct grpc_completion_queue; + +namespace grpc_impl { + +class Channel; +class Server; +class ServerBuilder; +} // namespace grpc_impl +namespace grpc { + +template +class ClientReader; +template +class ClientWriter; +template +class ClientReaderWriter; +template +class ServerReader; +template +class ServerWriter; +namespace internal { +template +class ServerReaderWriterBody; +} // namespace internal + +class ChannelInterface; +class ClientContext; +class ServerContext; +class ServerInterface; + +namespace internal { +class CompletionQueueTag; +class RpcMethod; +template +class RpcMethodHandler; +template +class ClientStreamingHandler; +template +class ServerStreamingHandler; +template +class BidiStreamingHandler; +template +class TemplatedBidiStreamingHandler; +template +class ErrorMethodHandler; +template +class BlockingUnaryCallImpl; +template +class CallOpSet; +} // namespace internal + +extern CoreCodegenInterface* g_core_codegen_interface; + +} // namespace grpc + +namespace grpc_impl { + +/// A thin wrapper around \ref grpc_completion_queue (see \ref +/// src/core/lib/surface/completion_queue.h). +/// See \ref doc/cpp/perf_notes.md for notes on best practices for high +/// performance servers. +class CompletionQueue : private ::grpc::GrpcLibraryCodegen { + public: + /// Default constructor. Implicitly creates a \a grpc_completion_queue + /// instance. + CompletionQueue() + : CompletionQueue(grpc_completion_queue_attributes{ + GRPC_CQ_CURRENT_VERSION, GRPC_CQ_NEXT, GRPC_CQ_DEFAULT_POLLING, + nullptr}) {} + + /// Wrap \a take, taking ownership of the instance. + /// + /// \param take The completion queue instance to wrap. Ownership is taken. + explicit CompletionQueue(grpc_completion_queue* take); + + /// Destructor. Destroys the owned wrapped completion queue / instance. + ~CompletionQueue() { + ::grpc::g_core_codegen_interface->grpc_completion_queue_destroy(cq_); + } + + /// Tri-state return for AsyncNext: SHUTDOWN, GOT_EVENT, TIMEOUT. + enum NextStatus { + SHUTDOWN, ///< The completion queue has been shutdown and fully-drained + GOT_EVENT, ///< Got a new event; \a tag will be filled in with its + ///< associated value; \a ok indicating its success. + TIMEOUT ///< deadline was reached. + }; + + /// Read from the queue, blocking until an event is available or the queue is + /// shutting down. + /// + /// \param tag [out] Updated to point to the read event's tag. + /// \param ok [out] true if read a successful event, false otherwise. + /// + /// Note that each tag sent to the completion queue (through RPC operations + /// or alarms) will be delivered out of the completion queue by a call to + /// Next (or a related method), regardless of whether the operation succeeded + /// or not. Success here means that this operation completed in the normal + /// valid manner. + /// + /// Server-side RPC request: \a ok indicates that the RPC has indeed + /// been started. If it is false, the server has been Shutdown + /// before this particular call got matched to an incoming RPC. + /// + /// Client-side StartCall/RPC invocation: \a ok indicates that the RPC is + /// going to go to the wire. If it is false, it not going to the wire. This + /// would happen if the channel is either permanently broken or + /// transiently broken but with the fail-fast option. (Note that async unary + /// RPCs don't post a CQ tag at this point, nor do client-streaming + /// or bidi-streaming RPCs that have the initial metadata corked option set.) + /// + /// Client-side Write, Client-side WritesDone, Server-side Write, + /// Server-side Finish, Server-side SendInitialMetadata (which is + /// typically included in Write or Finish when not done explicitly): + /// \a ok means that the data/metadata/status/etc is going to go to the + /// wire. If it is false, it not going to the wire because the call + /// is already dead (i.e., canceled, deadline expired, other side + /// dropped the channel, etc). + /// + /// Client-side Read, Server-side Read, Client-side + /// RecvInitialMetadata (which is typically included in Read if not + /// done explicitly): \a ok indicates whether there is a valid message + /// that got read. If not, you know that there are certainly no more + /// messages that can ever be read from this stream. For the client-side + /// operations, this only happens because the call is dead. For the + /// server-sider operation, though, this could happen because the client + /// has done a WritesDone already. + /// + /// Client-side Finish: \a ok should always be true + /// + /// Server-side AsyncNotifyWhenDone: \a ok should always be true + /// + /// Alarm: \a ok is true if it expired, false if it was canceled + /// + /// \return true if got an event, false if the queue is fully drained and + /// shut down. + bool Next(void** tag, bool* ok) { + return (AsyncNextInternal(tag, ok, + ::grpc::g_core_codegen_interface->gpr_inf_future( + GPR_CLOCK_REALTIME)) != SHUTDOWN); + } + + /// Read from the queue, blocking up to \a deadline (or the queue's shutdown). + /// Both \a tag and \a ok are updated upon success (if an event is available + /// within the \a deadline). A \a tag points to an arbitrary location usually + /// employed to uniquely identify an event. + /// + /// \param tag [out] Upon success, updated to point to the event's tag. + /// \param ok [out] Upon success, true if a successful event, false otherwise + /// See documentation for CompletionQueue::Next for explanation of ok + /// \param deadline [in] How long to block in wait for an event. + /// + /// \return The type of event read. + template + NextStatus AsyncNext(void** tag, bool* ok, const T& deadline) { + ::grpc::TimePoint deadline_tp(deadline); + return AsyncNextInternal(tag, ok, deadline_tp.raw_time()); + } + + /// EXPERIMENTAL + /// First executes \a F, then reads from the queue, blocking up to + /// \a deadline (or the queue's shutdown). + /// Both \a tag and \a ok are updated upon success (if an event is available + /// within the \a deadline). A \a tag points to an arbitrary location usually + /// employed to uniquely identify an event. + /// + /// \param f [in] Function to execute before calling AsyncNext on this queue. + /// \param tag [out] Upon success, updated to point to the event's tag. + /// \param ok [out] Upon success, true if read a regular event, false + /// otherwise. + /// \param deadline [in] How long to block in wait for an event. + /// + /// \return The type of event read. + template + NextStatus DoThenAsyncNext(F&& f, void** tag, bool* ok, const T& deadline) { + CompletionQueueTLSCache cache = CompletionQueueTLSCache(this); + f(); + if (cache.Flush(tag, ok)) { + return GOT_EVENT; + } else { + return AsyncNext(tag, ok, deadline); + } + } + + /// Request the shutdown of the queue. + /// + /// \warning This method must be called at some point if this completion queue + /// is accessed with Next or AsyncNext. \a Next will not return false + /// until this method has been called and all pending tags have been drained. + /// (Likewise for \a AsyncNext returning \a NextStatus::SHUTDOWN .) + /// Only once either one of these methods does that (that is, once the queue + /// has been \em drained) can an instance of this class be destroyed. + /// Also note that applications must ensure that no work is enqueued on this + /// completion queue after this method is called. + void Shutdown(); + + /// Returns a \em raw pointer to the underlying \a grpc_completion_queue + /// instance. + /// + /// \warning Remember that the returned instance is owned. No transfer of + /// owership is performed. + grpc_completion_queue* cq() { return cq_; } + + protected: + /// Private constructor of CompletionQueue only visible to friend classes + CompletionQueue(const grpc_completion_queue_attributes& attributes) { + cq_ = ::grpc::g_core_codegen_interface->grpc_completion_queue_create( + ::grpc::g_core_codegen_interface->grpc_completion_queue_factory_lookup( + &attributes), + &attributes, NULL); + InitialAvalanching(); // reserve this for the future shutdown + } + + private: + // Friend synchronous wrappers so that they can access Pluck(), which is + // a semi-private API geared towards the synchronous implementation. + template + friend class ::grpc::ClientReader; + template + friend class ::grpc::ClientWriter; + template + friend class ::grpc::ClientReaderWriter; + template + friend class ::grpc::ServerReader; + template + friend class ::grpc::ServerWriter; + template + friend class ::grpc::internal::ServerReaderWriterBody; + template + friend class ::grpc::internal::RpcMethodHandler; + template + friend class ::grpc::internal::ClientStreamingHandler; + template + friend class ::grpc::internal::ServerStreamingHandler; + template + friend class ::grpc::internal::TemplatedBidiStreamingHandler; + template <::grpc::StatusCode code> + friend class ::grpc::internal::ErrorMethodHandler; + friend class ::grpc_impl::Server; + friend class ::grpc::ServerContext; + friend class ::grpc::ServerInterface; + template + friend class ::grpc::internal::BlockingUnaryCallImpl; + + // Friends that need access to constructor for callback CQ + friend class ::grpc_impl::Channel; + + // For access to Register/CompleteAvalanching + template + friend class ::grpc::internal::CallOpSet; + + /// EXPERIMENTAL + /// Creates a Thread Local cache to store the first event + /// On this completion queue queued from this thread. Once + /// initialized, it must be flushed on the same thread. + class CompletionQueueTLSCache { + public: + CompletionQueueTLSCache(CompletionQueue* cq); + ~CompletionQueueTLSCache(); + bool Flush(void** tag, bool* ok); + + private: + CompletionQueue* cq_; + bool flushed_; + }; + + NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline); + + /// Wraps \a grpc_completion_queue_pluck. + /// \warning Must not be mixed with calls to \a Next. + bool Pluck(::grpc::internal::CompletionQueueTag* tag) { + auto deadline = + ::grpc::g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME); + while (true) { + auto ev = ::grpc::g_core_codegen_interface->grpc_completion_queue_pluck( + cq_, tag, deadline, nullptr); + bool ok = ev.success != 0; + void* ignored = tag; + if (tag->FinalizeResult(&ignored, &ok)) { + GPR_CODEGEN_ASSERT(ignored == tag); + return ok; + } + } + } + + /// Performs a single polling pluck on \a tag. + /// \warning Must not be mixed with calls to \a Next. + /// + /// TODO: sreek - This calls tag->FinalizeResult() even if the cq_ is already + /// shutdown. This is most likely a bug and if it is a bug, then change this + /// implementation to simple call the other TryPluck function with a zero + /// timeout. i.e: + /// TryPluck(tag, gpr_time_0(GPR_CLOCK_REALTIME)) + void TryPluck(::grpc::internal::CompletionQueueTag* tag) { + auto deadline = + ::grpc::g_core_codegen_interface->gpr_time_0(GPR_CLOCK_REALTIME); + auto ev = ::grpc::g_core_codegen_interface->grpc_completion_queue_pluck( + cq_, tag, deadline, nullptr); + if (ev.type == GRPC_QUEUE_TIMEOUT) return; + bool ok = ev.success != 0; + void* ignored = tag; + // the tag must be swallowed if using TryPluck + GPR_CODEGEN_ASSERT(!tag->FinalizeResult(&ignored, &ok)); + } + + /// Performs a single polling pluck on \a tag. Calls tag->FinalizeResult if + /// the pluck() was successful and returned the tag. + /// + /// This exects tag->FinalizeResult (if called) to return 'false' i.e expects + /// that the tag is internal not something that is returned to the user. + void TryPluck(::grpc::internal::CompletionQueueTag* tag, + gpr_timespec deadline) { + auto ev = ::grpc::g_core_codegen_interface->grpc_completion_queue_pluck( + cq_, tag, deadline, nullptr); + if (ev.type == GRPC_QUEUE_TIMEOUT || ev.type == GRPC_QUEUE_SHUTDOWN) { + return; + } + + bool ok = ev.success != 0; + void* ignored = tag; + GPR_CODEGEN_ASSERT(!tag->FinalizeResult(&ignored, &ok)); + } + + /// Manage state of avalanching operations : completion queue tags that + /// trigger other completion queue operations. The underlying core completion + /// queue should not really shutdown until all avalanching operations have + /// been finalized. Note that we maintain the requirement that an avalanche + /// registration must take place before CQ shutdown (which must be maintained + /// elsehwere) + void InitialAvalanching() { + gpr_atm_rel_store(&avalanches_in_flight_, static_cast(1)); + } + void RegisterAvalanching() { + gpr_atm_no_barrier_fetch_add(&avalanches_in_flight_, + static_cast(1)); + } + void CompleteAvalanching() { + if (gpr_atm_no_barrier_fetch_add(&avalanches_in_flight_, + static_cast(-1)) == 1) { + ::grpc::g_core_codegen_interface->grpc_completion_queue_shutdown(cq_); + } + } + + grpc_completion_queue* cq_; // owned + + gpr_atm avalanches_in_flight_; +}; + +/// A specific type of completion queue used by the processing of notifications +/// by servers. Instantiated by \a ServerBuilder. +class ServerCompletionQueue : public CompletionQueue { + public: + bool IsFrequentlyPolled() { return polling_type_ != GRPC_CQ_NON_LISTENING; } + + protected: + /// Default constructor + ServerCompletionQueue() : polling_type_(GRPC_CQ_DEFAULT_POLLING) {} + + private: + /// \param completion_type indicates whether this is a NEXT or CALLBACK + /// completion queue. + /// \param polling_type Informs the GRPC library about the type of polling + /// allowed on this completion queue. See grpc_cq_polling_type's description + /// in grpc_types.h for more details. + /// \param shutdown_cb is the shutdown callback used for CALLBACK api queues + ServerCompletionQueue(grpc_cq_completion_type completion_type, + grpc_cq_polling_type polling_type, + grpc_experimental_completion_queue_functor* shutdown_cb) + : CompletionQueue(grpc_completion_queue_attributes{ + GRPC_CQ_CURRENT_VERSION, completion_type, polling_type, + shutdown_cb}), + polling_type_(polling_type) {} + + grpc_cq_polling_type polling_type_; + friend class ::grpc_impl::ServerBuilder; + friend class ::grpc_impl::Server; +}; + +} // namespace grpc_impl + +#endif // GRPCPP_IMPL_CODEGEN_COMPLETION_QUEUE_IMPL_H diff --git a/include/grpcpp/impl/codegen/config_protobuf.h b/include/grpcpp/impl/codegen/config_protobuf.h index 8c2e9e67927..3c9ab3442af 100644 --- a/include/grpcpp/impl/codegen/config_protobuf.h +++ b/include/grpcpp/impl/codegen/config_protobuf.h @@ -30,9 +30,11 @@ #ifdef GRPC_USE_PROTO_LITE #include #define GRPC_CUSTOM_MESSAGE ::google::protobuf::MessageLite +#define GRPC_CUSTOM_MESSAGELITE ::google::protobuf::MessageLite #else #include #define GRPC_CUSTOM_MESSAGE ::google::protobuf::Message +#define GRPC_CUSTOM_MESSAGELITE ::google::protobuf::MessageLite #endif #endif @@ -76,6 +78,7 @@ namespace grpc { namespace protobuf { typedef GRPC_CUSTOM_MESSAGE Message; +typedef GRPC_CUSTOM_MESSAGELITE MessageLite; typedef GRPC_CUSTOM_PROTOBUF_INT64 int64; typedef GRPC_CUSTOM_DESCRIPTOR Descriptor; diff --git a/include/grpcpp/impl/codegen/intercepted_channel.h b/include/grpcpp/impl/codegen/intercepted_channel.h index 5255a6d1472..cd0fcc06753 100644 --- a/include/grpcpp/impl/codegen/intercepted_channel.h +++ b/include/grpcpp/impl/codegen/intercepted_channel.h @@ -21,6 +21,10 @@ #include +namespace grpc_impl { +class CompletionQueue; +} + namespace grpc { namespace internal { @@ -46,7 +50,7 @@ class InterceptedChannel : public ChannelInterface { : channel_(channel), interceptor_pos_(pos) {} Call CreateCall(const RpcMethod& method, ClientContext* context, - CompletionQueue* cq) override { + ::grpc_impl::CompletionQueue* cq) override { return channel_->CreateCallInternal(method, context, cq, interceptor_pos_); } @@ -58,7 +62,8 @@ class InterceptedChannel : public ChannelInterface { } void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed, - gpr_timespec deadline, CompletionQueue* cq, + gpr_timespec deadline, + ::grpc_impl::CompletionQueue* cq, void* tag) override { return channel_->NotifyOnStateChangeImpl(last_observed, deadline, cq, tag); } @@ -67,7 +72,9 @@ class InterceptedChannel : public ChannelInterface { return channel_->WaitForStateChangeImpl(last_observed, deadline); } - CompletionQueue* CallbackCQ() override { return channel_->CallbackCQ(); } + ::grpc_impl::CompletionQueue* CallbackCQ() override { + return channel_->CallbackCQ(); + } ChannelInterface* channel_; size_t interceptor_pos_; diff --git a/include/grpcpp/impl/codegen/message_allocator.h b/include/grpcpp/impl/codegen/message_allocator.h index 107bec62f1d..83544c64068 100644 --- a/include/grpcpp/impl/codegen/message_allocator.h +++ b/include/grpcpp/impl/codegen/message_allocator.h @@ -22,31 +22,49 @@ namespace grpc { namespace experimental { -// This is per rpc struct for the allocator. We can potentially put the grpc -// call arena in here in the future. +// NOTE: This is an API for advanced users who need custom allocators. +// Per rpc struct for the allocator. This is the interface to return to user. +class RpcAllocatorState { + public: + virtual ~RpcAllocatorState() = default; + // Optionally deallocate request early to reduce the size of working set. + // A custom MessageAllocator needs to be registered to make use of this. + // This is not abstract because implementing it is optional. + virtual void FreeRequest() {} +}; + +// This is the interface returned by the allocator. +// grpc library will call the methods to get request/response pointers and to +// release the object when it is done. template -struct RpcAllocatorInfo { - RequestT* request; - ResponseT* response; - // per rpc allocator internal state. MessageAllocator can set it when - // AllocateMessages is called and use it later. - void* allocator_state; +class MessageHolder : public RpcAllocatorState { + public: + // Release this object. For example, if the custom allocator's + // AllocateMessasge creates an instance of a subclass with new, the Release() + // should do a "delete this;". + virtual void Release() = 0; + RequestT* request() { return request_; } + ResponseT* response() { return response_; } + + protected: + void set_request(RequestT* request) { request_ = request; } + void set_response(ResponseT* response) { response_ = response; } + + private: + // NOTE: subclasses should set these pointers. + RequestT* request_; + ResponseT* response_; }; -// Implementations need to be thread-safe +// A custom allocator can be set via the generated code to a callback unary +// method, such as SetMessageAllocatorFor_Echo(custom_allocator). The allocator +// needs to be alive for the lifetime of the server. +// Implementations need to be thread-safe. template class MessageAllocator { public: virtual ~MessageAllocator() = default; - // Allocate both request and response - virtual void AllocateMessages( - RpcAllocatorInfo* info) = 0; - // Optional: deallocate request early, called by - // ServerCallbackRpcController::ReleaseRequest - virtual void DeallocateRequest(RpcAllocatorInfo* info) {} - // Deallocate response and request (if applicable) - virtual void DeallocateMessages( - RpcAllocatorInfo* info) = 0; + virtual MessageHolder* AllocateMessages() = 0; }; } // namespace experimental diff --git a/include/grpcpp/impl/codegen/proto_utils.h b/include/grpcpp/impl/codegen/proto_utils.h index d9db6de05c0..f9a7d3c0b34 100644 --- a/include/grpcpp/impl/codegen/proto_utils.h +++ b/include/grpcpp/impl/codegen/proto_utils.h @@ -42,7 +42,7 @@ extern CoreCodegenInterface* g_core_codegen_interface; // ProtoBufferWriter must be a subclass of ::protobuf::io::ZeroCopyOutputStream. template -Status GenericSerialize(const grpc::protobuf::Message& msg, ByteBuffer* bb, +Status GenericSerialize(const grpc::protobuf::MessageLite& msg, ByteBuffer* bb, bool* own_buffer) { static_assert(std::is_base_of::value, @@ -68,7 +68,8 @@ Status GenericSerialize(const grpc::protobuf::Message& msg, ByteBuffer* bb, // BufferReader must be a subclass of ::protobuf::io::ZeroCopyInputStream. template -Status GenericDeserialize(ByteBuffer* buffer, grpc::protobuf::Message* msg) { +Status GenericDeserialize(ByteBuffer* buffer, + grpc::protobuf::MessageLite* msg) { static_assert(std::is_base_of::value, "ProtoBufferReader must be a subclass of " @@ -102,15 +103,17 @@ Status GenericDeserialize(ByteBuffer* buffer, grpc::protobuf::Message* msg) { // objects and grpc_byte_buffers. More information about SerializationTraits can // be found in include/grpcpp/impl/codegen/serialization_traits.h. template -class SerializationTraits::value>::type> { +class SerializationTraits< + T, typename std::enable_if< + std::is_base_of::value>::type> { public: - static Status Serialize(const grpc::protobuf::Message& msg, ByteBuffer* bb, - bool* own_buffer) { + static Status Serialize(const grpc::protobuf::MessageLite& msg, + ByteBuffer* bb, bool* own_buffer) { return GenericSerialize(msg, bb, own_buffer); } - static Status Deserialize(ByteBuffer* buffer, grpc::protobuf::Message* msg) { + static Status Deserialize(ByteBuffer* buffer, + grpc::protobuf::MessageLite* msg) { return GenericDeserialize(buffer, msg); } }; diff --git a/include/grpcpp/impl/codegen/server_callback.h b/include/grpcpp/impl/codegen/server_callback.h index 3f6d5cd3555..9254518b605 100644 --- a/include/grpcpp/impl/codegen/server_callback.h +++ b/include/grpcpp/impl/codegen/server_callback.h @@ -77,6 +77,24 @@ class ServerReactor { std::atomic_int on_cancel_conditions_remaining_{2}; }; +template +class DefaultMessageHolder + : public experimental::MessageHolder { + public: + DefaultMessageHolder() { + this->set_request(&request_obj_); + this->set_response(&response_obj_); + } + void Release() override { + // the object is allocated in the call arena. + this->~DefaultMessageHolder(); + } + + private: + Request request_obj_; + Response response_obj_; +}; + } // namespace internal namespace experimental { @@ -137,13 +155,9 @@ class ServerCallbackRpcController { virtual void SetCancelCallback(std::function callback) = 0; virtual void ClearCancelCallback() = 0; - // NOTE: This is an API for advanced users who need custom allocators. - // Optionally deallocate request early to reduce the size of working set. - // A custom MessageAllocator needs to be registered to make use of this. - virtual void FreeRequest() = 0; // NOTE: This is an API for advanced users who need custom allocators. // Get and maybe mutate the allocator state associated with the current RPC. - virtual void* GetAllocatorState() = 0; + virtual RpcAllocatorState* GetRpcAllocatorState() = 0; }; // NOTE: The actual streaming object classes are provided @@ -465,13 +479,13 @@ class CallbackUnaryHandler : public MethodHandler { void RunHandler(const HandlerParameter& param) final { // Arena allocate a controller structure (that includes request/response) g_core_codegen_interface->grpc_call_ref(param.call->call()); - auto* allocator_info = - static_cast*>( + auto* allocator_state = + static_cast*>( param.internal_data); auto* controller = new (g_core_codegen_interface->grpc_call_arena_alloc( param.call->call(), sizeof(ServerCallbackRpcControllerImpl))) ServerCallbackRpcControllerImpl(param.server_context, param.call, - allocator_info, allocator_, + allocator_state, std::move(param.call_requester)); Status status = param.status; if (status.ok()) { @@ -489,36 +503,24 @@ class CallbackUnaryHandler : public MethodHandler { ByteBuffer buf; buf.set_buffer(req); RequestType* request = nullptr; - experimental::RpcAllocatorInfo* allocator_info = - new (g_core_codegen_interface->grpc_call_arena_alloc( - call, sizeof(*allocator_info))) - experimental::RpcAllocatorInfo(); + experimental::MessageHolder* allocator_state = + nullptr; if (allocator_ != nullptr) { - allocator_->AllocateMessages(allocator_info); + allocator_state = allocator_->AllocateMessages(); } else { - allocator_info->request = - new (g_core_codegen_interface->grpc_call_arena_alloc( - call, sizeof(RequestType))) RequestType(); - allocator_info->response = - new (g_core_codegen_interface->grpc_call_arena_alloc( - call, sizeof(ResponseType))) ResponseType(); + allocator_state = new (g_core_codegen_interface->grpc_call_arena_alloc( + call, sizeof(DefaultMessageHolder))) + DefaultMessageHolder(); } - *handler_data = allocator_info; - request = allocator_info->request; + *handler_data = allocator_state; + request = allocator_state->request(); *status = SerializationTraits::Deserialize(&buf, request); buf.Release(); if (status->ok()) { return request; } // Clean up on deserialization failure. - if (allocator_ != nullptr) { - allocator_->DeallocateMessages(allocator_info); - } else { - allocator_info->request->~RequestType(); - allocator_info->response->~ResponseType(); - allocator_info->request = nullptr; - allocator_info->response = nullptr; - } + allocator_state->Release(); return nullptr; } @@ -548,9 +550,8 @@ class CallbackUnaryHandler : public MethodHandler { } // The response is dropped if the status is not OK. if (s.ok()) { - finish_ops_.ServerSendStatus( - &ctx_->trailing_metadata_, - finish_ops_.SendMessagePtr(allocator_info_->response)); + finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, + finish_ops_.SendMessagePtr(response())); } else { finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s); } @@ -588,14 +589,8 @@ class CallbackUnaryHandler : public MethodHandler { void ClearCancelCallback() override { ctx_->ClearCancelCallback(); } - void FreeRequest() override { - if (allocator_ != nullptr) { - allocator_->DeallocateRequest(allocator_info_); - } - } - - void* GetAllocatorState() override { - return allocator_info_->allocator_state; + experimental::RpcAllocatorState* GetRpcAllocatorState() override { + return allocator_state_; } private: @@ -603,35 +598,23 @@ class CallbackUnaryHandler : public MethodHandler { ServerCallbackRpcControllerImpl( ServerContext* ctx, Call* call, - experimental::RpcAllocatorInfo* - allocator_info, - experimental::MessageAllocator* allocator, + experimental::MessageHolder* allocator_state, std::function call_requester) : ctx_(ctx), call_(*call), - allocator_info_(allocator_info), - allocator_(allocator), + allocator_state_(allocator_state), call_requester_(std::move(call_requester)) { ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, nullptr); } - const RequestType* request() { return allocator_info_->request; } - ResponseType* response() { return allocator_info_->response; } + const RequestType* request() { return allocator_state_->request(); } + ResponseType* response() { return allocator_state_->response(); } void MaybeDone() { if (--callbacks_outstanding_ == 0) { grpc_call* call = call_.call(); auto call_requester = std::move(call_requester_); - if (allocator_ != nullptr) { - allocator_->DeallocateMessages(allocator_info_); - } else { - if (allocator_info_->request != nullptr) { - allocator_info_->request->~RequestType(); - } - if (allocator_info_->response != nullptr) { - allocator_info_->response->~ResponseType(); - } - } + allocator_state_->Release(); this->~ServerCallbackRpcControllerImpl(); // explicitly call destructor g_core_codegen_interface->grpc_call_unref(call); call_requester(); @@ -647,8 +630,8 @@ class CallbackUnaryHandler : public MethodHandler { ServerContext* ctx_; Call call_; - experimental::RpcAllocatorInfo* allocator_info_; - experimental::MessageAllocator* allocator_; + experimental::MessageHolder* const + allocator_state_; std::function call_requester_; std::atomic_int callbacks_outstanding_{ 2}; // reserve for Finish and CompletionOp diff --git a/include/grpcpp/impl/codegen/server_context.h b/include/grpcpp/impl/codegen/server_context.h index 591a9ff9549..c6903743938 100644 --- a/include/grpcpp/impl/codegen/server_context.h +++ b/include/grpcpp/impl/codegen/server_context.h @@ -41,11 +41,14 @@ struct grpc_metadata; struct grpc_call; struct census_context; +namespace grpc_impl { + +class CompletionQueue; +class Server; +} // namespace grpc_impl namespace grpc { class ClientContext; class GenericServerContext; -class CompletionQueue; -class Server; class ServerInterface; template class ServerAsyncReader; @@ -87,6 +90,7 @@ class Call; class ServerReactor; } // namespace internal +class ServerInterface; namespace testing { class InteropServerContextInspector; class ServerContextTestSpouse; @@ -269,7 +273,7 @@ class ServerContext { friend class ::grpc::testing::InteropServerContextInspector; friend class ::grpc::testing::ServerContextTestSpouse; friend class ::grpc::ServerInterface; - friend class ::grpc::Server; + friend class ::grpc_impl::Server; template friend class ::grpc::ServerAsyncReader; template @@ -351,7 +355,7 @@ class ServerContext { gpr_timespec deadline_; grpc_call* call_; - CompletionQueue* cq_; + ::grpc_impl::CompletionQueue* cq_; bool sent_initial_metadata_; mutable std::shared_ptr auth_context_; mutable internal::MetadataMap client_metadata_; diff --git a/include/grpcpp/impl/codegen/server_interface.h b/include/grpcpp/impl/codegen/server_interface.h index 328f4389628..d8d49344965 100644 --- a/include/grpcpp/impl/codegen/server_interface.h +++ b/include/grpcpp/impl/codegen/server_interface.h @@ -30,14 +30,15 @@ namespace grpc_impl { +class Channel; +class CompletionQueue; +class ServerCompletionQueue; class ServerCredentials; -} +} // namespace grpc_impl namespace grpc { class AsyncGenericService; -class Channel; class GenericServerContext; -class ServerCompletionQueue; class ServerContext; class Service; @@ -161,7 +162,8 @@ class ServerInterface : public internal::CallHook { /// caller is required to keep all completion queues live until the server is /// destroyed. /// \param num_cqs How many completion queues does \a cqs hold. - virtual void Start(ServerCompletionQueue** cqs, size_t num_cqs) = 0; + virtual void Start(::grpc_impl::ServerCompletionQueue** cqs, + size_t num_cqs) = 0; virtual void ShutdownInternal(gpr_timespec deadline) = 0; @@ -176,9 +178,9 @@ class ServerInterface : public internal::CallHook { public: BaseAsyncRequest(ServerInterface* server, ServerContext* context, internal::ServerAsyncStreamingInterface* stream, - CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag, - bool delete_on_finalize); + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, + void* tag, bool delete_on_finalize); virtual ~BaseAsyncRequest(); bool FinalizeResult(void** tag, bool* status) override; @@ -190,8 +192,8 @@ class ServerInterface : public internal::CallHook { ServerInterface* const server_; ServerContext* const context_; internal::ServerAsyncStreamingInterface* const stream_; - CompletionQueue* const call_cq_; - ServerCompletionQueue* const notification_cq_; + ::grpc_impl::CompletionQueue* const call_cq_; + ::grpc_impl::ServerCompletionQueue* const notification_cq_; void* const tag_; const bool delete_on_finalize_; grpc_call* call_; @@ -205,16 +207,17 @@ class ServerInterface : public internal::CallHook { public: RegisteredAsyncRequest(ServerInterface* server, ServerContext* context, internal::ServerAsyncStreamingInterface* stream, - CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag, - const char* name, internal::RpcMethod::RpcType type); + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, + void* tag, const char* name, + internal::RpcMethod::RpcType type); virtual bool FinalizeResult(void** tag, bool* status) override { /* If we are done intercepting, then there is nothing more for us to do */ if (done_intercepting_) { return BaseAsyncRequest::FinalizeResult(tag, status); } - call_wrapper_ = internal::Call( + call_wrapper_ = ::grpc::internal::Call( call_, server_, call_cq_, server_->max_receive_message_size(), context_->set_server_rpc_info(name_, type_, *server_->interceptor_creators())); @@ -223,7 +226,7 @@ class ServerInterface : public internal::CallHook { protected: void IssueRequest(void* registered_method, grpc_byte_buffer** payload, - ServerCompletionQueue* notification_cq); + ::grpc_impl::ServerCompletionQueue* notification_cq); const char* name_; const internal::RpcMethod::RpcType type_; }; @@ -233,8 +236,9 @@ class ServerInterface : public internal::CallHook { NoPayloadAsyncRequest(internal::RpcServiceMethod* registered_method, ServerInterface* server, ServerContext* context, internal::ServerAsyncStreamingInterface* stream, - CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag) + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, + void* tag) : RegisteredAsyncRequest( server, context, stream, call_cq, notification_cq, tag, registered_method->name(), registered_method->method_type()) { @@ -250,9 +254,9 @@ class ServerInterface : public internal::CallHook { PayloadAsyncRequest(internal::RpcServiceMethod* registered_method, ServerInterface* server, ServerContext* context, internal::ServerAsyncStreamingInterface* stream, - CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag, - Message* request) + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, + void* tag, Message* request) : RegisteredAsyncRequest( server, context, stream, call_cq, notification_cq, tag, registered_method->name(), registered_method->method_type()), @@ -307,9 +311,9 @@ class ServerInterface : public internal::CallHook { ServerInterface* const server_; ServerContext* const context_; internal::ServerAsyncStreamingInterface* const stream_; - CompletionQueue* const call_cq_; + ::grpc_impl::CompletionQueue* const call_cq_; - ServerCompletionQueue* const notification_cq_; + ::grpc_impl::ServerCompletionQueue* const notification_cq_; void* const tag_; Message* const request_; ByteBuffer payload_; @@ -319,9 +323,9 @@ class ServerInterface : public internal::CallHook { public: GenericAsyncRequest(ServerInterface* server, GenericServerContext* context, internal::ServerAsyncStreamingInterface* stream, - CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag, - bool delete_on_finalize); + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, + void* tag, bool delete_on_finalize); bool FinalizeResult(void** tag, bool* status) override; @@ -333,9 +337,9 @@ class ServerInterface : public internal::CallHook { void RequestAsyncCall(internal::RpcServiceMethod* method, ServerContext* context, internal::ServerAsyncStreamingInterface* stream, - CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag, - Message* message) { + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, + void* tag, Message* message) { GPR_CODEGEN_ASSERT(method); new PayloadAsyncRequest(method, this, context, stream, call_cq, notification_cq, tag, message); @@ -344,18 +348,19 @@ class ServerInterface : public internal::CallHook { void RequestAsyncCall(internal::RpcServiceMethod* method, ServerContext* context, internal::ServerAsyncStreamingInterface* stream, - CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag) { + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, + void* tag) { GPR_CODEGEN_ASSERT(method); new NoPayloadAsyncRequest(method, this, context, stream, call_cq, notification_cq, tag); } - void RequestAsyncGenericCall(GenericServerContext* context, - internal::ServerAsyncStreamingInterface* stream, - CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, - void* tag) { + void RequestAsyncGenericCall( + GenericServerContext* context, + internal::ServerAsyncStreamingInterface* stream, + ::grpc_impl::CompletionQueue* call_cq, + ::grpc_impl::ServerCompletionQueue* notification_cq, void* tag) { new GenericAsyncRequest(this, context, stream, call_cq, notification_cq, tag, true); } @@ -380,7 +385,7 @@ class ServerInterface : public internal::CallHook { // Returns nullptr (rather than being pure) since this is a post-1.0 method // and adding a new pure method to an interface would be a breaking change // (even though this is private and non-API) - virtual CompletionQueue* CallbackCQ() { return nullptr; } + virtual ::grpc_impl::CompletionQueue* CallbackCQ() { return nullptr; } }; } // namespace grpc diff --git a/include/grpcpp/impl/codegen/service_type.h b/include/grpcpp/impl/codegen/service_type.h index 198bc7244b4..f1d1272dc20 100644 --- a/include/grpcpp/impl/codegen/service_type.h +++ b/include/grpcpp/impl/codegen/service_type.h @@ -26,12 +26,14 @@ #include #include -namespace grpc { +namespace grpc_impl { -class CompletionQueue; class Server; +class CompletionQueue; +} // namespace grpc_impl +namespace grpc { + class ServerInterface; -class ServerCompletionQueue; class ServerContext; namespace internal { @@ -233,7 +235,7 @@ class Service { } private: - friend class Server; + friend class grpc_impl::Server; friend class ServerInterface; ServerInterface* server_; std::vector> methods_; diff --git a/include/grpcpp/impl/codegen/status_code_enum.h b/include/grpcpp/impl/codegen/status_code_enum.h index 09943f10de8..bdd7ead6add 100644 --- a/include/grpcpp/impl/codegen/status_code_enum.h +++ b/include/grpcpp/impl/codegen/status_code_enum.h @@ -119,7 +119,8 @@ enum StatusCode { INTERNAL = 13, /// The service is currently unavailable. This is a most likely a transient - /// condition and may be corrected by retrying with a backoff. + /// condition and may be corrected by retrying with a backoff. Note that it is + /// not always safe to retry non-idempotent operations. /// /// \warning Although data MIGHT not have been transmitted when this /// status occurs, there is NOT A GUARANTEE that the server has not seen diff --git a/include/grpcpp/impl/server_builder_plugin.h b/include/grpcpp/impl/server_builder_plugin.h index dd600a839d7..84a88f2dd7b 100644 --- a/include/grpcpp/impl/server_builder_plugin.h +++ b/include/grpcpp/impl/server_builder_plugin.h @@ -25,13 +25,12 @@ namespace grpc_impl { +class ChannelArguments; class ServerBuilder; class ServerInitializer; } // namespace grpc_impl namespace grpc { -class ChannelArguments; - /// This interface is meant for internal usage only. Implementations of this /// interface should add themselves to a \a ServerBuilder instance through the /// \a InternalAddPluginFactory method. @@ -58,7 +57,7 @@ class ServerBuilderPlugin { /// UpdateChannelArguments will be called in ServerBuilder::BuildAndStart(), /// before the Server instance is created. - virtual void UpdateChannelArguments(ChannelArguments* args) {} + virtual void UpdateChannelArguments(grpc_impl::ChannelArguments* args) {} virtual bool has_sync_methods() const { return false; } virtual bool has_async_methods() const { return false; } diff --git a/include/grpcpp/impl/server_initializer_impl.h b/include/grpcpp/impl/server_initializer_impl.h index ff610efa2ac..0e2c65f4af4 100644 --- a/include/grpcpp/impl/server_initializer_impl.h +++ b/include/grpcpp/impl/server_initializer_impl.h @@ -26,10 +26,10 @@ namespace grpc { -class Server; class Service; } // namespace grpc namespace grpc_impl { +class Server; class ServerInitializer { public: diff --git a/include/grpcpp/security/credentials.h b/include/grpcpp/security/credentials.h index 34d2e2ea463..e924275d592 100644 --- a/include/grpcpp/security/credentials.h +++ b/include/grpcpp/security/credentials.h @@ -19,265 +19,104 @@ #ifndef GRPCPP_SECURITY_CREDENTIALS_H #define GRPCPP_SECURITY_CREDENTIALS_H -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -struct grpc_call; +#include namespace grpc { -class CallCredentials; -class ChannelArguments; -class ChannelCredentials; -} // namespace grpc -namespace grpc_impl { -std::shared_ptr CreateCustomChannel( - const grpc::string& target, - const std::shared_ptr& creds, - const grpc::ChannelArguments& args); - -namespace experimental { -std::shared_ptr CreateCustomChannelWithInterceptors( - const grpc::string& target, - const std::shared_ptr& creds, - const grpc::ChannelArguments& args, - std::vector< - std::unique_ptr> - interceptor_creators); -} // namespace experimental -} // namespace grpc_impl -namespace grpc { -class Channel; -class SecureChannelCredentials; -class SecureCallCredentials; - -/// A channel credentials object encapsulates all the state needed by a client -/// to authenticate with a server for a given channel. -/// It can make various assertions, e.g., about the client’s identity, role -/// for all the calls on that channel. -/// -/// \see https://grpc.io/docs/guides/auth.html -class ChannelCredentials : private GrpcLibraryCodegen { - public: - ChannelCredentials(); - ~ChannelCredentials(); - - protected: - friend std::shared_ptr CompositeChannelCredentials( - const std::shared_ptr& channel_creds, - const std::shared_ptr& call_creds); - - virtual SecureChannelCredentials* AsSecureCredentials() = 0; - - private: - friend std::shared_ptr grpc_impl::CreateCustomChannel( - const grpc::string& target, - const std::shared_ptr& creds, - const grpc::ChannelArguments& args); - - friend std::shared_ptr - grpc_impl::experimental::CreateCustomChannelWithInterceptors( - const grpc::string& target, - const std::shared_ptr& creds, - const grpc::ChannelArguments& args, - std::vector> - interceptor_creators); - - virtual std::shared_ptr CreateChannel( - const grpc::string& target, const ChannelArguments& args) = 0; - - // This function should have been a pure virtual function, but it is - // implemented as a virtual function so that it does not break API. - virtual std::shared_ptr CreateChannelWithInterceptors( - const grpc::string& target, const ChannelArguments& args, - std::vector< - std::unique_ptr> - interceptor_creators) { - return nullptr; - } -}; - -/// A call credentials object encapsulates the state needed by a client to -/// authenticate with a server for a given call on a channel. -/// -/// \see https://grpc.io/docs/guides/auth.html -class CallCredentials : private GrpcLibraryCodegen { - public: - CallCredentials(); - ~CallCredentials(); - - /// Apply this instance's credentials to \a call. - virtual bool ApplyToCall(grpc_call* call) = 0; - - protected: - friend std::shared_ptr CompositeChannelCredentials( - const std::shared_ptr& channel_creds, - const std::shared_ptr& call_creds); +typedef ::grpc_impl::ChannelCredentials ChannelCredentials; +typedef ::grpc_impl::CallCredentials CallCredentials; +typedef ::grpc_impl::SslCredentialsOptions SslCredentialsOptions; +typedef ::grpc_impl::SecureCallCredentials SecureCallCredentials; +typedef ::grpc_impl::SecureChannelCredentials SecureChannelCredentials; - friend std::shared_ptr CompositeCallCredentials( - const std::shared_ptr& creds1, - const std::shared_ptr& creds2); +static inline std::shared_ptr +GoogleDefaultCredentials() { + return ::grpc_impl::GoogleDefaultCredentials(); +} - virtual SecureCallCredentials* AsSecureCredentials() = 0; -}; +static inline std::shared_ptr SslCredentials( + const SslCredentialsOptions& options) { + return ::grpc_impl::SslCredentials(options); +} -/// Options used to build SslCredentials. -struct SslCredentialsOptions { - /// The buffer containing the PEM encoding of the server root certificates. If - /// this parameter is empty, the default roots will be used. The default - /// roots can be overridden using the \a GRPC_DEFAULT_SSL_ROOTS_FILE_PATH - /// environment variable pointing to a file on the file system containing the - /// roots. - grpc::string pem_root_certs; - - /// The buffer containing the PEM encoding of the client's private key. This - /// parameter can be empty if the client does not have a private key. - grpc::string pem_private_key; - - /// The buffer containing the PEM encoding of the client's certificate chain. - /// This parameter can be empty if the client does not have a certificate - /// chain. - grpc::string pem_cert_chain; -}; - -// Factories for building different types of Credentials The functions may -// return empty shared_ptr when credentials cannot be created. If a -// Credentials pointer is returned, it can still be invalid when used to create -// a channel. A lame channel will be created then and all rpcs will fail on it. - -/// Builds credentials with reasonable defaults. -/// -/// \warning Only use these credentials when connecting to a Google endpoint. -/// Using these credentials to connect to any other service may result in this -/// service being able to impersonate your client for requests to Google -/// services. -std::shared_ptr GoogleDefaultCredentials(); - -/// Builds SSL Credentials given SSL specific options -std::shared_ptr SslCredentials( - const SslCredentialsOptions& options); - -/// Builds credentials for use when running in GCE -/// -/// \warning Only use these credentials when connecting to a Google endpoint. -/// Using these credentials to connect to any other service may result in this -/// service being able to impersonate your client for requests to Google -/// services. -std::shared_ptr GoogleComputeEngineCredentials(); +static inline std::shared_ptr +GoogleComputeEngineCredentials() { + return ::grpc_impl::GoogleComputeEngineCredentials(); +} /// Constant for maximum auth token lifetime. -constexpr long kMaxAuthTokenLifetimeSecs = 3600; +constexpr long kMaxAuthTokenLifetimeSecs = + ::grpc_impl::kMaxAuthTokenLifetimeSecs; -/// Builds Service Account JWT Access credentials. -/// json_key is the JSON key string containing the client's private key. -/// token_lifetime_seconds is the lifetime in seconds of each Json Web Token -/// (JWT) created with this credentials. It should not exceed -/// \a kMaxAuthTokenLifetimeSecs or will be cropped to this value. -std::shared_ptr ServiceAccountJWTAccessCredentials( +static inline std::shared_ptr +ServiceAccountJWTAccessCredentials( const grpc::string& json_key, - long token_lifetime_seconds = kMaxAuthTokenLifetimeSecs); - -/// Builds refresh token credentials. -/// json_refresh_token is the JSON string containing the refresh token along -/// with a client_id and client_secret. -/// -/// \warning Only use these credentials when connecting to a Google endpoint. -/// Using these credentials to connect to any other service may result in this -/// service being able to impersonate your client for requests to Google -/// services. -std::shared_ptr GoogleRefreshTokenCredentials( - const grpc::string& json_refresh_token); - -/// Builds access token credentials. -/// access_token is an oauth2 access token that was fetched using an out of band -/// mechanism. -/// -/// \warning Only use these credentials when connecting to a Google endpoint. -/// Using these credentials to connect to any other service may result in this -/// service being able to impersonate your client for requests to Google -/// services. -std::shared_ptr AccessTokenCredentials( - const grpc::string& access_token); - -/// Builds IAM credentials. -/// -/// \warning Only use these credentials when connecting to a Google endpoint. -/// Using these credentials to connect to any other service may result in this -/// service being able to impersonate your client for requests to Google -/// services. -std::shared_ptr GoogleIAMCredentials( + long token_lifetime_seconds = grpc::kMaxAuthTokenLifetimeSecs) { + return ::grpc_impl::ServiceAccountJWTAccessCredentials( + json_key, token_lifetime_seconds); +} + +static inline std::shared_ptr +GoogleRefreshTokenCredentials(const grpc::string& json_refresh_token) { + return ::grpc_impl::GoogleRefreshTokenCredentials(json_refresh_token); +} + +static inline std::shared_ptr +AccessTokenCredentials(const grpc::string& access_token) { + return ::grpc_impl::AccessTokenCredentials(access_token); +} + +static inline std::shared_ptr GoogleIAMCredentials( const grpc::string& authorization_token, - const grpc::string& authority_selector); + const grpc::string& authority_selector) { + return ::grpc_impl::GoogleIAMCredentials(authorization_token, + authority_selector); +} -/// Combines a channel credentials and a call credentials into a composite -/// channel credentials. -std::shared_ptr CompositeChannelCredentials( +static inline std::shared_ptr CompositeChannelCredentials( const std::shared_ptr& channel_creds, - const std::shared_ptr& call_creds); - -/// Combines two call credentials objects into a composite call credentials. -std::shared_ptr CompositeCallCredentials( - const std::shared_ptr& creds1, - const std::shared_ptr& creds2); - -/// Credentials for an unencrypted, unauthenticated channel -std::shared_ptr InsecureChannelCredentials(); - -/// Credentials for a channel using Cronet. -std::shared_ptr CronetChannelCredentials(void* engine); - -/// User defined metadata credentials. -class MetadataCredentialsPlugin { - public: - virtual ~MetadataCredentialsPlugin() {} - - /// If this method returns true, the Process function will be scheduled in - /// a different thread from the one processing the call. - virtual bool IsBlocking() const { return true; } - - /// Type of credentials this plugin is implementing. - virtual const char* GetType() const { return ""; } - - /// Gets the auth metatada produced by this plugin. - /// The fully qualified method name is: - /// service_url + "/" + method_name. - /// The channel_auth_context contains (among other things), the identity of - /// the server. - virtual Status GetMetadata( - grpc::string_ref service_url, grpc::string_ref method_name, - const AuthContext& channel_auth_context, - std::multimap* metadata) = 0; -}; - -std::shared_ptr MetadataCredentialsFromPlugin( - std::unique_ptr plugin); + const std::shared_ptr& call_creds) { + return ::grpc_impl::CompositeChannelCredentials(channel_creds, call_creds); +} + +static inline std::shared_ptr +CompositeCallCredentials(const std::shared_ptr& creds1, + const std::shared_ptr& creds2) { + return ::grpc_impl::CompositeCallCredentials(creds1, creds2); +} + +static inline std::shared_ptr +InsecureChannelCredentials() { + return ::grpc_impl::InsecureChannelCredentials(); +} + +static inline std::shared_ptr +CronetChannelCredentials(void* engine) { + return ::grpc_impl::CronetChannelCredentials(engine); +} + +typedef ::grpc_impl::MetadataCredentialsPlugin MetadataCredentialsPlugin; + +static inline std::shared_ptr +MetadataCredentialsFromPlugin( + std::unique_ptr plugin) { + return ::grpc_impl::MetadataCredentialsFromPlugin(std::move(plugin)); +} namespace experimental { -/// Options used to build AltsCredentials. -struct AltsCredentialsOptions { - /// service accounts of target endpoint that will be acceptable - /// by the client. If service accounts are provided and none of them matches - /// that of the server, authentication will fail. - std::vector target_service_accounts; -}; +typedef ::grpc_impl::experimental::AltsCredentialsOptions + AltsCredentialsOptions; -/// Builds ALTS Credentials given ALTS specific options -std::shared_ptr AltsCredentials( - const AltsCredentialsOptions& options); +static inline std::shared_ptr AltsCredentials( + const AltsCredentialsOptions& options) { + return ::grpc_impl::experimental::AltsCredentials(options); +} -/// Builds Local Credentials. -std::shared_ptr LocalCredentials( - grpc_local_connect_type type); +static inline std::shared_ptr LocalCredentials( + grpc_local_connect_type type) { + return ::grpc_impl::experimental::LocalCredentials(type); +} } // namespace experimental } // namespace grpc diff --git a/include/grpcpp/security/credentials_impl.h b/include/grpcpp/security/credentials_impl.h new file mode 100644 index 00000000000..29ba2075c29 --- /dev/null +++ b/include/grpcpp/security/credentials_impl.h @@ -0,0 +1,281 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * 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 GRPCPP_SECURITY_CREDENTIALS_IMPL_H +#define GRPCPP_SECURITY_CREDENTIALS_IMPL_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +struct grpc_call; + +namespace grpc_impl { + +class ChannelCredentials; +class CallCredentials; +class SecureCallCredentials; +class SecureChannelCredentials; + +std::shared_ptr<::grpc::Channel> CreateCustomChannelImpl( + const grpc::string& target, + const std::shared_ptr& creds, + const grpc::ChannelArguments& args); + +namespace experimental { +std::shared_ptr<::grpc::Channel> CreateCustomChannelWithInterceptors( + const grpc::string& target, + const std::shared_ptr& creds, + const grpc::ChannelArguments& args, + std::vector< + std::unique_ptr> + interceptor_creators); +} + +/// A channel credentials object encapsulates all the state needed by a client +/// to authenticate with a server for a given channel. +/// It can make various assertions, e.g., about the client’s identity, role +/// for all the calls on that channel. +/// +/// \see https://grpc.io/docs/guides/auth.html +class ChannelCredentials : private grpc::GrpcLibraryCodegen { + public: + ChannelCredentials(); + ~ChannelCredentials(); + + protected: + friend std::shared_ptr CompositeChannelCredentials( + const std::shared_ptr& channel_creds, + const std::shared_ptr& call_creds); + + virtual SecureChannelCredentials* AsSecureCredentials() = 0; + + private: + friend std::shared_ptr<::grpc::Channel> CreateCustomChannelImpl( + const grpc::string& target, + const std::shared_ptr& creds, + const grpc::ChannelArguments& args); + + friend std::shared_ptr<::grpc::Channel> + grpc_impl::experimental::CreateCustomChannelWithInterceptors( + const grpc::string& target, + const std::shared_ptr& creds, + const grpc::ChannelArguments& args, + std::vector> + interceptor_creators); + + virtual std::shared_ptr<::grpc::Channel> CreateChannelImpl( + const grpc::string& target, const grpc::ChannelArguments& args) = 0; + + // This function should have been a pure virtual function, but it is + // implemented as a virtual function so that it does not break API. + virtual std::shared_ptr<::grpc::Channel> CreateChannelWithInterceptors( + const grpc::string& target, const grpc::ChannelArguments& args, + std::vector> + interceptor_creators) { + return nullptr; + } +}; + +/// A call credentials object encapsulates the state needed by a client to +/// authenticate with a server for a given call on a channel. +/// +/// \see https://grpc.io/docs/guides/auth.html +class CallCredentials : private grpc::GrpcLibraryCodegen { + public: + CallCredentials(); + ~CallCredentials(); + + /// Apply this instance's credentials to \a call. + virtual bool ApplyToCall(grpc_call* call) = 0; + + protected: + friend std::shared_ptr CompositeChannelCredentials( + const std::shared_ptr& channel_creds, + const std::shared_ptr& call_creds); + + friend std::shared_ptr CompositeCallCredentials( + const std::shared_ptr& creds1, + const std::shared_ptr& creds2); + + virtual SecureCallCredentials* AsSecureCredentials() = 0; +}; + +/// Options used to build SslCredentials. +struct SslCredentialsOptions { + /// The buffer containing the PEM encoding of the server root certificates. If + /// this parameter is empty, the default roots will be used. The default + /// roots can be overridden using the \a GRPC_DEFAULT_SSL_ROOTS_FILE_PATH + /// environment variable pointing to a file on the file system containing the + /// roots. + grpc::string pem_root_certs; + + /// The buffer containing the PEM encoding of the client's private key. This + /// parameter can be empty if the client does not have a private key. + grpc::string pem_private_key; + + /// The buffer containing the PEM encoding of the client's certificate chain. + /// This parameter can be empty if the client does not have a certificate + /// chain. + grpc::string pem_cert_chain; +}; + +// Factories for building different types of Credentials The functions may +// return empty shared_ptr when credentials cannot be created. If a +// Credentials pointer is returned, it can still be invalid when used to create +// a channel. A lame channel will be created then and all rpcs will fail on it. + +/// Builds credentials with reasonable defaults. +/// +/// \warning Only use these credentials when connecting to a Google endpoint. +/// Using these credentials to connect to any other service may result in this +/// service being able to impersonate your client for requests to Google +/// services. +std::shared_ptr GoogleDefaultCredentials(); + +/// Builds SSL Credentials given SSL specific options +std::shared_ptr SslCredentials( + const SslCredentialsOptions& options); + +/// Builds credentials for use when running in GCE +/// +/// \warning Only use these credentials when connecting to a Google endpoint. +/// Using these credentials to connect to any other service may result in this +/// service being able to impersonate your client for requests to Google +/// services. +std::shared_ptr GoogleComputeEngineCredentials(); + +constexpr long kMaxAuthTokenLifetimeSecs = 3600; + +/// Builds Service Account JWT Access credentials. +/// json_key is the JSON key string containing the client's private key. +/// token_lifetime_seconds is the lifetime in seconds of each Json Web Token +/// (JWT) created with this credentials. It should not exceed +/// \a kMaxAuthTokenLifetimeSecs or will be cropped to this value. +std::shared_ptr ServiceAccountJWTAccessCredentials( + const grpc::string& json_key, + long token_lifetime_seconds = grpc_impl::kMaxAuthTokenLifetimeSecs); + +/// Builds refresh token credentials. +/// json_refresh_token is the JSON string containing the refresh token along +/// with a client_id and client_secret. +/// +/// \warning Only use these credentials when connecting to a Google endpoint. +/// Using these credentials to connect to any other service may result in this +/// service being able to impersonate your client for requests to Google +/// services. +std::shared_ptr GoogleRefreshTokenCredentials( + const grpc::string& json_refresh_token); + +/// Builds access token credentials. +/// access_token is an oauth2 access token that was fetched using an out of band +/// mechanism. +/// +/// \warning Only use these credentials when connecting to a Google endpoint. +/// Using these credentials to connect to any other service may result in this +/// service being able to impersonate your client for requests to Google +/// services. +std::shared_ptr AccessTokenCredentials( + const grpc::string& access_token); + +/// Builds IAM credentials. +/// +/// \warning Only use these credentials when connecting to a Google endpoint. +/// Using these credentials to connect to any other service may result in this +/// service being able to impersonate your client for requests to Google +/// services. +std::shared_ptr GoogleIAMCredentials( + const grpc::string& authorization_token, + const grpc::string& authority_selector); + +/// Combines a channel credentials and a call credentials into a composite +/// channel credentials. +std::shared_ptr CompositeChannelCredentials( + const std::shared_ptr& channel_creds, + const std::shared_ptr& call_creds); + +/// Combines two call credentials objects into a composite call credentials. +std::shared_ptr CompositeCallCredentials( + const std::shared_ptr& creds1, + const std::shared_ptr& creds2); + +/// Credentials for an unencrypted, unauthenticated channel +std::shared_ptr InsecureChannelCredentials(); + +/// Credentials for a channel using Cronet. +std::shared_ptr CronetChannelCredentials(void* engine); + +/// User defined metadata credentials. +class MetadataCredentialsPlugin { + public: + virtual ~MetadataCredentialsPlugin() {} + + /// If this method returns true, the Process function will be scheduled in + /// a different thread from the one processing the call. + virtual bool IsBlocking() const { return true; } + + /// Type of credentials this plugin is implementing. + virtual const char* GetType() const { return ""; } + + /// Gets the auth metatada produced by this plugin. + /// The fully qualified method name is: + /// service_url + "/" + method_name. + /// The channel_auth_context contains (among other things), the identity of + /// the server. + virtual grpc::Status GetMetadata( + grpc::string_ref service_url, grpc::string_ref method_name, + const grpc::AuthContext& channel_auth_context, + std::multimap* metadata) = 0; +}; + +std::shared_ptr MetadataCredentialsFromPlugin( + std::unique_ptr plugin); + +namespace experimental { + +/// Options used to build AltsCredentials. +struct AltsCredentialsOptions { + /// service accounts of target endpoint that will be acceptable + /// by the client. If service accounts are provided and none of them matches + /// that of the server, authentication will fail. + std::vector target_service_accounts; +}; + +/// Builds ALTS Credentials given ALTS specific options +std::shared_ptr AltsCredentials( + const AltsCredentialsOptions& options); + +/// Builds Local Credentials. +std::shared_ptr LocalCredentials( + grpc_local_connect_type type); + +} // namespace experimental +} // namespace grpc_impl + +#endif // GRPCPP_SECURITY_CREDENTIALS_IMPL_H diff --git a/include/grpcpp/security/server_credentials.h b/include/grpcpp/security/server_credentials.h index 7e643ae7400..57f733886f4 100644 --- a/include/grpcpp/security/server_credentials.h +++ b/include/grpcpp/security/server_credentials.h @@ -21,6 +21,10 @@ #include +namespace grpc_impl { + +class Server; +} // namespace grpc_impl namespace grpc { typedef ::grpc_impl::ServerCredentials ServerCredentials; diff --git a/include/grpcpp/security/server_credentials_impl.h b/include/grpcpp/security/server_credentials_impl.h index afe8d22650b..f08849097ad 100644 --- a/include/grpcpp/security/server_credentials_impl.h +++ b/include/grpcpp/security/server_credentials_impl.h @@ -30,10 +30,10 @@ struct grpc_server; namespace grpc { -class Server; struct SslServerCredentialsOptions; } // namespace grpc namespace grpc_impl { +class Server; /// Wrapper around \a grpc_server_credentials, a way to authenticate a server. class ServerCredentials { @@ -46,7 +46,7 @@ class ServerCredentials { const std::shared_ptr& processor) = 0; private: - friend class ::grpc::Server; + friend class ::grpc_impl::Server; /// Tries to bind \a server to the given \a addr (eg, localhost:1234, /// 192.168.1.1:31416, [::1]:27182, etc.) diff --git a/include/grpcpp/server.h b/include/grpcpp/server.h index 8aff0663fe2..3de2aba0b59 100644 --- a/include/grpcpp/server.h +++ b/include/grpcpp/server.h @@ -1,6 +1,6 @@ /* * - * Copyright 2015 gRPC authors. + * Copyright 2019 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,333 +19,11 @@ #ifndef GRPCPP_SERVER_H #define GRPCPP_SERVER_H -#include -#include -#include -#include -#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct grpc_server; - -namespace grpc_impl { - -class ServerInitializer; -} namespace grpc { -class AsyncGenericService; -class ServerContext; - -/// Represents a gRPC server. -/// -/// Use a \a grpc::ServerBuilder to create, configure, and start -/// \a Server instances. -class Server : public ServerInterface, private GrpcLibraryCodegen { - public: - ~Server(); - - /// Block until the server shuts down. - /// - /// \warning The server must be either shutting down or some other thread must - /// call \a Shutdown for this function to ever return. - void Wait() override; - - /// Global callbacks are a set of hooks that are called when server - /// events occur. \a SetGlobalCallbacks method is used to register - /// the hooks with gRPC. Note that - /// the \a GlobalCallbacks instance will be shared among all - /// \a Server instances in an application and can be set exactly - /// once per application. - class GlobalCallbacks { - public: - virtual ~GlobalCallbacks() {} - /// Called before server is created. - virtual void UpdateArguments(ChannelArguments* args) {} - /// Called before application callback for each synchronous server request - virtual void PreSynchronousRequest(ServerContext* context) = 0; - /// Called after application callback for each synchronous server request - virtual void PostSynchronousRequest(ServerContext* context) = 0; - /// Called before server is started. - virtual void PreServerStart(Server* server) {} - /// Called after a server port is added. - virtual void AddPort(Server* server, const grpc::string& addr, - ServerCredentials* creds, int port) {} - }; - /// Set the global callback object. Can only be called once per application. - /// Does not take ownership of callbacks, and expects the pointed to object - /// to be alive until all server objects in the process have been destroyed. - /// The same \a GlobalCallbacks object will be used throughout the - /// application and is shared among all \a Server objects. - static void SetGlobalCallbacks(GlobalCallbacks* callbacks); - - /// Returns a \em raw pointer to the underlying \a grpc_server instance. - /// EXPERIMENTAL: for internal/test use only - grpc_server* c_server(); - - /// Returns the health check service. - HealthCheckServiceInterface* GetHealthCheckService() const { - return health_check_service_.get(); - } - - /// Establish a channel for in-process communication - std::shared_ptr InProcessChannel(const ChannelArguments& args); - - /// NOTE: class experimental_type is not part of the public API of this class. - /// TODO(yashykt): Integrate into public API when this is no longer - /// experimental. - class experimental_type { - public: - explicit experimental_type(Server* server) : server_(server) {} - - /// Establish a channel for in-process communication with client - /// interceptors - std::shared_ptr InProcessChannelWithInterceptors( - const ChannelArguments& args, - std::vector< - std::unique_ptr> - interceptor_creators); - - private: - Server* server_; - }; - - /// NOTE: The function experimental() is not stable public API. It is a view - /// to the experimental components of this class. It may be changed or removed - /// at any time. - experimental_type experimental() { return experimental_type(this); } - - protected: - /// Register a service. This call does not take ownership of the service. - /// The service must exist for the lifetime of the Server instance. - bool RegisterService(const grpc::string* host, Service* service) override; - - /// Try binding the server to the given \a addr endpoint - /// (port, and optionally including IP address to bind to). - /// - /// It can be invoked multiple times. Should be used before - /// starting the server. - /// - /// \param addr The address to try to bind to the server (eg, localhost:1234, - /// 192.168.1.1:31416, [::1]:27182, etc.). - /// \param creds The credentials associated with the server. - /// - /// \return bound port number on success, 0 on failure. - /// - /// \warning It is an error to call this method on an already started server. - int AddListeningPort(const grpc::string& addr, - ServerCredentials* creds) override; - - /// NOTE: This is *NOT* a public API. The server constructors are supposed to - /// be used by \a ServerBuilder class only. The constructor will be made - /// 'private' very soon. - /// - /// Server constructors. To be used by \a ServerBuilder only. - /// - /// \param max_message_size Maximum message length that the channel can - /// receive. - /// - /// \param args The channel args - /// - /// \param sync_server_cqs The completion queues to use if the server is a - /// synchronous server (or a hybrid server). The server polls for new RPCs on - /// these queues - /// - /// \param min_pollers The minimum number of polling threads per server - /// completion queue (in param sync_server_cqs) to use for listening to - /// incoming requests (used only in case of sync server) - /// - /// \param max_pollers The maximum number of polling threads per server - /// completion queue (in param sync_server_cqs) to use for listening to - /// incoming requests (used only in case of sync server) - /// - /// \param sync_cq_timeout_msec The timeout to use when calling AsyncNext() on - /// server completion queues passed via sync_server_cqs param. - Server(int max_message_size, ChannelArguments* args, - std::shared_ptr>> - sync_server_cqs, - int min_pollers, int max_pollers, int sync_cq_timeout_msec, - grpc_resource_quota* server_rq = nullptr, - std::vector< - std::unique_ptr> - interceptor_creators = std::vector>()); - - /// Start the server. - /// - /// \param cqs Completion queues for handling asynchronous services. The - /// caller is required to keep all completion queues live until the server is - /// destroyed. - /// \param num_cqs How many completion queues does \a cqs hold. - void Start(ServerCompletionQueue** cqs, size_t num_cqs) override; - - grpc_server* server() override { return server_; } - - private: - std::vector>* - interceptor_creators() override { - return &interceptor_creators_; - } - - friend class AsyncGenericService; - friend class grpc_impl::ServerBuilder; - friend class grpc_impl::ServerInitializer; - - class SyncRequest; - class CallbackRequestBase; - template - class CallbackRequest; - class UnimplementedAsyncRequest; - class UnimplementedAsyncResponse; - - /// SyncRequestThreadManager is an implementation of ThreadManager. This class - /// is responsible for polling for incoming RPCs and calling the RPC handlers. - /// This is only used in case of a Sync server (i.e a server exposing a sync - /// interface) - class SyncRequestThreadManager; - - /// Register a generic service. This call does not take ownership of the - /// service. The service must exist for the lifetime of the Server instance. - void RegisterAsyncGenericService(AsyncGenericService* service) override; - - /// NOTE: class experimental_registration_type is not part of the public API - /// of this class - /// TODO(vjpai): Move these contents to the public API of Server when - /// they are no longer experimental - class experimental_registration_type final - : public experimental_registration_interface { - public: - explicit experimental_registration_type(Server* server) : server_(server) {} - void RegisterCallbackGenericService( - experimental::CallbackGenericService* service) override { - server_->RegisterCallbackGenericService(service); - } - - private: - Server* server_; - }; - - /// TODO(vjpai): Mark this override when experimental type above is deleted - void RegisterCallbackGenericService( - experimental::CallbackGenericService* service); - - /// NOTE: The function experimental_registration() is not stable public API. - /// It is a view to the experimental components of this class. It may be - /// changed or removed at any time. - experimental_registration_interface* experimental_registration() override { - return &experimental_registration_; - } - - void PerformOpsOnCall(internal::CallOpSetInterface* ops, - internal::Call* call) override; - - void ShutdownInternal(gpr_timespec deadline) override; - - int max_receive_message_size() const override { - return max_receive_message_size_; - } - - CompletionQueue* CallbackCQ() override; - - grpc_impl::ServerInitializer* initializer(); - - // A vector of interceptor factory objects. - // This should be destroyed after health_check_service_ and this requirement - // is satisfied by declaring interceptor_creators_ before - // health_check_service_. (C++ mandates that member objects be destroyed in - // the reverse order of initialization.) - std::vector> - interceptor_creators_; - - const int max_receive_message_size_; - - /// The following completion queues are ONLY used in case of Sync API - /// i.e. if the server has any services with sync methods. The server uses - /// these completion queues to poll for new RPCs - std::shared_ptr>> - sync_server_cqs_; - - /// List of \a ThreadManager instances (one for each cq in - /// the \a sync_server_cqs) - std::vector> sync_req_mgrs_; - - // Outstanding unmatched callback requests, indexed by method. - // NOTE: Using a gpr_atm rather than atomic_int because atomic_int isn't - // copyable or movable and thus will cause compilation errors. We - // actually only want to extend the vector before the threaded use - // starts, but this is still a limitation. - std::vector callback_unmatched_reqs_count_; - - // List of callback requests to start when server actually starts. - std::list callback_reqs_to_start_; - - // For registering experimental callback generic service; remove when that - // method longer experimental - experimental_registration_type experimental_registration_{this}; - - // Server status - grpc::internal::Mutex mu_; - bool started_; - bool shutdown_; - bool shutdown_notified_; // Was notify called on the shutdown_cv_ - - grpc::internal::CondVar shutdown_cv_; - - // It is ok (but not required) to nest callback_reqs_mu_ under mu_ . - // Incrementing callback_reqs_outstanding_ is ok without a lock but it must be - // decremented under the lock in case it is the last request and enables the - // server shutdown. The increment is performance-critical since it happens - // during periods of increasing load; the decrement happens only when memory - // is maxed out, during server shutdown, or (possibly in a future version) - // during decreasing load, so it is less performance-critical. - grpc::internal::Mutex callback_reqs_mu_; - grpc::internal::CondVar callback_reqs_done_cv_; - std::atomic_int callback_reqs_outstanding_{0}; - - std::shared_ptr global_callbacks_; - - std::vector services_; - bool has_async_generic_service_{false}; - bool has_callback_generic_service_{false}; - - // Pointer to the wrapped grpc_server. - grpc_server* server_; - - std::unique_ptr server_initializer_; - - std::unique_ptr health_check_service_; - bool health_check_service_disabled_; - - // When appropriate, use a default callback generic service to handle - // unimplemented methods - std::unique_ptr unimplemented_service_; - - // A special handler for resource exhausted in sync case - std::unique_ptr resource_exhausted_handler_; - - // Handler for callback generic service, if any - std::unique_ptr generic_handler_; - - // callback_cq_ references the callbackable completion queue associated - // with this server (if any). It is set on the first call to CallbackCQ(). - // It is _not owned_ by the server; ownership belongs with its internal - // shutdown callback tag (invoked when the CQ is fully shutdown). - // It is protected by mu_ - CompletionQueue* callback_cq_ = nullptr; -}; +typedef ::grpc_impl::Server Server; } // namespace grpc diff --git a/include/grpcpp/server_builder.h b/include/grpcpp/server_builder.h index 33689561825..d9ec7c42f3d 100644 --- a/include/grpcpp/server_builder.h +++ b/include/grpcpp/server_builder.h @@ -21,12 +21,6 @@ #include -namespace grpc_impl { - -class ServerCredentials; -class ResourceQuota; -} // namespace grpc_impl - namespace grpc { typedef ::grpc_impl::ServerBuilder ServerBuilder; diff --git a/include/grpcpp/server_builder_impl.h b/include/grpcpp/server_builder_impl.h index 25b8091a7df..0de72cc397c 100644 --- a/include/grpcpp/server_builder_impl.h +++ b/include/grpcpp/server_builder_impl.h @@ -31,31 +31,54 @@ #include #include #include +#include #include struct grpc_resource_quota; namespace grpc_impl { +class CompletionQueue; class ResourceQuota; +class Server; +class ServerCompletionQueue; class ServerCredentials; } // namespace grpc_impl + namespace grpc { class AsyncGenericService; -class CompletionQueue; -class Server; -class ServerCompletionQueue; class Service; - namespace testing { class ServerBuilderPluginTest; } // namespace testing +namespace internal { +class ExternalConnectionAcceptorImpl; +} // namespace internal + namespace experimental { class CallbackGenericService; -} + +// EXPERIMENTAL API: +// Interface for a grpc server to build transports with connections created out +// of band. +// See ServerBuilder's AddExternalConnectionAcceptor API. +class ExternalConnectionAcceptor { + public: + struct NewConnectionParameters { + int fd = -1; + ByteBuffer read_buffer; // data intended for the grpc server + }; + virtual ~ExternalConnectionAcceptor() {} + // If called before grpc::Server is started or after it is shut down, the new + // connection will be closed. + virtual void HandleNewConnection(NewConnectionParameters* p) = 0; +}; + +} // namespace experimental } // namespace grpc + namespace grpc_impl { /// A builder class for the creation and startup of \a grpc::Server instances. @@ -133,7 +156,7 @@ class ServerBuilder { /// not polling the completion queue frequently) will have a significantly /// negative performance impact and hence should not be used in production /// use cases. - std::unique_ptr AddCompletionQueue( + std::unique_ptr AddCompletionQueue( bool is_frequently_polled = true); ////////////////////////////////////////////////////////////////////////////// @@ -248,6 +271,18 @@ class ServerBuilder { ServerBuilder& RegisterCallbackGenericService( grpc::experimental::CallbackGenericService* service); + enum class ExternalConnectionType { + FROM_FD = 0 // in the form of a file descriptor + }; + + /// Register an acceptor to handle the externally accepted connection in + /// grpc server. The returned acceptor can be used to pass the connection + /// to grpc server, where a channel will be created with the provided + /// server credentials. + std::unique_ptr + AddExternalConnectionAcceptor(ExternalConnectionType type, + std::shared_ptr creds); + private: ServerBuilder* builder_; }; @@ -327,7 +362,7 @@ class ServerBuilder { SyncServerSettings sync_server_settings_; /// List of completion queues added via \a AddCompletionQueue method. - std::vector cqs_; + std::vector cqs_; std::shared_ptr creds_; std::vector> plugins_; @@ -347,6 +382,8 @@ class ServerBuilder { std::vector< std::unique_ptr> interceptor_creators_; + std::vector> + acceptors_; }; } // namespace grpc_impl diff --git a/include/grpcpp/server_impl.h b/include/grpcpp/server_impl.h index 14b16a06f4e..59a780276e0 100644 --- a/include/grpcpp/server_impl.h +++ b/include/grpcpp/server_impl.h @@ -27,7 +27,9 @@ #include #include +#include #include +#include #include #include #include @@ -41,14 +43,16 @@ struct grpc_server; namespace grpc { - class AsyncGenericService; class ServerContext; +namespace internal { +class ExternalConnectionAcceptorImpl; +} // namespace internal + } // namespace grpc namespace grpc_impl { - class HealthCheckServiceInterface; class ServerInitializer; @@ -99,12 +103,12 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen { grpc_server* c_server(); /// Returns the health check service. - grpc_impl::HealthCheckServiceInterface* GetHealthCheckService() const { + grpc::HealthCheckServiceInterface* GetHealthCheckService() const { return health_check_service_.get(); } /// Establish a channel for in-process communication - std::shared_ptr InProcessChannel( + std::shared_ptr<::grpc::Channel> InProcessChannel( const grpc::ChannelArguments& args); /// NOTE: class experimental_type is not part of the public API of this class. @@ -116,7 +120,7 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen { /// Establish a channel for in-process communication with client /// interceptors - std::shared_ptr InProcessChannelWithInterceptors( + std::shared_ptr<::grpc::Channel> InProcessChannelWithInterceptors( const grpc::ChannelArguments& args, std::vector> @@ -183,6 +187,9 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen { std::shared_ptr>> sync_server_cqs, int min_pollers, int max_pollers, int sync_cq_timeout_msec, + std::vector< + std::shared_ptr> + acceptors, grpc_resource_quota* server_rq = nullptr, std::vector> @@ -199,6 +206,18 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen { grpc_server* server() override { return server_; } + protected: + /// NOTE: This method is not part of the public API for this class. + void set_health_check_service( + std::unique_ptr service) { + health_check_service_ = std::move(service); + } + + /// NOTE: This method is not part of the public API for this class. + bool health_check_service_disabled() const { + return health_check_service_disabled_; + } + private: std::vector< std::unique_ptr>* @@ -268,6 +287,9 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen { grpc_impl::ServerInitializer* initializer(); + std::vector> + acceptors_; + // A vector of interceptor factory objects. // This should be destroyed after health_check_service_ and this requirement // is satisfied by declaring interceptor_creators_ before @@ -333,7 +355,7 @@ class Server : public grpc::ServerInterface, private grpc::GrpcLibraryCodegen { std::unique_ptr server_initializer_; - std::unique_ptr health_check_service_; + std::unique_ptr health_check_service_; bool health_check_service_disabled_; // When appropriate, use a default callback generic service to handle diff --git a/include/grpcpp/support/channel_arguments.h b/include/grpcpp/support/channel_arguments.h index 48ae4246462..593aaec76a7 100644 --- a/include/grpcpp/support/channel_arguments.h +++ b/include/grpcpp/support/channel_arguments.h @@ -19,132 +19,17 @@ #ifndef GRPCPP_SUPPORT_CHANNEL_ARGUMENTS_H #define GRPCPP_SUPPORT_CHANNEL_ARGUMENTS_H -#include -#include - -#include -#include -#include +#include namespace grpc_impl { +class SecureChannelCredentials; class ResourceQuota; -} +} // namespace grpc_impl namespace grpc { -namespace testing { -class ChannelArgumentsTest; -} // namespace testing - -/// Options for channel creation. The user can use generic setters to pass -/// key value pairs down to C channel creation code. For gRPC related options, -/// concrete setters are provided. -class ChannelArguments { - public: - ChannelArguments(); - ~ChannelArguments(); - - ChannelArguments(const ChannelArguments& other); - ChannelArguments& operator=(ChannelArguments other) { - Swap(other); - return *this; - } - - void Swap(ChannelArguments& other); - - /// Dump arguments in this instance to \a channel_args. Does not take - /// ownership of \a channel_args. - /// - /// Note that the underlying arguments are shared. Changes made to either \a - /// channel_args or this instance would be reflected on both. - void SetChannelArgs(grpc_channel_args* channel_args) const; - - // gRPC specific channel argument setters - /// Set target name override for SSL host name checking. This option is for - /// testing only and should never be used in production. - void SetSslTargetNameOverride(const grpc::string& name); - // TODO(yangg) add flow control options - /// Set the compression algorithm for the channel. - void SetCompressionAlgorithm(grpc_compression_algorithm algorithm); - - /// Set the grpclb fallback timeout (in ms) for the channel. If this amount - /// of time has passed but we have not gotten any non-empty \a serverlist from - /// the balancer, we will fall back to use the backend address(es) returned by - /// the resolver. - void SetGrpclbFallbackTimeout(int fallback_timeout); - - /// For client channel's, the socket mutator operates on - /// "channel" sockets. For server's, the socket mutator operates - /// only on "listen" sockets. - /// TODO(apolcyn): allow socket mutators to also operate - /// on server "channel" sockets, and adjust the socket mutator - /// object to be more speficic about which type of socket - /// it should operate on. - void SetSocketMutator(grpc_socket_mutator* mutator); - - /// Set the string to prepend to the user agent. - void SetUserAgentPrefix(const grpc::string& user_agent_prefix); - - /// Set the buffer pool to be attached to the constructed channel. - void SetResourceQuota(const ::grpc_impl::ResourceQuota& resource_quota); - - /// Set the max receive and send message sizes. - void SetMaxReceiveMessageSize(int size); - void SetMaxSendMessageSize(int size); - - /// Set LB policy name. - /// Note that if the name resolver returns only balancer addresses, the - /// grpclb LB policy will be used, regardless of what is specified here. - void SetLoadBalancingPolicyName(const grpc::string& lb_policy_name); - - /// Set service config in JSON form. - /// Primarily meant for use in unit tests. - void SetServiceConfigJSON(const grpc::string& service_config_json); - - // Generic channel argument setters. Only for advanced use cases. - /// Set an integer argument \a value under \a key. - void SetInt(const grpc::string& key, int value); - - // Generic channel argument setter. Only for advanced use cases. - /// Set a pointer argument \a value under \a key. Owership is not transferred. - void SetPointer(const grpc::string& key, void* value); - - void SetPointerWithVtable(const grpc::string& key, void* value, - const grpc_arg_pointer_vtable* vtable); - - /// Set a textual argument \a value under \a key. - void SetString(const grpc::string& key, const grpc::string& value); - - /// Return (by value) a C \a grpc_channel_args structure which points to - /// arguments owned by this \a ChannelArguments instance - grpc_channel_args c_channel_args() const { - grpc_channel_args out; - out.num_args = args_.size(); - out.args = args_.empty() ? NULL : const_cast(&args_[0]); - return out; - } - - private: - friend class SecureChannelCredentials; - friend class testing::ChannelArgumentsTest; - - /// Default pointer argument operations. - struct PointerVtableMembers { - static void* Copy(void* in) { return in; } - static void Destroy(void* in) {} - static int Compare(void* a, void* b) { - if (a < b) return -1; - if (a > b) return 1; - return 0; - } - }; - - // Returns empty string when it is not set. - grpc::string GetSslTargetNameOverride() const; - std::vector args_; - std::list strings_; -}; +typedef ::grpc_impl::ChannelArguments ChannelArguments; } // namespace grpc diff --git a/include/grpcpp/support/channel_arguments_impl.h b/include/grpcpp/support/channel_arguments_impl.h new file mode 100644 index 00000000000..ac3b6c4a7e2 --- /dev/null +++ b/include/grpcpp/support/channel_arguments_impl.h @@ -0,0 +1,152 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * 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 GRPCPP_SUPPORT_CHANNEL_ARGUMENTS_IMPL_H +#define GRPCPP_SUPPORT_CHANNEL_ARGUMENTS_IMPL_H + +#include +#include + +#include +#include +#include +#include + +namespace grpc { +namespace testing { +class ChannelArgumentsTest; +} // namespace testing +} // namespace grpc + +namespace grpc_impl { + +class SecureChannelCredentials; + +/// Options for channel creation. The user can use generic setters to pass +/// key value pairs down to C channel creation code. For gRPC related options, +/// concrete setters are provided. +class ChannelArguments { + public: + ChannelArguments(); + ~ChannelArguments(); + + ChannelArguments(const ChannelArguments& other); + ChannelArguments& operator=(ChannelArguments other) { + Swap(other); + return *this; + } + + void Swap(ChannelArguments& other); + + /// Dump arguments in this instance to \a channel_args. Does not take + /// ownership of \a channel_args. + /// + /// Note that the underlying arguments are shared. Changes made to either \a + /// channel_args or this instance would be reflected on both. + void SetChannelArgs(grpc_channel_args* channel_args) const; + + // gRPC specific channel argument setters + /// Set target name override for SSL host name checking. This option should + /// be used with caution in production. + void SetSslTargetNameOverride(const grpc::string& name); + // TODO(yangg) add flow control options + /// Set the compression algorithm for the channel. + void SetCompressionAlgorithm(grpc_compression_algorithm algorithm); + + /// Set the grpclb fallback timeout (in ms) for the channel. If this amount + /// of time has passed but we have not gotten any non-empty \a serverlist from + /// the balancer, we will fall back to use the backend address(es) returned by + /// the resolver. + void SetGrpclbFallbackTimeout(int fallback_timeout); + + /// For client channel's, the socket mutator operates on + /// "channel" sockets. For server's, the socket mutator operates + /// only on "listen" sockets. + /// TODO(apolcyn): allow socket mutators to also operate + /// on server "channel" sockets, and adjust the socket mutator + /// object to be more speficic about which type of socket + /// it should operate on. + void SetSocketMutator(grpc_socket_mutator* mutator); + + /// Set the string to prepend to the user agent. + void SetUserAgentPrefix(const grpc::string& user_agent_prefix); + + /// Set the buffer pool to be attached to the constructed channel. + void SetResourceQuota(const grpc::ResourceQuota& resource_quota); + + /// Set the max receive and send message sizes. + void SetMaxReceiveMessageSize(int size); + void SetMaxSendMessageSize(int size); + + /// Set LB policy name. + /// Note that if the name resolver returns only balancer addresses, the + /// grpclb LB policy will be used, regardless of what is specified here. + void SetLoadBalancingPolicyName(const grpc::string& lb_policy_name); + + /// Set service config in JSON form. + /// Primarily meant for use in unit tests. + void SetServiceConfigJSON(const grpc::string& service_config_json); + + // Generic channel argument setters. Only for advanced use cases. + /// Set an integer argument \a value under \a key. + void SetInt(const grpc::string& key, int value); + + // Generic channel argument setter. Only for advanced use cases. + /// Set a pointer argument \a value under \a key. Owership is not transferred. + void SetPointer(const grpc::string& key, void* value); + + void SetPointerWithVtable(const grpc::string& key, void* value, + const grpc_arg_pointer_vtable* vtable); + + /// Set a textual argument \a value under \a key. + void SetString(const grpc::string& key, const grpc::string& value); + + /// Return (by value) a C \a grpc_channel_args structure which points to + /// arguments owned by this \a ChannelArguments instance + grpc_channel_args c_channel_args() const { + grpc_channel_args out; + out.num_args = args_.size(); + out.args = args_.empty() ? NULL : const_cast(&args_[0]); + return out; + } + + private: + friend class grpc_impl::SecureChannelCredentials; + friend class grpc::testing::ChannelArgumentsTest; + + /// Default pointer argument operations. + struct PointerVtableMembers { + static void* Copy(void* in) { return in; } + static void Destroy(void* in) {} + static int Compare(void* a, void* b) { + if (a < b) return -1; + if (a > b) return 1; + return 0; + } + }; + + // Returns empty string when it is not set. + grpc::string GetSslTargetNameOverride() const; + + std::vector args_; + std::list strings_; +}; + +} // namespace grpc_impl + +#endif // GRPCPP_SUPPORT_CHANNEL_ARGUMENTS_IMPL_H diff --git a/package.xml b/package.xml index c3f4e17dd12..eca74c8f167 100644 --- a/package.xml +++ b/package.xml @@ -13,8 +13,8 @@ 2018-01-19 - 1.21.0dev - 1.21.0dev + 1.22.0dev + 1.22.0dev beta @@ -104,8 +104,13 @@ + + + + + @@ -114,7 +119,6 @@ - @@ -147,7 +151,9 @@ + + @@ -352,12 +358,15 @@ + + + @@ -424,6 +433,7 @@ + @@ -468,6 +478,7 @@ + @@ -500,12 +511,15 @@ + + + @@ -526,6 +540,7 @@ + @@ -554,6 +569,7 @@ + @@ -787,12 +803,15 @@ + + + diff --git a/src/android/test/interop/app/src/main/cpp/grpc-interop.cc b/src/android/test/interop/app/src/main/cpp/grpc-interop.cc index 07834250d22..b5075529be2 100644 --- a/src/android/test/interop/app/src/main/cpp/grpc-interop.cc +++ b/src/android/test/interop/app/src/main/cpp/grpc-interop.cc @@ -18,8 +18,8 @@ #include #include -#include +#include "src/core/lib/security/security_connector/ssl_utils.h" #include "test/cpp/interop/interop_client.h" extern "C" JNIEXPORT void JNICALL @@ -28,7 +28,7 @@ Java_io_grpc_interop_cpp_InteropActivity_configureSslRoots(JNIEnv* env, jstring path_raw) { const char* path = env->GetStringUTFChars(path_raw, (jboolean*)0); - gpr_setenv("GRPC_DEFAULT_SSL_ROOTS_FILE_PATH", path); + GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, path); } std::shared_ptr GetClient(const char* host, @@ -45,7 +45,7 @@ std::shared_ptr GetClient(const char* host, credentials = grpc::InsecureChannelCredentials(); } - grpc::testing::ChannelCreationFunc channel_creation_func = + grpc::testing::ChannelCreationFunc channel_creation_func = std::bind(grpc::CreateChannel, host_port, credentials); return std::shared_ptr( new grpc::testing::InteropClient(channel_creation_func, true, false)); diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc index ecec3206577..bcc849035c6 100644 --- a/src/compiler/cpp_generator.cc +++ b/src/compiler/cpp_generator.cc @@ -154,14 +154,15 @@ grpc::string GetHeaderIncludes(grpc_generator::File* file, PrintIncludes(printer.get(), headers, params.use_system_headers, params.grpc_search_path); printer->Print(vars, "\n"); + printer->Print(vars, "namespace grpc_impl {\n"); + printer->Print(vars, "class CompletionQueue;\n"); + printer->Print(vars, "class ServerCompletionQueue;\n"); + printer->Print(vars, "} // namespace grpc_impl\n\n"); printer->Print(vars, "namespace grpc {\n"); printer->Print(vars, "namespace experimental {\n"); printer->Print(vars, "template \n"); printer->Print(vars, "class MessageAllocator;\n"); printer->Print(vars, "} // namespace experimental\n"); - printer->Print(vars, "class CompletionQueue;\n"); - printer->Print(vars, "class Channel;\n"); - printer->Print(vars, "class ServerCompletionQueue;\n"); printer->Print(vars, "class ServerContext;\n"); printer->Print(vars, "} // namespace grpc\n\n"); diff --git a/src/compiler/cpp_plugin.cc b/src/compiler/cpp_plugin.cc index 3c09b6feb24..2de2745445f 100644 --- a/src/compiler/cpp_plugin.cc +++ b/src/compiler/cpp_plugin.cc @@ -18,137 +18,7 @@ // Generates cpp gRPC service interface out of Protobuf IDL. // - -#include -#include - -#include "src/compiler/config.h" - -#include "src/compiler/cpp_generator.h" -#include "src/compiler/generator_helpers.h" -#include "src/compiler/protobuf_plugin.h" - -class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { - public: - CppGrpcGenerator() {} - virtual ~CppGrpcGenerator() {} - - virtual bool Generate(const grpc::protobuf::FileDescriptor* file, - const grpc::string& parameter, - grpc::protobuf::compiler::GeneratorContext* context, - grpc::string* error) const { - if (file->options().cc_generic_services()) { - *error = - "cpp grpc proto compiler plugin does not work with generic " - "services. To generate cpp grpc APIs, please set \"" - "cc_generic_service = false\"."; - return false; - } - - grpc_cpp_generator::Parameters generator_parameters; - generator_parameters.use_system_headers = true; - generator_parameters.generate_mock_code = false; - generator_parameters.include_import_headers = false; - - ProtoBufFile pbfile(file); - - if (!parameter.empty()) { - std::vector parameters_list = - grpc_generator::tokenize(parameter, ","); - for (auto parameter_string = parameters_list.begin(); - parameter_string != parameters_list.end(); parameter_string++) { - std::vector param = - grpc_generator::tokenize(*parameter_string, "="); - if (param[0] == "services_namespace") { - generator_parameters.services_namespace = param[1]; - } else if (param[0] == "use_system_headers") { - if (param[1] == "true") { - generator_parameters.use_system_headers = true; - } else if (param[1] == "false") { - generator_parameters.use_system_headers = false; - } else { - *error = grpc::string("Invalid parameter: ") + *parameter_string; - return false; - } - } else if (param[0] == "grpc_search_path") { - generator_parameters.grpc_search_path = param[1]; - } else if (param[0] == "generate_mock_code") { - if (param[1] == "true") { - generator_parameters.generate_mock_code = true; - } else if (param[1] != "false") { - *error = grpc::string("Invalid parameter: ") + *parameter_string; - return false; - } - } else if (param[0] == "gmock_search_path") { - generator_parameters.gmock_search_path = param[1]; - } else if (param[0] == "additional_header_includes") { - generator_parameters.additional_header_includes = - grpc_generator::tokenize(param[1], ":"); - } else if (param[0] == "message_header_extension") { - generator_parameters.message_header_extension = param[1]; - } else if (param[0] == "include_import_headers") { - if (param[1] == "true") { - generator_parameters.include_import_headers = true; - } else if (param[1] != "false") { - *error = grpc::string("Invalid parameter: ") + *parameter_string; - return false; - } - } else { - *error = grpc::string("Unknown parameter: ") + *parameter_string; - return false; - } - } - } - - grpc::string file_name = grpc_generator::StripProto(file->name()); - - grpc::string header_code = - grpc_cpp_generator::GetHeaderPrologue(&pbfile, generator_parameters) + - grpc_cpp_generator::GetHeaderIncludes(&pbfile, generator_parameters) + - grpc_cpp_generator::GetHeaderServices(&pbfile, generator_parameters) + - grpc_cpp_generator::GetHeaderEpilogue(&pbfile, generator_parameters); - std::unique_ptr header_output( - context->Open(file_name + ".grpc.pb.h")); - grpc::protobuf::io::CodedOutputStream header_coded_out(header_output.get()); - header_coded_out.WriteRaw(header_code.data(), header_code.size()); - - grpc::string source_code = - grpc_cpp_generator::GetSourcePrologue(&pbfile, generator_parameters) + - grpc_cpp_generator::GetSourceIncludes(&pbfile, generator_parameters) + - grpc_cpp_generator::GetSourceServices(&pbfile, generator_parameters) + - grpc_cpp_generator::GetSourceEpilogue(&pbfile, generator_parameters); - std::unique_ptr source_output( - context->Open(file_name + ".grpc.pb.cc")); - grpc::protobuf::io::CodedOutputStream source_coded_out(source_output.get()); - source_coded_out.WriteRaw(source_code.data(), source_code.size()); - - if (!generator_parameters.generate_mock_code) { - return true; - } - grpc::string mock_code = - grpc_cpp_generator::GetMockPrologue(&pbfile, generator_parameters) + - grpc_cpp_generator::GetMockIncludes(&pbfile, generator_parameters) + - grpc_cpp_generator::GetMockServices(&pbfile, generator_parameters) + - grpc_cpp_generator::GetMockEpilogue(&pbfile, generator_parameters); - std::unique_ptr mock_output( - context->Open(file_name + "_mock.grpc.pb.h")); - grpc::protobuf::io::CodedOutputStream mock_coded_out(mock_output.get()); - mock_coded_out.WriteRaw(mock_code.data(), mock_code.size()); - - return true; - } - - private: - // Insert the given code into the given file at the given insertion point. - void Insert(grpc::protobuf::compiler::GeneratorContext* context, - const grpc::string& filename, const grpc::string& insertion_point, - const grpc::string& code) const { - std::unique_ptr output( - context->OpenForInsert(filename, insertion_point)); - grpc::protobuf::io::CodedOutputStream coded_out(output.get()); - coded_out.WriteRaw(code.data(), code.size()); - } -}; +#include "src/compiler/cpp_plugin.h" int main(int argc, char* argv[]) { CppGrpcGenerator generator; diff --git a/src/compiler/cpp_plugin.h b/src/compiler/cpp_plugin.h new file mode 100644 index 00000000000..1cdf0b3c196 --- /dev/null +++ b/src/compiler/cpp_plugin.h @@ -0,0 +1,154 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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_INTERNAL_COMPILER_CPP_PLUGIN_H +#define GRPC_INTERNAL_COMPILER_CPP_PLUGIN_H + +#include +#include + +#include "src/compiler/config.h" + +#include "src/compiler/cpp_generator.h" +#include "src/compiler/generator_helpers.h" +#include "src/compiler/protobuf_plugin.h" + +// Cpp Generator for Protobug IDL +class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { + public: + CppGrpcGenerator() {} + virtual ~CppGrpcGenerator() {} + + virtual bool Generate(const grpc::protobuf::FileDescriptor* file, + const grpc::string& parameter, + grpc::protobuf::compiler::GeneratorContext* context, + grpc::string* error) const { + if (file->options().cc_generic_services()) { + *error = + "cpp grpc proto compiler plugin does not work with generic " + "services. To generate cpp grpc APIs, please set \"" + "cc_generic_service = false\"."; + return false; + } + + grpc_cpp_generator::Parameters generator_parameters; + generator_parameters.use_system_headers = true; + generator_parameters.generate_mock_code = false; + generator_parameters.include_import_headers = false; + + ProtoBufFile pbfile(file); + + if (!parameter.empty()) { + std::vector parameters_list = + grpc_generator::tokenize(parameter, ","); + for (auto parameter_string = parameters_list.begin(); + parameter_string != parameters_list.end(); parameter_string++) { + std::vector param = + grpc_generator::tokenize(*parameter_string, "="); + if (param[0] == "services_namespace") { + generator_parameters.services_namespace = param[1]; + } else if (param[0] == "use_system_headers") { + if (param[1] == "true") { + generator_parameters.use_system_headers = true; + } else if (param[1] == "false") { + generator_parameters.use_system_headers = false; + } else { + *error = grpc::string("Invalid parameter: ") + *parameter_string; + return false; + } + } else if (param[0] == "grpc_search_path") { + generator_parameters.grpc_search_path = param[1]; + } else if (param[0] == "generate_mock_code") { + if (param[1] == "true") { + generator_parameters.generate_mock_code = true; + } else if (param[1] != "false") { + *error = grpc::string("Invalid parameter: ") + *parameter_string; + return false; + } + } else if (param[0] == "gmock_search_path") { + generator_parameters.gmock_search_path = param[1]; + } else if (param[0] == "additional_header_includes") { + generator_parameters.additional_header_includes = + grpc_generator::tokenize(param[1], ":"); + } else if (param[0] == "message_header_extension") { + generator_parameters.message_header_extension = param[1]; + } else if (param[0] == "include_import_headers") { + if (param[1] == "true") { + generator_parameters.include_import_headers = true; + } else if (param[1] != "false") { + *error = grpc::string("Invalid parameter: ") + *parameter_string; + return false; + } + } else { + *error = grpc::string("Unknown parameter: ") + *parameter_string; + return false; + } + } + } + + grpc::string file_name = grpc_generator::StripProto(file->name()); + + grpc::string header_code = + grpc_cpp_generator::GetHeaderPrologue(&pbfile, generator_parameters) + + grpc_cpp_generator::GetHeaderIncludes(&pbfile, generator_parameters) + + grpc_cpp_generator::GetHeaderServices(&pbfile, generator_parameters) + + grpc_cpp_generator::GetHeaderEpilogue(&pbfile, generator_parameters); + std::unique_ptr header_output( + context->Open(file_name + ".grpc.pb.h")); + grpc::protobuf::io::CodedOutputStream header_coded_out(header_output.get()); + header_coded_out.WriteRaw(header_code.data(), header_code.size()); + + grpc::string source_code = + grpc_cpp_generator::GetSourcePrologue(&pbfile, generator_parameters) + + grpc_cpp_generator::GetSourceIncludes(&pbfile, generator_parameters) + + grpc_cpp_generator::GetSourceServices(&pbfile, generator_parameters) + + grpc_cpp_generator::GetSourceEpilogue(&pbfile, generator_parameters); + std::unique_ptr source_output( + context->Open(file_name + ".grpc.pb.cc")); + grpc::protobuf::io::CodedOutputStream source_coded_out(source_output.get()); + source_coded_out.WriteRaw(source_code.data(), source_code.size()); + + if (!generator_parameters.generate_mock_code) { + return true; + } + grpc::string mock_code = + grpc_cpp_generator::GetMockPrologue(&pbfile, generator_parameters) + + grpc_cpp_generator::GetMockIncludes(&pbfile, generator_parameters) + + grpc_cpp_generator::GetMockServices(&pbfile, generator_parameters) + + grpc_cpp_generator::GetMockEpilogue(&pbfile, generator_parameters); + std::unique_ptr mock_output( + context->Open(file_name + "_mock.grpc.pb.h")); + grpc::protobuf::io::CodedOutputStream mock_coded_out(mock_output.get()); + mock_coded_out.WriteRaw(mock_code.data(), mock_code.size()); + + return true; + } + + private: + // Insert the given code into the given file at the given insertion point. + void Insert(grpc::protobuf::compiler::GeneratorContext* context, + const grpc::string& filename, const grpc::string& insertion_point, + const grpc::string& code) const { + std::unique_ptr output( + context->OpenForInsert(filename, insertion_point)); + grpc::protobuf::io::CodedOutputStream coded_out(output.get()); + coded_out.WriteRaw(code.data(), code.size()); + } +}; + +#endif // GRPC_INTERNAL_COMPILER_CPP_PLUGIN_H diff --git a/src/core/ext/filters/client_channel/backup_poller.cc b/src/core/ext/filters/client_channel/backup_poller.cc index 3e2faa57bcf..dd761694414 100644 --- a/src/core/ext/filters/client_channel/backup_poller.cc +++ b/src/core/ext/filters/client_channel/backup_poller.cc @@ -25,8 +25,8 @@ #include #include #include "src/core/ext/filters/client_channel/client_channel.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/gprpp/global_config.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/iomgr/timer.h" @@ -56,21 +56,27 @@ static backup_poller* g_poller = nullptr; // guarded by g_poller_mu // treated as const. static int g_poll_interval_ms = DEFAULT_POLL_INTERVAL_MS; +GPR_GLOBAL_CONFIG_DEFINE_INT32( + grpc_client_channel_backup_poll_interval_ms, DEFAULT_POLL_INTERVAL_MS, + "Declares the interval in ms between two backup polls on client channels. " + "These polls are run in the timer thread so that gRPC can process " + "connection failures while there is no active polling thread. " + "They help reconnect disconnected client channels (mostly due to " + "idleness), so that the next RPC on this channel won't fail. Set to 0 to " + "turn off the backup polls."); + static void init_globals() { gpr_mu_init(&g_poller_mu); - char* env = gpr_getenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS"); - if (env != nullptr) { - int poll_interval_ms = gpr_parse_nonnegative_int(env); - if (poll_interval_ms == -1) { - gpr_log(GPR_ERROR, - "Invalid GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS: %s, " - "default value %d will be used.", - env, g_poll_interval_ms); - } else { - g_poll_interval_ms = poll_interval_ms; - } + int32_t poll_interval_ms = + GPR_GLOBAL_CONFIG_GET(grpc_client_channel_backup_poll_interval_ms); + if (poll_interval_ms < 0) { + gpr_log(GPR_ERROR, + "Invalid GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS: %d, " + "default value %d will be used.", + poll_interval_ms, g_poll_interval_ms); + } else { + g_poll_interval_ms = poll_interval_ms; } - gpr_free(env); } static void backup_poller_shutdown_unref(backup_poller* p) { diff --git a/src/core/ext/filters/client_channel/backup_poller.h b/src/core/ext/filters/client_channel/backup_poller.h index 8f132f968ce..e1bf4f88b2a 100644 --- a/src/core/ext/filters/client_channel/backup_poller.h +++ b/src/core/ext/filters/client_channel/backup_poller.h @@ -23,6 +23,9 @@ #include #include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/gprpp/global_config.h" + +GPR_GLOBAL_CONFIG_DECLARE_INT32(grpc_client_channel_backup_poll_interval_ms); /* Start polling \a interested_parties periodically in the timer thread */ void grpc_client_channel_start_backup_polling( diff --git a/src/core/ext/filters/client_channel/channel_connectivity.cc b/src/core/ext/filters/client_channel/channel_connectivity.cc index 9f970f6affa..232183d61ff 100644 --- a/src/core/ext/filters/client_channel/channel_connectivity.cc +++ b/src/core/ext/filters/client_channel/channel_connectivity.cc @@ -125,7 +125,7 @@ static void partly_done(state_watcher* w, bool due_to_completion, gpr_mu_lock(&w->mu); if (due_to_completion) { - if (grpc_trace_operation_failures.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures)) { GRPC_LOG_IF_ERROR("watch_completion_error", GRPC_ERROR_REF(error)); } GRPC_ERROR_UNREF(error); diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index 412ac1662b8..c0586d459b2 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -66,9 +66,7 @@ #include "src/core/lib/transport/static_metadata.h" #include "src/core/lib/transport/status_metadata.h" -using grpc_core::internal::ClientChannelMethodParams; -using grpc_core::internal::ClientChannelMethodParamsTable; -using grpc_core::internal::ProcessedResolverResult; +using grpc_core::internal::ClientChannelMethodParsedConfig; using grpc_core::internal::ServerRetryThrottleData; // @@ -157,10 +155,8 @@ class ChannelData { RefCountedPtr retry_throttle_data() const { return retry_throttle_data_; } - RefCountedPtr GetMethodParams( - const grpc_slice& path) { - if (method_params_table_ == nullptr) return nullptr; - return ServiceConfig::MethodConfigTableLookup(*method_params_table_, path); + RefCountedPtr service_config() const { + return service_config_; } grpc_connectivity_state CheckConnectivityState(bool try_to_connect); @@ -227,7 +223,8 @@ class ChannelData { static bool ProcessResolverResultLocked( void* arg, Resolver::Result* result, const char** lb_policy_name, - RefCountedPtr* lb_policy_config); + RefCountedPtr* lb_policy_config, + grpc_error** service_config_error); grpc_error* DoPingLocked(grpc_transport_op* op); @@ -235,6 +232,12 @@ class ChannelData { static void TryToConnectLocked(void* arg, grpc_error* error_ignored); + void ProcessLbPolicy( + const Resolver::Result& resolver_result, + const internal::ClientChannelGlobalParsedConfig* parsed_service_config, + UniquePtr* lb_policy_name, + RefCountedPtr* lb_policy_config); + // // Fields set at construction and never modified. // @@ -243,6 +246,8 @@ class ChannelData { const size_t per_rpc_retry_buffer_size_; grpc_channel_stack* owning_stack_; ClientChannelFactory* client_channel_factory_; + UniquePtr server_name_; + RefCountedPtr default_service_config_; // Initialized shortly after construction. channelz::ClientChannelNode* channelz_node_ = nullptr; @@ -255,7 +260,7 @@ class ChannelData { // Data from service config. bool received_service_config_data_ = false; RefCountedPtr retry_throttle_data_; - RefCountedPtr method_params_table_; + RefCountedPtr service_config_; // // Fields used in the control plane. Guarded by combiner. @@ -266,6 +271,8 @@ class ChannelData { OrphanablePtr resolving_lb_policy_; grpc_connectivity_state_tracker state_tracker_; ExternalConnectivityWatcher::WatcherList external_connectivity_watcher_list_; + RefCountedPtr saved_service_config_; + bool received_first_resolver_result_ = false; // // Fields accessed from both data plane and control plane combiners. @@ -615,13 +622,14 @@ class CallData { grpc_slice path_; // Request path. gpr_timespec call_start_time_; grpc_millis deadline_; - gpr_arena* arena_; + Arena* arena_; grpc_call_stack* owning_call_; - grpc_call_combiner* call_combiner_; + CallCombiner* call_combiner_; grpc_call_context_element* call_context_; RefCountedPtr retry_throttle_data_; - RefCountedPtr method_params_; + ServiceConfig::CallData service_config_call_data_; + const ClientChannelMethodParsedConfig* method_params_ = nullptr; RefCountedPtr subchannel_call_; @@ -764,11 +772,12 @@ class ChannelData::ServiceConfigSetter { public: ServiceConfigSetter( ChannelData* chand, - RefCountedPtr retry_throttle_data, - RefCountedPtr method_params_table) + Optional + retry_throttle_data, + RefCountedPtr service_config) : chand_(chand), - retry_throttle_data_(std::move(retry_throttle_data)), - method_params_table_(std::move(method_params_table)) { + retry_throttle_data_(retry_throttle_data), + service_config_(std::move(service_config)) { GRPC_CHANNEL_STACK_REF(chand->owning_stack_, "ServiceConfigSetter"); GRPC_CLOSURE_INIT(&closure_, SetServiceConfigData, this, grpc_combiner_scheduler(chand->data_plane_combiner_)); @@ -781,8 +790,14 @@ class ChannelData::ServiceConfigSetter { ChannelData* chand = self->chand_; // Update channel state. chand->received_service_config_data_ = true; - chand->retry_throttle_data_ = std::move(self->retry_throttle_data_); - chand->method_params_table_ = std::move(self->method_params_table_); + if (self->retry_throttle_data_.has_value()) { + chand->retry_throttle_data_ = + internal::ServerRetryThrottleMap::GetDataForServer( + chand->server_name_.get(), + self->retry_throttle_data_.value().max_milli_tokens, + self->retry_throttle_data_.value().milli_token_ratio); + } + chand->service_config_ = std::move(self->service_config_); // Apply service config to queued picks. for (QueuedPick* pick = chand->queued_picks_; pick != nullptr; pick = pick->next) { @@ -796,8 +811,9 @@ class ChannelData::ServiceConfigSetter { } ChannelData* chand_; - RefCountedPtr retry_throttle_data_; - RefCountedPtr method_params_table_; + Optional + retry_throttle_data_; + RefCountedPtr service_config_; grpc_closure closure_; }; @@ -954,7 +970,7 @@ class ChannelData::ClientChannelControlHelper UniquePtr picker) override { grpc_error* disconnect_error = chand_->disconnect_error_.Load(MemoryOrder::ACQUIRE); - if (grpc_client_channel_routing_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { const char* extra = disconnect_error == GRPC_ERROR_NONE ? "" : " (ignoring -- channel shutting down)"; @@ -1050,6 +1066,23 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error) "filter"); return; } + // Get default service config + const char* service_config_json = grpc_channel_arg_get_string( + grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG)); + if (service_config_json != nullptr) { + *error = GRPC_ERROR_NONE; + default_service_config_ = ServiceConfig::Create(service_config_json, error); + if (*error != GRPC_ERROR_NONE) { + default_service_config_.reset(); + return; + } + } + grpc_uri* uri = grpc_uri_parse(server_uri, true); + if (uri != nullptr && uri->path[0] != '\0') { + server_name_.reset( + gpr_strdup(uri->path[0] == '/' ? uri->path + 1 : uri->path)); + } + grpc_uri_destroy(uri); char* proxy_name = nullptr; grpc_channel_args* new_args = nullptr; grpc_proxy_mappers_map_name(server_uri, args->channel_args, &proxy_name, @@ -1083,7 +1116,7 @@ ChannelData::ChannelData(grpc_channel_element_args* args, grpc_error** error) } else { grpc_pollset_set_add_pollset_set(resolving_lb_policy_->interested_parties(), interested_parties_); - if (grpc_client_channel_routing_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { gpr_log(GPR_INFO, "chand=%p: created resolving_lb_policy=%p", this, resolving_lb_policy_.get()); } @@ -1106,38 +1139,172 @@ ChannelData::~ChannelData() { gpr_mu_destroy(&info_mu_); } +void ChannelData::ProcessLbPolicy( + const Resolver::Result& resolver_result, + const internal::ClientChannelGlobalParsedConfig* parsed_service_config, + UniquePtr* lb_policy_name, + RefCountedPtr* lb_policy_config) { + // Prefer the LB policy name found in the service config. + if (parsed_service_config != nullptr && + parsed_service_config->parsed_lb_config() != nullptr) { + lb_policy_name->reset( + gpr_strdup(parsed_service_config->parsed_lb_config()->name())); + *lb_policy_config = parsed_service_config->parsed_lb_config(); + return; + } + const char* local_policy_name = nullptr; + if (parsed_service_config != nullptr && + parsed_service_config->parsed_deprecated_lb_policy() != nullptr) { + local_policy_name = parsed_service_config->parsed_deprecated_lb_policy(); + } else { + const grpc_arg* channel_arg = + grpc_channel_args_find(resolver_result.args, GRPC_ARG_LB_POLICY_NAME); + local_policy_name = grpc_channel_arg_get_string(channel_arg); + } + // Special case: If at least one balancer address is present, we use + // the grpclb policy, regardless of what the resolver has returned. + bool found_balancer_address = false; + for (size_t i = 0; i < resolver_result.addresses.size(); ++i) { + const ServerAddress& address = resolver_result.addresses[i]; + if (address.IsBalancer()) { + found_balancer_address = true; + break; + } + } + if (found_balancer_address) { + if (local_policy_name != nullptr && + strcmp(local_policy_name, "grpclb") != 0) { + gpr_log(GPR_INFO, + "resolver requested LB policy %s but provided at least one " + "balancer address -- forcing use of grpclb LB policy", + local_policy_name); + } + local_policy_name = "grpclb"; + } + // Use pick_first if nothing was specified and we didn't select grpclb + // above. + lb_policy_name->reset(gpr_strdup( + local_policy_name == nullptr ? "pick_first" : local_policy_name)); +} + // Synchronous callback from ResolvingLoadBalancingPolicy to process a // resolver result update. bool ChannelData::ProcessResolverResultLocked( void* arg, Resolver::Result* result, const char** lb_policy_name, - RefCountedPtr* lb_policy_config) { + RefCountedPtr* lb_policy_config, + grpc_error** service_config_error) { ChannelData* chand = static_cast(arg); - ProcessedResolverResult resolver_result(result, chand->enable_retries_); - UniquePtr service_config_json = resolver_result.service_config_json(); - if (grpc_client_channel_routing_trace.enabled()) { - gpr_log(GPR_INFO, "chand=%p: resolver returned service config: \"%s\"", - chand, service_config_json.get()); - } - // Create service config setter to update channel state in the data - // plane combiner. Destroys itself when done. - New(chand, resolver_result.retry_throttle_data(), - resolver_result.method_params_table()); + RefCountedPtr service_config; + // If resolver did not return a service config or returned an invalid service + // config, we need a fallback service config. + if (result->service_config_error != GRPC_ERROR_NONE) { + // If the service config was invalid, then fallback to the saved service + // config. If there is no saved config either, use the default service + // config. + if (chand->saved_service_config_ != nullptr) { + service_config = chand->saved_service_config_; + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { + gpr_log(GPR_INFO, + "chand=%p: resolver returned invalid service config. " + "Continuing to use previous service config.", + chand); + } + } else if (chand->default_service_config_ != nullptr) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { + gpr_log(GPR_INFO, + "chand=%p: resolver returned invalid service config. Using " + "default service config provided by client API.", + chand); + } + service_config = chand->default_service_config_; + } + } else if (result->service_config == nullptr) { + if (chand->default_service_config_ != nullptr) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { + gpr_log(GPR_INFO, + "chand=%p: resolver returned no service config. Using default " + "service config provided by client API.", + chand); + } + service_config = chand->default_service_config_; + } + } else { + service_config = result->service_config; + } + *service_config_error = GRPC_ERROR_REF(result->service_config_error); + if (service_config == nullptr && + result->service_config_error != GRPC_ERROR_NONE) { + return false; + } + // Process service config. + UniquePtr service_config_json; + const internal::ClientChannelGlobalParsedConfig* parsed_service_config = + nullptr; + if (service_config != nullptr) { + parsed_service_config = + static_cast( + service_config->GetGlobalParsedConfig( + internal::ClientChannelServiceConfigParser::ParserIndex())); + } + // TODO(roth): Eliminate this hack as part of hiding health check + // service name from LB policy API. As part of this, change the API + // for this function to pass in result as a const reference. + if (parsed_service_config != nullptr && + parsed_service_config->health_check_service_name() != nullptr) { + grpc_arg new_arg = grpc_channel_arg_string_create( + const_cast("grpc.temp.health_check"), + const_cast(parsed_service_config->health_check_service_name())); + grpc_channel_args* new_args = + grpc_channel_args_copy_and_add(result->args, &new_arg, 1); + grpc_channel_args_destroy(result->args); + result->args = new_args; + } + // Check if the config has changed. + const bool service_config_changed = + ((service_config == nullptr) != + (chand->saved_service_config_ == nullptr)) || + (service_config != nullptr && + strcmp(service_config->service_config_json(), + chand->saved_service_config_->service_config_json()) != 0); + if (service_config_changed) { + service_config_json.reset(gpr_strdup( + service_config != nullptr ? service_config->service_config_json() + : "")); + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { + gpr_log(GPR_INFO, + "chand=%p: resolver returned updated service config: \"%s\"", + chand, service_config_json.get()); + } + chand->saved_service_config_ = std::move(service_config); + } + // We want to set the service config at least once. This should not really be + // needed, but we are doing it as a defensive approach. This can be removed, + // if we feel it is unnecessary. + if (service_config_changed || !chand->received_first_resolver_result_) { + chand->received_first_resolver_result_ = true; + Optional + retry_throttle_data; + if (parsed_service_config != nullptr) { + retry_throttle_data = parsed_service_config->retry_throttling(); + } + // Create service config setter to update channel state in the data + // plane combiner. Destroys itself when done. + New(chand, retry_throttle_data, + chand->saved_service_config_); + } + UniquePtr processed_lb_policy_name; + chand->ProcessLbPolicy(*result, parsed_service_config, + &processed_lb_policy_name, lb_policy_config); // Swap out the data used by GetChannelInfo(). - bool service_config_changed; { MutexLock lock(&chand->info_mu_); - chand->info_lb_policy_name_ = resolver_result.lb_policy_name(); - service_config_changed = - ((service_config_json == nullptr) != - (chand->info_service_config_json_ == nullptr)) || - (service_config_json != nullptr && - strcmp(service_config_json.get(), - chand->info_service_config_json_.get()) != 0); - chand->info_service_config_json_ = std::move(service_config_json); + chand->info_lb_policy_name_ = std::move(processed_lb_policy_name); + if (service_config_json != nullptr) { + chand->info_service_config_json_ = std::move(service_config_json); + } } // Return results. *lb_policy_name = chand->info_lb_policy_name_.get(); - *lb_policy_config = resolver_result.lb_policy_config(); return service_config_changed; } @@ -1383,7 +1550,7 @@ void CallData::StartTransportStreamOpBatch( } // If we've previously been cancelled, immediately fail any new batches. if (GPR_UNLIKELY(calld->cancel_error_ != GRPC_ERROR_NONE)) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: failing batch with error: %s", chand, calld, grpc_error_string(calld->cancel_error_)); } @@ -1402,7 +1569,7 @@ void CallData::StartTransportStreamOpBatch( GRPC_ERROR_UNREF(calld->cancel_error_); calld->cancel_error_ = GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error); - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: recording cancel_error=%s", chand, calld, grpc_error_string(calld->cancel_error_)); } @@ -1430,7 +1597,7 @@ void CallData::StartTransportStreamOpBatch( // the channel combiner, which is more efficient (especially for // streaming calls). if (calld->subchannel_call_ != nullptr) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: starting batch on subchannel_call=%p", chand, calld, calld->subchannel_call_.get()); @@ -1442,7 +1609,7 @@ void CallData::StartTransportStreamOpBatch( // For batches containing a send_initial_metadata op, enter the channel // combiner to start a pick. if (GPR_LIKELY(batch->send_initial_metadata)) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: entering client_channel combiner", chand, calld); } @@ -1453,7 +1620,7 @@ void CallData::StartTransportStreamOpBatch( GRPC_ERROR_NONE); } else { // For all other batches, release the call combiner. - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: saved batch, yielding call combiner", chand, calld); @@ -1483,8 +1650,8 @@ void CallData::MaybeCacheSendOpsForBatch(PendingBatch* pending) { GPR_ASSERT(send_initial_metadata_storage_ == nullptr); grpc_metadata_batch* send_initial_metadata = batch->payload->send_initial_metadata.send_initial_metadata; - send_initial_metadata_storage_ = (grpc_linked_mdelem*)gpr_arena_alloc( - arena_, sizeof(grpc_linked_mdelem) * send_initial_metadata->list.count); + send_initial_metadata_storage_ = (grpc_linked_mdelem*)arena_->Alloc( + sizeof(grpc_linked_mdelem) * send_initial_metadata->list.count); grpc_metadata_batch_copy(send_initial_metadata, &send_initial_metadata_, send_initial_metadata_storage_); send_initial_metadata_flags_ = @@ -1493,10 +1660,8 @@ void CallData::MaybeCacheSendOpsForBatch(PendingBatch* pending) { } // Set up cache for send_message ops. if (batch->send_message) { - ByteStreamCache* cache = static_cast( - gpr_arena_alloc(arena_, sizeof(ByteStreamCache))); - new (cache) - ByteStreamCache(std::move(batch->payload->send_message.send_message)); + ByteStreamCache* cache = arena_->New( + std::move(batch->payload->send_message.send_message)); send_messages_.push_back(cache); } // Save metadata batch for send_trailing_metadata ops. @@ -1505,8 +1670,7 @@ void CallData::MaybeCacheSendOpsForBatch(PendingBatch* pending) { GPR_ASSERT(send_trailing_metadata_storage_ == nullptr); grpc_metadata_batch* send_trailing_metadata = batch->payload->send_trailing_metadata.send_trailing_metadata; - send_trailing_metadata_storage_ = (grpc_linked_mdelem*)gpr_arena_alloc( - arena_, + send_trailing_metadata_storage_ = (grpc_linked_mdelem*)arena_->Alloc( sizeof(grpc_linked_mdelem) * send_trailing_metadata->list.count); grpc_metadata_batch_copy(send_trailing_metadata, &send_trailing_metadata_, send_trailing_metadata_storage_); @@ -1514,7 +1678,7 @@ void CallData::MaybeCacheSendOpsForBatch(PendingBatch* pending) { } void CallData::FreeCachedSendInitialMetadata(ChannelData* chand) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: destroying calld->send_initial_metadata", chand, this); @@ -1523,7 +1687,7 @@ void CallData::FreeCachedSendInitialMetadata(ChannelData* chand) { } void CallData::FreeCachedSendMessage(ChannelData* chand, size_t idx) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: destroying calld->send_messages[%" PRIuPTR "]", chand, this, idx); @@ -1532,7 +1696,7 @@ void CallData::FreeCachedSendMessage(ChannelData* chand, size_t idx) { } void CallData::FreeCachedSendTrailingMetadata(ChannelData* chand) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: destroying calld->send_trailing_metadata", chand, this); @@ -1609,7 +1773,7 @@ void CallData::PendingBatchesAdd(grpc_call_element* elem, grpc_transport_stream_op_batch* batch) { ChannelData* chand = static_cast(elem->channel_data); const size_t idx = GetBatchIndex(batch); - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: adding pending batch at index %" PRIuPTR, chand, this, idx); @@ -1638,7 +1802,7 @@ void CallData::PendingBatchesAdd(grpc_call_element* elem, } if (GPR_UNLIKELY(bytes_buffered_for_retry_ > chand->per_rpc_retry_buffer_size())) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: exceeded retry buffer size, committing", chand, this); @@ -1651,7 +1815,7 @@ void CallData::PendingBatchesAdd(grpc_call_element* elem, // If we are not going to retry and have not yet started, pretend // retries are disabled so that we don't bother with retry overhead. if (num_attempts_completed_ == 0) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: disabling retries before first attempt", chand, this); @@ -1692,7 +1856,7 @@ void CallData::MaybeClearPendingBatch(grpc_call_element* elem, (!batch->recv_trailing_metadata || batch->payload->recv_trailing_metadata.recv_trailing_metadata_ready == nullptr)) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: clearing pending batch", chand, this); } @@ -1715,7 +1879,7 @@ void CallData::PendingBatchesFail( grpc_call_element* elem, grpc_error* error, YieldCallCombinerPredicate yield_call_combiner_predicate) { GPR_ASSERT(error != GRPC_ERROR_NONE); - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { size_t num_batches = 0; for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) { if (pending_batches_[i].batch != nullptr) ++num_batches; @@ -1769,7 +1933,7 @@ void CallData::PendingBatchesResume(grpc_call_element* elem) { return; } // Retries not enabled; send down batches as-is. - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { size_t num_batches = 0; for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) { if (pending_batches_[i].batch != nullptr) ++num_batches; @@ -1810,7 +1974,7 @@ CallData::PendingBatch* CallData::PendingBatchFind(grpc_call_element* elem, PendingBatch* pending = &pending_batches_[i]; grpc_transport_stream_op_batch* batch = pending->batch; if (batch != nullptr && predicate(batch)) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: %s pending batch at index %" PRIuPTR, chand, this, log_message, i); @@ -1830,7 +1994,7 @@ void CallData::RetryCommit(grpc_call_element* elem, ChannelData* chand = static_cast(elem->channel_data); if (retry_committed_) return; retry_committed_ = true; - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: committing retries", chand, this); } if (retry_state != nullptr) { @@ -1843,8 +2007,7 @@ void CallData::DoRetry(grpc_call_element* elem, grpc_millis server_pushback_ms) { ChannelData* chand = static_cast(elem->channel_data); GPR_ASSERT(method_params_ != nullptr); - const ClientChannelMethodParams::RetryPolicy* retry_policy = - method_params_->retry_policy(); + const auto* retry_policy = method_params_->retry_policy(); GPR_ASSERT(retry_policy != nullptr); // Reset subchannel call and connected subchannel. subchannel_call_.reset(); @@ -1852,7 +2015,7 @@ void CallData::DoRetry(grpc_call_element* elem, // Compute backoff delay. grpc_millis next_attempt_time; if (server_pushback_ms >= 0) { - next_attempt_time = grpc_core::ExecCtx::Get()->Now() + server_pushback_ms; + next_attempt_time = ExecCtx::Get()->Now() + server_pushback_ms; last_attempt_got_server_pushback_ = true; } else { if (num_attempts_completed_ == 1 || last_attempt_got_server_pushback_) { @@ -1866,10 +2029,10 @@ void CallData::DoRetry(grpc_call_element* elem, } next_attempt_time = retry_backoff_->NextAttemptTime(); } - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: retrying failed call in %" PRId64 " ms", chand, - this, next_attempt_time - grpc_core::ExecCtx::Get()->Now()); + this, next_attempt_time - ExecCtx::Get()->Now()); } // Schedule retry after computed delay. GRPC_CLOSURE_INIT(&pick_closure_, StartPickLocked, elem, @@ -1886,8 +2049,7 @@ bool CallData::MaybeRetry(grpc_call_element* elem, ChannelData* chand = static_cast(elem->channel_data); // Get retry policy. if (method_params_ == nullptr) return false; - const ClientChannelMethodParams::RetryPolicy* retry_policy = - method_params_->retry_policy(); + const auto* retry_policy = method_params_->retry_policy(); if (retry_policy == nullptr) return false; // If we've already dispatched a retry from this call, return true. // This catches the case where the batch has multiple callbacks @@ -1897,7 +2059,7 @@ bool CallData::MaybeRetry(grpc_call_element* elem, retry_state = static_cast( batch_data->subchannel_call->GetParentData()); if (retry_state->retry_dispatched) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: retry already dispatched", chand, this); } @@ -1909,14 +2071,14 @@ bool CallData::MaybeRetry(grpc_call_element* elem, if (retry_throttle_data_ != nullptr) { retry_throttle_data_->RecordSuccess(); } - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: call succeeded", chand, this); } return false; } // Status is not OK. Check whether the status is retryable. if (!retry_policy->retryable_status_codes.Contains(status)) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: status %s not configured as retryable", chand, this, grpc_status_code_to_string(status)); @@ -1932,14 +2094,14 @@ bool CallData::MaybeRetry(grpc_call_element* elem, // checks, so that we don't fail to record failures due to other factors. if (retry_throttle_data_ != nullptr && !retry_throttle_data_->RecordFailure()) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: retries throttled", chand, this); } return false; } // Check whether the call is committed. if (retry_committed_) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: retries already committed", chand, this); } @@ -1948,7 +2110,7 @@ bool CallData::MaybeRetry(grpc_call_element* elem, // Check whether we have retries remaining. ++num_attempts_completed_; if (num_attempts_completed_ >= retry_policy->max_attempts) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: exceeded %d retry attempts", chand, this, retry_policy->max_attempts); } @@ -1956,7 +2118,7 @@ bool CallData::MaybeRetry(grpc_call_element* elem, } // If the call was cancelled from the surface, don't retry. if (cancel_error_ != GRPC_ERROR_NONE) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: call cancelled from surface, not retrying", chand, this); @@ -1969,14 +2131,14 @@ bool CallData::MaybeRetry(grpc_call_element* elem, // If the value is "-1" or any other unparseable string, we do not retry. uint32_t ms; if (!grpc_parse_slice_to_uint32(GRPC_MDVALUE(*server_pushback_md), &ms)) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: not retrying due to server push-back", chand, this); } return false; } else { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: server push-back: retry in %u ms", chand, this, ms); } @@ -1994,10 +2156,8 @@ bool CallData::MaybeRetry(grpc_call_element* elem, CallData::SubchannelCallBatchData* CallData::SubchannelCallBatchData::Create( grpc_call_element* elem, int refcount, bool set_on_complete) { CallData* calld = static_cast(elem->call_data); - SubchannelCallBatchData* batch_data = - new (gpr_arena_alloc(calld->arena_, sizeof(*batch_data))) - SubchannelCallBatchData(elem, calld, refcount, set_on_complete); - return batch_data; + return calld->arena_->New(elem, calld, refcount, + set_on_complete); } CallData::SubchannelCallBatchData::SubchannelCallBatchData( @@ -2081,7 +2241,7 @@ void CallData::RecvInitialMetadataReady(void* arg, grpc_error* error) { grpc_call_element* elem = batch_data->elem; ChannelData* chand = static_cast(elem->channel_data); CallData* calld = static_cast(elem->call_data); - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: got recv_initial_metadata_ready, error=%s", chand, calld, grpc_error_string(error)); @@ -2105,7 +2265,7 @@ void CallData::RecvInitialMetadataReady(void* arg, grpc_error* error) { if (GPR_UNLIKELY((retry_state->trailing_metadata_available || error != GRPC_ERROR_NONE) && !retry_state->completed_recv_trailing_metadata)) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: deferring recv_initial_metadata_ready " "(Trailers-Only)", @@ -2171,7 +2331,7 @@ void CallData::RecvMessageReady(void* arg, grpc_error* error) { grpc_call_element* elem = batch_data->elem; ChannelData* chand = static_cast(elem->channel_data); CallData* calld = static_cast(elem->call_data); - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: got recv_message_ready, error=%s", chand, calld, grpc_error_string(error)); } @@ -2193,7 +2353,7 @@ void CallData::RecvMessageReady(void* arg, grpc_error* error) { if (GPR_UNLIKELY( (retry_state->recv_message == nullptr || error != GRPC_ERROR_NONE) && !retry_state->completed_recv_trailing_metadata)) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: deferring recv_message_ready (nullptr " "message and recv_trailing_metadata pending)", @@ -2331,7 +2491,7 @@ void CallData::AddClosuresToFailUnstartedPendingBatches( for (size_t i = 0; i < GPR_ARRAY_SIZE(pending_batches_); ++i) { PendingBatch* pending = &pending_batches_[i]; if (PendingBatchIsUnstarted(pending, retry_state)) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: failing unstarted pending batch at index " "%" PRIuPTR, @@ -2377,7 +2537,7 @@ void CallData::RecvTrailingMetadataReady(void* arg, grpc_error* error) { grpc_call_element* elem = batch_data->elem; ChannelData* chand = static_cast(elem->channel_data); CallData* calld = static_cast(elem->call_data); - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: got recv_trailing_metadata_ready, error=%s", chand, calld, grpc_error_string(error)); @@ -2393,7 +2553,7 @@ void CallData::RecvTrailingMetadataReady(void* arg, grpc_error* error) { batch_data->batch.payload->recv_trailing_metadata.recv_trailing_metadata; calld->GetCallStatus(elem, md_batch, GRPC_ERROR_REF(error), &status, &server_pushback_md); - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: call finished, status=%s", chand, calld, grpc_status_code_to_string(status)); } @@ -2472,7 +2632,7 @@ void CallData::AddClosuresForReplayOrPendingSendOps( } } if (have_pending_send_message_ops || have_pending_send_trailing_metadata_op) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: starting next batch for pending send op(s)", chand, this); @@ -2491,7 +2651,7 @@ void CallData::OnComplete(void* arg, grpc_error* error) { grpc_call_element* elem = batch_data->elem; ChannelData* chand = static_cast(elem->channel_data); CallData* calld = static_cast(elem->call_data); - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { char* batch_str = grpc_transport_stream_op_batch_string(&batch_data->batch); gpr_log(GPR_INFO, "chand=%p calld=%p: got on_complete, error=%s, batch=%s", chand, calld, grpc_error_string(error), batch_str); @@ -2567,7 +2727,7 @@ void CallData::AddClosureForSubchannelBatch( batch->handler_private.extra_arg = subchannel_call_.get(); GRPC_CLOSURE_INIT(&batch->handler_private.closure, StartBatchInCallCombiner, batch, grpc_schedule_on_exec_ctx); - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { char* batch_str = grpc_transport_stream_op_batch_string(batch); gpr_log(GPR_INFO, "chand=%p calld=%p: starting subchannel batch: %s", chand, this, batch_str); @@ -2589,10 +2749,10 @@ void CallData::AddRetriableSendInitialMetadataOp( // // If we've already completed one or more attempts, add the // grpc-retry-attempts header. - retry_state->send_initial_metadata_storage = static_cast( - gpr_arena_alloc(arena_, sizeof(grpc_linked_mdelem) * - (send_initial_metadata_.list.count + - (num_attempts_completed_ > 0)))); + retry_state->send_initial_metadata_storage = + static_cast(arena_->Alloc( + sizeof(grpc_linked_mdelem) * + (send_initial_metadata_.list.count + (num_attempts_completed_ > 0)))); grpc_metadata_batch_copy(&send_initial_metadata_, &retry_state->send_initial_metadata, retry_state->send_initial_metadata_storage); @@ -2630,7 +2790,7 @@ void CallData::AddRetriableSendMessageOp(grpc_call_element* elem, SubchannelCallRetryState* retry_state, SubchannelCallBatchData* batch_data) { ChannelData* chand = static_cast(elem->channel_data); - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: starting calld->send_messages[%" PRIuPTR "]", chand, this, retry_state->started_send_message_count); @@ -2651,8 +2811,7 @@ void CallData::AddRetriableSendTrailingMetadataOp( // the filters in the subchannel stack may modify this batch, and we don't // want those modifications to be passed forward to subsequent attempts. retry_state->send_trailing_metadata_storage = - static_cast(gpr_arena_alloc( - arena_, + static_cast(arena_->Alloc( sizeof(grpc_linked_mdelem) * send_trailing_metadata_.list.count)); grpc_metadata_batch_copy(&send_trailing_metadata_, &retry_state->send_trailing_metadata, @@ -2714,7 +2873,7 @@ void CallData::AddRetriableRecvTrailingMetadataOp( void CallData::StartInternalRecvTrailingMetadata(grpc_call_element* elem) { ChannelData* chand = static_cast(elem->channel_data); - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: call failed but recv_trailing_metadata not " "started; starting it internally", @@ -2746,7 +2905,7 @@ CallData::MaybeCreateSubchannelBatchForReplay( if (seen_send_initial_metadata_ && !retry_state->started_send_initial_metadata && !pending_send_initial_metadata_) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: replaying previously completed " "send_initial_metadata op", @@ -2762,7 +2921,7 @@ CallData::MaybeCreateSubchannelBatchForReplay( retry_state->started_send_message_count == retry_state->completed_send_message_count && !pending_send_message_) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: replaying previously completed " "send_message op", @@ -2782,7 +2941,7 @@ CallData::MaybeCreateSubchannelBatchForReplay( retry_state->started_send_message_count == send_messages_.size() && !retry_state->started_send_trailing_metadata && !pending_send_trailing_metadata_) { - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: replaying previously completed " "send_trailing_metadata op", @@ -2867,6 +3026,8 @@ void CallData::AddSubchannelBatchesForPendingBatches( // If we're not retrying, just send the batch as-is. if (method_params_ == nullptr || method_params_->retry_policy() == nullptr || retry_committed_) { + // TODO(roth) : We should probably call + // MaybeInjectRecvTrailingMetadataReadyForLoadBalancingPolicy here. AddClosureForSubchannelBatch(elem, batch, closures); PendingBatchClear(pending); continue; @@ -2925,7 +3086,7 @@ void CallData::StartRetriableSubchannelBatches(void* arg, grpc_error* ignored) { grpc_call_element* elem = static_cast(arg); ChannelData* chand = static_cast(elem->channel_data); CallData* calld = static_cast(elem->call_data); - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: constructing retriable batches", chand, calld); } @@ -2950,7 +3111,7 @@ void CallData::StartRetriableSubchannelBatches(void* arg, grpc_error* ignored) { // Now add pending batches. calld->AddSubchannelBatchesForPendingBatches(elem, retry_state, &closures); // Start batches on subchannel call. - if (grpc_client_channel_call_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_call_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: starting %" PRIuPTR " retriable batches on subchannel_call=%p", @@ -2976,7 +3137,7 @@ void CallData::CreateSubchannelCall(grpc_call_element* elem) { grpc_error* error = GRPC_ERROR_NONE; subchannel_call_ = pick_.pick.connected_subchannel->CreateCall(call_args, &error); - if (grpc_client_channel_routing_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: create subchannel_call=%p: error=%s", chand, this, subchannel_call_.get(), grpc_error_string(error)); } @@ -2996,7 +3157,7 @@ void CallData::PickDone(void* arg, grpc_error* error) { ChannelData* chand = static_cast(elem->channel_data); CallData* calld = static_cast(elem->call_data); if (error != GRPC_ERROR_NONE) { - if (grpc_client_channel_routing_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: failed to pick subchannel: error=%s", chand, calld, grpc_error_string(error)); @@ -3017,7 +3178,7 @@ class CallData::QueuedPickCanceller { GRPC_CALL_STACK_REF(calld->owning_call_, "QueuedPickCanceller"); GRPC_CLOSURE_INIT(&closure_, &CancelLocked, this, grpc_combiner_scheduler(chand->data_plane_combiner())); - grpc_call_combiner_set_notify_on_cancel(calld->call_combiner_, &closure_); + calld->call_combiner_->SetNotifyOnCancel(&closure_); } private: @@ -3025,7 +3186,7 @@ class CallData::QueuedPickCanceller { auto* self = static_cast(arg); auto* chand = static_cast(self->elem_->channel_data); auto* calld = static_cast(self->elem_->call_data); - if (grpc_client_channel_routing_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: cancelling queued pick: " "error=%s self=%p calld->pick_canceller=%p", @@ -3049,7 +3210,7 @@ class CallData::QueuedPickCanceller { void CallData::RemoveCallFromQueuedPicksLocked(grpc_call_element* elem) { auto* chand = static_cast(elem->channel_data); - if (grpc_client_channel_routing_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: removing from queued picks list", chand, this); } @@ -3061,7 +3222,7 @@ void CallData::RemoveCallFromQueuedPicksLocked(grpc_call_element* elem) { void CallData::AddCallToQueuedPicksLocked(grpc_call_element* elem) { auto* chand = static_cast(elem->channel_data); - if (grpc_client_channel_routing_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: adding to queued picks list", chand, this); } @@ -3074,12 +3235,23 @@ void CallData::AddCallToQueuedPicksLocked(grpc_call_element* elem) { void CallData::ApplyServiceConfigToCallLocked(grpc_call_element* elem) { ChannelData* chand = static_cast(elem->channel_data); - if (grpc_client_channel_routing_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: applying service config to call", chand, this); } + // Store a ref to the service_config in service_config_call_data_. Also, save + // a pointer to this in the call_context so that all future filters can access + // it. + service_config_call_data_ = + ServiceConfig::CallData(chand->service_config(), path_); + if (service_config_call_data_.service_config() != nullptr) { + call_context_[GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA].value = + &service_config_call_data_; + method_params_ = static_cast( + service_config_call_data_.GetMethodParsedConfig( + internal::ClientChannelServiceConfigParser::ParserIndex())); + } retry_throttle_data_ = chand->retry_throttle_data(); - method_params_ = chand->GetMethodParams(path_); if (method_params_ != nullptr) { // If the deadline from the service config is shorter than the one // from the client API, reset the deadline timer. @@ -3097,12 +3269,10 @@ void CallData::ApplyServiceConfigToCallLocked(grpc_call_element* elem) { uint32_t* send_initial_metadata_flags = &pending_batches_[0] .batch->payload->send_initial_metadata.send_initial_metadata_flags; - if (GPR_UNLIKELY(method_params_->wait_for_ready() != - ClientChannelMethodParams::WAIT_FOR_READY_UNSET && - !(*send_initial_metadata_flags & - GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET))) { - if (method_params_->wait_for_ready() == - ClientChannelMethodParams::WAIT_FOR_READY_TRUE) { + if (method_params_->wait_for_ready().has_value() && + !(*send_initial_metadata_flags & + GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET)) { + if (method_params_->wait_for_ready().value()) { *send_initial_metadata_flags |= GRPC_INITIAL_METADATA_WAIT_FOR_READY; } else { *send_initial_metadata_flags &= ~GRPC_INITIAL_METADATA_WAIT_FOR_READY; @@ -3174,7 +3344,7 @@ void CallData::StartPickLocked(void* arg, grpc_error* error) { // Attempt pick. error = GRPC_ERROR_NONE; auto pick_result = chand->picker()->Pick(&calld->pick_.pick, &error); - if (grpc_client_channel_routing_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) { gpr_log(GPR_INFO, "chand=%p calld=%p: LB pick returned %s (connected_subchannel=%p, " "error=%s)", diff --git a/src/core/ext/filters/client_channel/client_channel_channelz.cc b/src/core/ext/filters/client_channel/client_channel_channelz.cc index a7a47e9eb10..de61819ef54 100644 --- a/src/core/ext/filters/client_channel/client_channel_channelz.cc +++ b/src/core/ext/filters/client_channel/client_channel_channelz.cc @@ -127,7 +127,9 @@ void SubchannelNode::PopulateConnectivityState(grpc_json* json) { if (subchannel_ == nullptr) { state = GRPC_CHANNEL_SHUTDOWN; } else { - state = subchannel_->CheckConnectivity(true /* inhibit_health_checking */); + state = subchannel_->CheckConnectivityState( + nullptr /* health_check_service_name */, + nullptr /* connected_subchannel */); } json = grpc_json_create_child(nullptr, json, "state", nullptr, GRPC_JSON_OBJECT, false); diff --git a/src/core/ext/filters/client_channel/client_channel_plugin.cc b/src/core/ext/filters/client_channel/client_channel_plugin.cc index 8e76c4cbb15..e564df8be33 100644 --- a/src/core/ext/filters/client_channel/client_channel_plugin.cc +++ b/src/core/ext/filters/client_channel/client_channel_plugin.cc @@ -32,6 +32,7 @@ #include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/proxy_mapper_registry.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" +#include "src/core/ext/filters/client_channel/resolver_result_parsing.h" #include "src/core/ext/filters/client_channel/retry_throttle.h" #include "src/core/lib/surface/channel_init.h" @@ -50,6 +51,7 @@ static bool append_filter(grpc_channel_stack_builder* builder, void* arg) { void grpc_client_channel_init(void) { grpc_core::ServiceConfig::Init(); + grpc_core::internal::ClientChannelServiceConfigParser::Register(); grpc_core::LoadBalancingPolicyRegistry::Builder::InitRegistry(); grpc_core::ResolverRegistry::Builder::InitRegistry(); grpc_core::internal::ServerRetryThrottleMap::Init(); diff --git a/src/core/ext/filters/client_channel/health/health_check_client.cc b/src/core/ext/filters/client_channel/health/health_check_client.cc index a99f1e54062..faa2ba5b3b1 100644 --- a/src/core/ext/filters/client_channel/health/health_check_client.cc +++ b/src/core/ext/filters/client_channel/health/health_check_client.cc @@ -37,11 +37,10 @@ #define HEALTH_CHECK_RECONNECT_MAX_BACKOFF_SECONDS 120 #define HEALTH_CHECK_RECONNECT_JITTER 0.2 -grpc_core::TraceFlag grpc_health_check_client_trace(false, - "health_check_client"); - namespace grpc_core { +TraceFlag grpc_health_check_client_trace(false, "health_check_client"); + // // HealthCheckClient // @@ -50,7 +49,7 @@ HealthCheckClient::HealthCheckClient( const char* service_name, RefCountedPtr connected_subchannel, grpc_pollset_set* interested_parties, - grpc_core::RefCountedPtr channelz_node) + RefCountedPtr channelz_node) : InternallyRefCounted(&grpc_health_check_client_trace), service_name_(service_name), connected_subchannel_(std::move(connected_subchannel)), @@ -64,7 +63,7 @@ HealthCheckClient::HealthCheckClient( .set_jitter(HEALTH_CHECK_RECONNECT_JITTER) .set_max_backoff(HEALTH_CHECK_RECONNECT_MAX_BACKOFF_SECONDS * 1000)) { - if (grpc_health_check_client_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_health_check_client_trace)) { gpr_log(GPR_INFO, "created HealthCheckClient %p", this); } GRPC_CLOSURE_INIT(&retry_timer_callback_, OnRetryTimer, this, @@ -73,7 +72,7 @@ HealthCheckClient::HealthCheckClient( } HealthCheckClient::~HealthCheckClient() { - if (grpc_health_check_client_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_health_check_client_trace)) { gpr_log(GPR_INFO, "destroying HealthCheckClient %p", this); } GRPC_ERROR_UNREF(error_); @@ -100,7 +99,7 @@ void HealthCheckClient::SetHealthStatus(grpc_connectivity_state state, void HealthCheckClient::SetHealthStatusLocked(grpc_connectivity_state state, grpc_error* error) { - if (grpc_health_check_client_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_health_check_client_trace)) { gpr_log(GPR_INFO, "HealthCheckClient %p: setting state=%d error=%s", this, state, grpc_error_string(error)); } @@ -116,7 +115,7 @@ void HealthCheckClient::SetHealthStatusLocked(grpc_connectivity_state state, } void HealthCheckClient::Orphan() { - if (grpc_health_check_client_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_health_check_client_trace)) { gpr_log(GPR_INFO, "HealthCheckClient %p: shutting down", this); } { @@ -146,7 +145,7 @@ void HealthCheckClient::StartCallLocked() { GPR_ASSERT(call_state_ == nullptr); SetHealthStatusLocked(GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE); call_state_ = MakeOrphanable(Ref(), interested_parties_); - if (grpc_health_check_client_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_health_check_client_trace)) { gpr_log(GPR_INFO, "HealthCheckClient %p: created CallState %p", this, call_state_.get()); } @@ -160,7 +159,7 @@ void HealthCheckClient::StartRetryTimer() { GRPC_ERROR_CREATE_FROM_STATIC_STRING( "health check call failed; will retry after backoff")); grpc_millis next_try = retry_backoff_.NextAttemptTime(); - if (grpc_health_check_client_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_health_check_client_trace)) { gpr_log(GPR_INFO, "HealthCheckClient %p: health check call lost...", this); grpc_millis timeout = next_try - ExecCtx::Get()->Now(); if (timeout > 0) { @@ -185,7 +184,7 @@ void HealthCheckClient::OnRetryTimer(void* arg, grpc_error* error) { self->retry_timer_callback_pending_ = false; if (!self->shutting_down_ && error == GRPC_ERROR_NONE && self->call_state_ == nullptr) { - if (grpc_health_check_client_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_health_check_client_trace)) { gpr_log(GPR_INFO, "HealthCheckClient %p: restarting health check call", self); } @@ -278,17 +277,14 @@ bool DecodeResponse(grpc_slice_buffer* slice_buffer, grpc_error** error) { HealthCheckClient::CallState::CallState( RefCountedPtr health_check_client, grpc_pollset_set* interested_parties) - : InternallyRefCounted(&grpc_health_check_client_trace), - health_check_client_(std::move(health_check_client)), + : health_check_client_(std::move(health_check_client)), pollent_(grpc_polling_entity_create_from_pollset_set(interested_parties)), - arena_(gpr_arena_create(health_check_client_->connected_subchannel_ - ->GetInitialCallSizeEstimate(0))), - payload_(context_) { - grpc_call_combiner_init(&call_combiner_); -} + arena_(Arena::Create(health_check_client_->connected_subchannel_ + ->GetInitialCallSizeEstimate(0))), + payload_(context_) {} HealthCheckClient::CallState::~CallState() { - if (grpc_health_check_client_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_health_check_client_trace)) { gpr_log(GPR_INFO, "HealthCheckClient %p: destroying CallState %p", health_check_client_.get(), this); } @@ -303,14 +299,13 @@ HealthCheckClient::CallState::~CallState() { // holding to the call stack. Also flush the closures on exec_ctx so that // filters that schedule cancel notification closures on exec_ctx do not // need to take a ref of the call stack to guarantee closure liveness. - grpc_call_combiner_set_notify_on_cancel(&call_combiner_, nullptr); - grpc_core::ExecCtx::Get()->Flush(); - grpc_call_combiner_destroy(&call_combiner_); - gpr_arena_destroy(arena_); + call_combiner_.SetNotifyOnCancel(nullptr); + ExecCtx::Get()->Flush(); + arena_->Destroy(); } void HealthCheckClient::CallState::Orphan() { - grpc_call_combiner_cancel(&call_combiner_, GRPC_ERROR_CANCELLED); + call_combiner_.Cancel(GRPC_ERROR_CANCELLED); Cancel(); } @@ -326,7 +321,13 @@ void HealthCheckClient::CallState::StartCall() { 0, // parent_data_size }; grpc_error* error = GRPC_ERROR_NONE; - call_ = health_check_client_->connected_subchannel_->CreateCall(args, &error); + call_ = health_check_client_->connected_subchannel_->CreateCall(args, &error) + .release(); + // Register after-destruction callback. + GRPC_CLOSURE_INIT(&after_call_stack_destruction_, AfterCallStackDestruction, + this, grpc_schedule_on_exec_ctx); + call_->SetAfterCallStackDestroy(&after_call_stack_destruction_); + // Check if creation failed. if (error != GRPC_ERROR_NONE) { gpr_log(GPR_ERROR, "HealthCheckClient %p CallState %p: error creating health " @@ -335,7 +336,7 @@ void HealthCheckClient::CallState::StartCall() { GRPC_ERROR_UNREF(error); // Schedule instead of running directly, since we must not be // holding health_check_client_->mu_ when CallEnded() is called. - Ref(DEBUG_LOCATION, "call_end_closure").release(); + call_->Ref(DEBUG_LOCATION, "call_end_closure").release(); GRPC_CLOSURE_SCHED( GRPC_CLOSURE_INIT(&batch_.handler_private.closure, CallEndedRetry, this, grpc_schedule_on_exec_ctx), @@ -346,7 +347,7 @@ void HealthCheckClient::CallState::StartCall() { payload_.context = context_; batch_.payload = &payload_; // on_complete callback takes ref, handled manually. - Ref(DEBUG_LOCATION, "on_complete").release(); + call_->Ref(DEBUG_LOCATION, "on_complete").release(); batch_.on_complete = GRPC_CLOSURE_INIT(&on_complete_, OnComplete, this, grpc_schedule_on_exec_ctx); // Add send_initial_metadata op. @@ -379,7 +380,7 @@ void HealthCheckClient::CallState::StartCall() { payload_.recv_initial_metadata.trailing_metadata_available = nullptr; payload_.recv_initial_metadata.peer_string = nullptr; // recv_initial_metadata_ready callback takes ref, handled manually. - Ref(DEBUG_LOCATION, "recv_initial_metadata_ready").release(); + call_->Ref(DEBUG_LOCATION, "recv_initial_metadata_ready").release(); payload_.recv_initial_metadata.recv_initial_metadata_ready = GRPC_CLOSURE_INIT(&recv_initial_metadata_ready_, RecvInitialMetadataReady, this, grpc_schedule_on_exec_ctx); @@ -387,7 +388,7 @@ void HealthCheckClient::CallState::StartCall() { // Add recv_message op. payload_.recv_message.recv_message = &recv_message_; // recv_message callback takes ref, handled manually. - Ref(DEBUG_LOCATION, "recv_message_ready").release(); + call_->Ref(DEBUG_LOCATION, "recv_message_ready").release(); payload_.recv_message.recv_message_ready = GRPC_CLOSURE_INIT( &recv_message_ready_, RecvMessageReady, this, grpc_schedule_on_exec_ctx); batch_.recv_message = true; @@ -423,7 +424,7 @@ void HealthCheckClient::CallState::StartBatchInCallCombiner(void* arg, void HealthCheckClient::CallState::StartBatch( grpc_transport_stream_op_batch* batch) { - batch->handler_private.extra_arg = call_.get(); + batch->handler_private.extra_arg = call_; GRPC_CLOSURE_INIT(&batch->handler_private.closure, StartBatchInCallCombiner, batch, grpc_schedule_on_exec_ctx); GRPC_CALL_COMBINER_START(&call_combiner_, &batch->handler_private.closure, @@ -434,7 +435,7 @@ void HealthCheckClient::CallState::AfterCallStackDestruction( void* arg, grpc_error* error) { HealthCheckClient::CallState* self = static_cast(arg); - self->Unref(DEBUG_LOCATION, "cancel"); + Delete(self); } void HealthCheckClient::CallState::OnCancelComplete(void* arg, @@ -442,10 +443,7 @@ void HealthCheckClient::CallState::OnCancelComplete(void* arg, HealthCheckClient::CallState* self = static_cast(arg); GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "health_cancel"); - GRPC_CLOSURE_INIT(&self->after_call_stack_destruction_, - AfterCallStackDestruction, self, grpc_schedule_on_exec_ctx); - self->call_->SetAfterCallStackDestroy(&self->after_call_stack_destruction_); - self->call_.reset(); + self->call_->Unref(DEBUG_LOCATION, "cancel"); } void HealthCheckClient::CallState::StartCancel(void* arg, grpc_error* error) { @@ -462,7 +460,7 @@ void HealthCheckClient::CallState::Cancel() { bool expected = false; if (cancelled_.CompareExchangeStrong(&expected, true, MemoryOrder::ACQ_REL, MemoryOrder::ACQUIRE)) { - Ref(DEBUG_LOCATION, "cancel").release(); + call_->Ref(DEBUG_LOCATION, "cancel").release(); GRPC_CALL_COMBINER_START( &call_combiner_, GRPC_CLOSURE_CREATE(StartCancel, this, grpc_schedule_on_exec_ctx), @@ -476,7 +474,7 @@ void HealthCheckClient::CallState::OnComplete(void* arg, grpc_error* error) { GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "on_complete"); grpc_metadata_batch_destroy(&self->send_initial_metadata_); grpc_metadata_batch_destroy(&self->send_trailing_metadata_); - self->Unref(DEBUG_LOCATION, "on_complete"); + self->call_->Unref(DEBUG_LOCATION, "on_complete"); } void HealthCheckClient::CallState::RecvInitialMetadataReady(void* arg, @@ -485,7 +483,7 @@ void HealthCheckClient::CallState::RecvInitialMetadataReady(void* arg, static_cast(arg); GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "recv_initial_metadata_ready"); grpc_metadata_batch_destroy(&self->recv_initial_metadata_); - self->Unref(DEBUG_LOCATION, "recv_initial_metadata_ready"); + self->call_->Unref(DEBUG_LOCATION, "recv_initial_metadata_ready"); } void HealthCheckClient::CallState::DoneReadingRecvMessage(grpc_error* error) { @@ -494,7 +492,7 @@ void HealthCheckClient::CallState::DoneReadingRecvMessage(grpc_error* error) { GRPC_ERROR_UNREF(error); Cancel(); grpc_slice_buffer_destroy_internal(&recv_message_buffer_); - Unref(DEBUG_LOCATION, "recv_message_ready"); + call_->Unref(DEBUG_LOCATION, "recv_message_ready"); return; } const bool healthy = DecodeResponse(&recv_message_buffer_, &error); @@ -567,7 +565,7 @@ void HealthCheckClient::CallState::RecvMessageReady(void* arg, static_cast(arg); GRPC_CALL_COMBINER_STOP(&self->call_combiner_, "recv_message_ready"); if (self->recv_message_ == nullptr) { - self->Unref(DEBUG_LOCATION, "recv_message_ready"); + self->call_->Unref(DEBUG_LOCATION, "recv_message_ready"); return; } grpc_slice_buffer_init(&self->recv_message_buffer_); @@ -593,7 +591,7 @@ void HealthCheckClient::CallState::RecvTrailingMetadataReady( status = grpc_get_status_code_from_metadata( self->recv_trailing_metadata_.idx.named.grpc_status->md); } - if (grpc_health_check_client_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_health_check_client_trace)) { gpr_log(GPR_INFO, "HealthCheckClient %p CallState %p: health watch failed with " "status %d", @@ -625,7 +623,7 @@ void HealthCheckClient::CallState::CallEndedRetry(void* arg, HealthCheckClient::CallState* self = static_cast(arg); self->CallEnded(true /* retry */); - self->Unref(DEBUG_LOCATION, "call_end_closure"); + self->call_->Unref(DEBUG_LOCATION, "call_end_closure"); } void HealthCheckClient::CallState::CallEnded(bool retry) { @@ -648,7 +646,9 @@ void HealthCheckClient::CallState::CallEnded(bool retry) { } } } - Unref(DEBUG_LOCATION, "call_ended"); + // When the last ref to the call stack goes away, the CallState object + // will be automatically destroyed. + call_->Unref(DEBUG_LOCATION, "call_ended"); } } // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/health/health_check_client.h b/src/core/ext/filters/client_channel/health/health_check_client.h index 6e0123e4925..956c1095550 100644 --- a/src/core/ext/filters/client_channel/health/health_check_client.h +++ b/src/core/ext/filters/client_channel/health/health_check_client.h @@ -27,7 +27,7 @@ #include "src/core/ext/filters/client_channel/client_channel_channelz.h" #include "src/core/ext/filters/client_channel/subchannel.h" #include "src/core/lib/backoff/backoff.h" -#include "src/core/lib/gpr/arena.h" +#include "src/core/lib/gprpp/arena.h" #include "src/core/lib/gprpp/atomic.h" #include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" @@ -61,7 +61,7 @@ class HealthCheckClient : public InternallyRefCounted { private: // Contains a call to the backend and all the data related to the call. - class CallState : public InternallyRefCounted { + class CallState : public Orphanable { public: CallState(RefCountedPtr health_check_client, grpc_pollset_set* interested_parties_); @@ -97,12 +97,14 @@ class HealthCheckClient : public InternallyRefCounted { RefCountedPtr health_check_client_; grpc_polling_entity pollent_; - gpr_arena* arena_; - grpc_call_combiner call_combiner_; + Arena* arena_; + grpc_core::CallCombiner call_combiner_; grpc_call_context_element context_[GRPC_CONTEXT_COUNT] = {}; - // The streaming call to the backend. Always non-NULL. - RefCountedPtr call_; + // The streaming call to the backend. Always non-null. + // Refs are tracked manually; when the last ref is released, the + // CallState object will be automatically destroyed. + SubchannelCall* call_; grpc_transport_stream_op_batch_payload payload_; grpc_transport_stream_op_batch batch_; diff --git a/src/core/ext/filters/client_channel/http_connect_handshaker.cc b/src/core/ext/filters/client_channel/http_connect_handshaker.cc index 90a79843458..95366b57386 100644 --- a/src/core/ext/filters/client_channel/http_connect_handshaker.cc +++ b/src/core/ext/filters/client_channel/http_connect_handshaker.cc @@ -31,7 +31,6 @@ #include "src/core/ext/filters/client_channel/resolver_registry.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/handshaker_registry.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gprpp/sync.h" #include "src/core/lib/http/format_request.h" diff --git a/src/core/ext/filters/client_channel/lb_policy.cc b/src/core/ext/filters/client_channel/lb_policy.cc index 6b657465891..6fa799343ca 100644 --- a/src/core/ext/filters/client_channel/lb_policy.cc +++ b/src/core/ext/filters/client_channel/lb_policy.cc @@ -62,32 +62,6 @@ void LoadBalancingPolicy::ShutdownAndUnrefLocked(void* arg, policy->Unref(); } -grpc_json* LoadBalancingPolicy::ParseLoadBalancingConfig( - const grpc_json* lb_config_array) { - if (lb_config_array == nullptr || lb_config_array->type != GRPC_JSON_ARRAY) { - return nullptr; - } - // Find the first LB policy that this client supports. - for (const grpc_json* lb_config = lb_config_array->child; - lb_config != nullptr; lb_config = lb_config->next) { - if (lb_config->type != GRPC_JSON_OBJECT) return nullptr; - grpc_json* policy = nullptr; - for (grpc_json* field = lb_config->child; field != nullptr; - field = field->next) { - if (field->key == nullptr || field->type != GRPC_JSON_OBJECT) - return nullptr; - if (policy != nullptr) return nullptr; // Violate "oneof" type. - policy = field; - } - if (policy == nullptr) return nullptr; - // If we support this policy, then select it. - if (LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(policy->key)) { - return policy; - } - } - return nullptr; -} - // // LoadBalancingPolicy::UpdateArgs // diff --git a/src/core/ext/filters/client_channel/lb_policy.h b/src/core/ext/filters/client_channel/lb_policy.h index e369f591727..2ac7df63b7d 100644 --- a/src/core/ext/filters/client_channel/lb_policy.h +++ b/src/core/ext/filters/client_channel/lb_policy.h @@ -36,6 +36,18 @@ extern grpc_core::DebugOnlyTraceFlag grpc_trace_lb_policy_refcount; namespace grpc_core { +/// Interface for parsed forms of load balancing configs found in a service +/// config. +class ParsedLoadBalancingConfig : public RefCounted { + public: + virtual ~ParsedLoadBalancingConfig() = default; + + // Returns the load balancing policy name + virtual const char* name() const GRPC_ABSTRACT; + + GRPC_ABSTRACT_BASE_CLASS; +}; + /// Interface for load balancing policies. /// /// The following concepts are used here: @@ -167,6 +179,9 @@ class LoadBalancingPolicy : public InternallyRefCounted { /// A proxy object used by the LB policy to communicate with the client /// channel. + // TODO(juanlishen): Consider adding a mid-layer subclass that helps handle + // things like swapping in pending policy when it's ready. Currently, we are + // duplicating the logic in many subclasses. class ChannelControlHelper { public: ChannelControlHelper() = default; @@ -193,30 +208,11 @@ class LoadBalancingPolicy : public InternallyRefCounted { GRPC_ABSTRACT_BASE_CLASS }; - /// Configuration for an LB policy instance. - // TODO(roth): Find a better JSON representation for this API. - class Config : public RefCounted { - public: - Config(const grpc_json* lb_config, - RefCountedPtr service_config) - : json_(lb_config), service_config_(std::move(service_config)) {} - - const char* name() const { return json_->key; } - const grpc_json* config() const { return json_->child; } - RefCountedPtr service_config() const { - return service_config_; - } - - private: - const grpc_json* json_; - RefCountedPtr service_config_; - }; - /// Data passed to the UpdateLocked() method when new addresses and /// config are available. struct UpdateArgs { ServerAddressList addresses; - RefCountedPtr config; + RefCountedPtr config; const grpc_channel_args* args = nullptr; // TODO(roth): Remove everything below once channel args is @@ -287,10 +283,6 @@ class LoadBalancingPolicy : public InternallyRefCounted { void Orphan() override; - /// Returns the JSON node of policy (with both policy name and config content) - /// given the JSON node of a LoadBalancingConfig array. - static grpc_json* ParseLoadBalancingConfig(const grpc_json* lb_config_array); - // A picker that returns PICK_QUEUE for all picks. // Also calls the parent LB policy's ExitIdleLocked() method when the // first pick is seen. diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc index 4423e479d62..ed6e8de3f21 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc @@ -118,6 +118,21 @@ namespace { constexpr char kGrpclb[] = "grpclb"; +class ParsedGrpcLbConfig : public ParsedLoadBalancingConfig { + public: + explicit ParsedGrpcLbConfig( + RefCountedPtr child_policy) + : child_policy_(std::move(child_policy)) {} + const char* name() const override { return kGrpclb; } + + RefCountedPtr child_policy() const { + return child_policy_; + } + + private: + RefCountedPtr child_policy_; +}; + class GrpcLb : public LoadBalancingPolicy { public: explicit GrpcLb(Args args); @@ -302,7 +317,6 @@ class GrpcLb : public LoadBalancingPolicy { // Helper functions used in UpdateLocked(). void ProcessAddressesAndChannelArgsLocked(const ServerAddressList& addresses, const grpc_channel_args& args); - void ParseLbConfig(Config* grpclb_config); static void OnBalancerChannelConnectivityChangedLocked(void* arg, grpc_error* error); void CancelBalancerChannelConnectivityWatchLocked(); @@ -380,7 +394,7 @@ class GrpcLb : public LoadBalancingPolicy { // until it reports READY, at which point it will be moved to child_policy_. OrphanablePtr pending_child_policy_; // The child policy config. - RefCountedPtr child_policy_config_; + RefCountedPtr child_policy_config_; // Child policy in state READY. bool child_policy_ready_ = false; }; @@ -626,7 +640,7 @@ void GrpcLb::Helper::UpdateState(grpc_connectivity_state state, // If this request is from the pending child policy, ignore it until // it reports READY, at which point we swap it into place. if (CalledByPendingChild()) { - if (grpc_lb_glb_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { gpr_log(GPR_INFO, "[grpclb %p helper %p] pending child policy %p reports state=%s", parent_.get(), this, parent_->pending_child_policy_.get(), @@ -668,7 +682,7 @@ void GrpcLb::Helper::UpdateState(grpc_connectivity_state state, if (parent_->serverlist_ == nullptr || (!parent_->serverlist_->ContainsAllDropEntries() && state != GRPC_CHANNEL_READY)) { - if (grpc_lb_glb_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { gpr_log(GPR_INFO, "[grpclb %p helper %p] state=%s passing child picker %p as-is", parent_.get(), this, grpc_connectivity_state_name(state), @@ -678,7 +692,7 @@ void GrpcLb::Helper::UpdateState(grpc_connectivity_state state, return; } // Cases 2 and 3a: wrap picker from the child in our own picker. - if (grpc_lb_glb_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { gpr_log(GPR_INFO, "[grpclb %p helper %p] state=%s wrapping child picker %p", parent_.get(), this, grpc_connectivity_state_name(state), picker.get()); @@ -701,7 +715,7 @@ void GrpcLb::Helper::RequestReresolution() { ? parent_->pending_child_policy_.get() : parent_->child_policy_.get(); if (child_ != latest_child_policy) return; - if (grpc_lb_glb_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { gpr_log(GPR_INFO, "[grpclb %p] Re-resolution requested from %schild policy (%p).", parent_.get(), CalledByPendingChild() ? "pending " : "", child_); @@ -788,7 +802,7 @@ void GrpcLb::BalancerCallState::Orphan() { void GrpcLb::BalancerCallState::StartQuery() { GPR_ASSERT(lb_call_ != nullptr); - if (grpc_lb_glb_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { gpr_log(GPR_INFO, "[grpclb %p] lb_calld=%p: Starting LB call %p", grpclb_policy_.get(), this, lb_call_); } @@ -995,7 +1009,7 @@ void GrpcLb::BalancerCallState::OnBalancerMessageReceivedLocked( lb_calld->client_stats_report_interval_ = GPR_MAX( GPR_MS_PER_SEC, grpc_grpclb_duration_to_millis( &initial_response->client_stats_report_interval)); - if (grpc_lb_glb_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { gpr_log(GPR_INFO, "[grpclb %p] lb_calld=%p: Received initial LB response " "message; client load reporting interval = %" PRId64 @@ -1003,7 +1017,7 @@ void GrpcLb::BalancerCallState::OnBalancerMessageReceivedLocked( grpclb_policy, lb_calld, lb_calld->client_stats_report_interval_); } - } else if (grpc_lb_glb_trace.enabled()) { + } else if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { gpr_log(GPR_INFO, "[grpclb %p] lb_calld=%p: Received initial LB response message; " "client load reporting NOT enabled", @@ -1016,7 +1030,7 @@ void GrpcLb::BalancerCallState::OnBalancerMessageReceivedLocked( // Have seen initial response, look for serverlist. GPR_ASSERT(lb_calld->lb_call_ != nullptr); auto serverlist_wrapper = MakeRefCounted(serverlist); - if (grpc_lb_glb_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { UniquePtr serverlist_text = serverlist_wrapper->AsText(); gpr_log(GPR_INFO, "[grpclb %p] lb_calld=%p: Serverlist with %" PRIuPTR @@ -1037,7 +1051,7 @@ void GrpcLb::BalancerCallState::OnBalancerMessageReceivedLocked( // Check if the serverlist differs from the previous one. if (grpclb_policy->serverlist_ != nullptr && *grpclb_policy->serverlist_ == *serverlist_wrapper) { - if (grpc_lb_glb_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { gpr_log(GPR_INFO, "[grpclb %p] lb_calld=%p: Incoming server list identical to " "current, ignoring.", @@ -1115,7 +1129,7 @@ void GrpcLb::BalancerCallState::OnBalancerStatusReceivedLocked( BalancerCallState* lb_calld = static_cast(arg); GrpcLb* grpclb_policy = lb_calld->grpclb_policy(); GPR_ASSERT(lb_calld->lb_call_ != nullptr); - if (grpc_lb_glb_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { char* status_details = grpc_slice_to_c_string(lb_calld->lb_call_status_details_); gpr_log(GPR_INFO, @@ -1129,13 +1143,13 @@ void GrpcLb::BalancerCallState::OnBalancerStatusReceivedLocked( // we want to retry connecting. Otherwise, we have deliberately ended this // call and no further action is required. if (lb_calld == grpclb_policy->lb_calld_.get()) { - // If we did not receive a serverlist and the fallback-at-startup checks - // are pending, go into fallback mode immediately. This short-circuits - // the timeout for the fallback-at-startup case. - if (!lb_calld->seen_serverlist_ && - grpclb_policy->fallback_at_startup_checks_pending_) { + // If the fallback-at-startup checks are pending, go into fallback mode + // immediately. This short-circuits the timeout for the fallback-at-startup + // case. + if (grpclb_policy->fallback_at_startup_checks_pending_) { + GPR_ASSERT(!lb_calld->seen_serverlist_); gpr_log(GPR_INFO, - "[grpclb %p] balancer call finished without receiving " + "[grpclb %p] Balancer call finished without receiving " "serverlist; entering fallback mode", grpclb_policy); grpclb_policy->fallback_at_startup_checks_pending_ = false; @@ -1277,7 +1291,7 @@ GrpcLb::GrpcLb(Args args) grpc_uri* uri = grpc_uri_parse(server_uri, true); GPR_ASSERT(uri->path[0] != '\0'); server_name_ = gpr_strdup(uri->path[0] == '/' ? uri->path + 1 : uri->path); - if (grpc_lb_glb_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { gpr_log(GPR_INFO, "[grpclb %p] Will use '%s' as the server name for LB request.", this, server_name_); @@ -1373,7 +1387,13 @@ void GrpcLb::FillChildRefsForChannelz( void GrpcLb::UpdateLocked(UpdateArgs args) { const bool is_initial_update = lb_channel_ == nullptr; - ParseLbConfig(args.config.get()); + auto* grpclb_config = + static_cast(args.config.get()); + if (grpclb_config != nullptr) { + child_policy_config_ = grpclb_config->child_policy(); + } else { + child_policy_config_ = nullptr; + } ProcessAddressesAndChannelArgsLocked(args.addresses, *args.args); // Update the existing child policy. if (child_policy_ != nullptr) CreateOrUpdateChildPolicyLocked(); @@ -1462,27 +1482,6 @@ void GrpcLb::ProcessAddressesAndChannelArgsLocked( response_generator_->SetResponse(std::move(result)); } -void GrpcLb::ParseLbConfig(Config* grpclb_config) { - const grpc_json* child_policy = nullptr; - if (grpclb_config != nullptr) { - const grpc_json* grpclb_config_json = grpclb_config->config(); - for (const grpc_json* field = grpclb_config_json; field != nullptr; - field = field->next) { - if (field->key == nullptr) return; - if (strcmp(field->key, "childPolicy") == 0) { - if (child_policy != nullptr) return; // Duplicate. - child_policy = ParseLoadBalancingConfig(field); - } - } - } - if (child_policy != nullptr) { - child_policy_config_ = - MakeRefCounted(child_policy, grpclb_config->service_config()); - } else { - child_policy_config_.reset(); - } -} - void GrpcLb::OnBalancerChannelConnectivityChangedLocked(void* arg, grpc_error* error) { GrpcLb* self = static_cast(arg); @@ -1536,7 +1535,7 @@ void GrpcLb::StartBalancerCallLocked() { // Init the LB call data. GPR_ASSERT(lb_calld_ == nullptr); lb_calld_ = MakeOrphanable(Ref()); - if (grpc_lb_glb_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { gpr_log(GPR_INFO, "[grpclb %p] Query for backends (lb_channel: %p, lb_calld: %p)", this, lb_channel_, lb_calld_.get()); @@ -1546,7 +1545,7 @@ void GrpcLb::StartBalancerCallLocked() { void GrpcLb::StartBalancerCallRetryTimerLocked() { grpc_millis next_try = lb_call_backoff_.NextAttemptTime(); - if (grpc_lb_glb_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { gpr_log(GPR_INFO, "[grpclb %p] Connection to LB server lost...", this); grpc_millis timeout = next_try - ExecCtx::Get()->Now(); if (timeout > 0) { @@ -1573,7 +1572,7 @@ void GrpcLb::OnBalancerCallRetryTimerLocked(void* arg, grpc_error* error) { grpclb_policy->retry_timer_callback_pending_ = false; if (!grpclb_policy->shutting_down_ && error == GRPC_ERROR_NONE && grpclb_policy->lb_calld_ == nullptr) { - if (grpc_lb_glb_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { gpr_log(GPR_INFO, "[grpclb %p] Restarting call to LB server", grpclb_policy); } @@ -1628,20 +1627,16 @@ void GrpcLb::OnFallbackTimerLocked(void* arg, grpc_error* error) { grpc_channel_args* GrpcLb::CreateChildPolicyArgsLocked( bool is_backend_from_grpclb_load_balancer) { - grpc_arg args_to_add[2] = { - // A channel arg indicating if the target is a backend inferred from a - // grpclb load balancer. - grpc_channel_arg_integer_create( - const_cast( - GRPC_ARG_ADDRESS_IS_BACKEND_FROM_GRPCLB_LOAD_BALANCER), - is_backend_from_grpclb_load_balancer), - }; - size_t num_args_to_add = 1; + InlinedVector args_to_add; + args_to_add.emplace_back(grpc_channel_arg_integer_create( + const_cast(GRPC_ARG_ADDRESS_IS_BACKEND_FROM_GRPCLB_LOAD_BALANCER), + is_backend_from_grpclb_load_balancer)); if (is_backend_from_grpclb_load_balancer) { - args_to_add[num_args_to_add++] = grpc_channel_arg_integer_create( - const_cast(GRPC_ARG_INHIBIT_HEALTH_CHECKING), 1); + args_to_add.emplace_back(grpc_channel_arg_integer_create( + const_cast(GRPC_ARG_INHIBIT_HEALTH_CHECKING), 1)); } - return grpc_channel_args_copy_and_add(args_, args_to_add, num_args_to_add); + return grpc_channel_args_copy_and_add(args_, args_to_add.data(), + args_to_add.size()); } OrphanablePtr GrpcLb::CreateChildPolicyLocked( @@ -1661,7 +1656,7 @@ OrphanablePtr GrpcLb::CreateChildPolicyLocked( return nullptr; } helper->set_child(lb_policy.get()); - if (grpc_lb_glb_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { gpr_log(GPR_INFO, "[grpclb %p] Created new child policy %s (%p)", this, name, lb_policy.get()); } @@ -1760,7 +1755,7 @@ void GrpcLb::CreateOrUpdateChildPolicyLocked() { // Cases 1, 2b, and 3b: create a new child policy. // If child_policy_ is null, we set it (case 1), else we set // pending_child_policy_ (cases 2b and 3b). - if (grpc_lb_glb_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { gpr_log(GPR_INFO, "[grpclb %p] Creating new %schild policy %s", this, child_policy_ == nullptr ? "" : "pending ", child_policy_name); } @@ -1784,7 +1779,7 @@ void GrpcLb::CreateOrUpdateChildPolicyLocked() { } GPR_ASSERT(policy_to_update != nullptr); // Update the policy. - if (grpc_lb_glb_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_glb_trace)) { gpr_log(GPR_INFO, "[grpclb %p] Updating %schild policy %p", this, policy_to_update == pending_child_policy_.get() ? "pending " : "", policy_to_update); @@ -1804,6 +1799,40 @@ class GrpcLbFactory : public LoadBalancingPolicyFactory { } const char* name() const override { return kGrpclb; } + + RefCountedPtr ParseLoadBalancingConfig( + const grpc_json* json, grpc_error** error) const override { + GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE); + if (json == nullptr) { + return RefCountedPtr( + New(nullptr)); + } + InlinedVector error_list; + RefCountedPtr child_policy; + for (const grpc_json* field = json->child; field != nullptr; + field = field->next) { + if (field->key == nullptr) continue; + if (strcmp(field->key, "childPolicy") == 0) { + if (child_policy != nullptr) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:childPolicy error:Duplicate entry")); + } + grpc_error* parse_error = GRPC_ERROR_NONE; + child_policy = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig( + field, &parse_error); + if (parse_error != GRPC_ERROR_NONE) { + error_list.push_back(parse_error); + } + } + } + if (error_list.empty()) { + return RefCountedPtr( + New(std::move(child_policy))); + } else { + *error = GRPC_ERROR_CREATE_FROM_VECTOR("GrpcLb Parser", &error_list); + return nullptr; + } + } }; } // namespace diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index 637806b4804..199e973e72c 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -68,9 +68,8 @@ class PickFirst : public LoadBalancingPolicy { PickFirstSubchannelData( SubchannelList* subchannel_list, - const ServerAddress& address, Subchannel* subchannel, - grpc_combiner* combiner) - : SubchannelData(subchannel_list, address, subchannel, combiner) {} + const ServerAddress& address, Subchannel* subchannel) + : SubchannelData(subchannel_list, address, subchannel) {} void ProcessConnectivityChangeLocked( grpc_connectivity_state connectivity_state) override; @@ -160,13 +159,13 @@ class PickFirst : public LoadBalancingPolicy { }; PickFirst::PickFirst(Args args) : LoadBalancingPolicy(std::move(args)) { - if (grpc_lb_pick_first_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { gpr_log(GPR_INFO, "Pick First %p created.", this); } } PickFirst::~PickFirst() { - if (grpc_lb_pick_first_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { gpr_log(GPR_INFO, "Destroying Pick First %p", this); } GPR_ASSERT(subchannel_list_ == nullptr); @@ -175,7 +174,7 @@ PickFirst::~PickFirst() { void PickFirst::ShutdownLocked() { AutoChildRefsUpdater guard(this); - if (grpc_lb_pick_first_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { gpr_log(GPR_INFO, "Pick First %p Shutting down", this); } shutdown_ = true; @@ -245,7 +244,7 @@ void PickFirst::UpdateChildRefsLocked() { void PickFirst::UpdateLocked(UpdateArgs args) { AutoChildRefsUpdater guard(this); - if (grpc_lb_pick_first_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { gpr_log(GPR_INFO, "Pick First %p received update with %" PRIuPTR " addresses", this, args.addresses.size()); @@ -312,12 +311,13 @@ void PickFirst::UpdateLocked(UpdateArgs args) { // here, since we've already checked the initial connectivity // state of all subchannels above. subchannel_list_->subchannel(0)->StartConnectivityWatchLocked(); + subchannel_list_->subchannel(0)->subchannel()->AttemptToConnect(); } } else { // We do have a selected subchannel (which means it's READY), so keep // using it until one of the subchannels in the new list reports READY. if (latest_pending_subchannel_list_ != nullptr) { - if (grpc_lb_pick_first_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { gpr_log(GPR_INFO, "Pick First %p Shutting down latest pending subchannel list " "%p, about to be replaced by newer latest %p", @@ -334,6 +334,9 @@ void PickFirst::UpdateLocked(UpdateArgs args) { // state of all subchannels above. latest_pending_subchannel_list_->subchannel(0) ->StartConnectivityWatchLocked(); + latest_pending_subchannel_list_->subchannel(0) + ->subchannel() + ->AttemptToConnect(); } } } @@ -349,7 +352,7 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( GPR_ASSERT(connectivity_state != GRPC_CHANNEL_SHUTDOWN); // Handle updates for the currently selected subchannel. if (p->selected_ == this) { - if (grpc_lb_pick_first_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { gpr_log(GPR_INFO, "Pick First %p selected subchannel connectivity changed to %s", p, grpc_connectivity_state_name(connectivity_state)); @@ -358,7 +361,7 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( // pending update, switch to the pending update. if (connectivity_state != GRPC_CHANNEL_READY && p->latest_pending_subchannel_list_ != nullptr) { - if (grpc_lb_pick_first_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { gpr_log(GPR_INFO, "Pick First %p promoting pending subchannel list %p to " "replace %p", @@ -366,7 +369,8 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( p->subchannel_list_.get()); } p->selected_ = nullptr; - StopConnectivityWatchLocked(); + CancelConnectivityWatchLocked( + "selected subchannel failed; switching to pending update"); p->subchannel_list_ = std::move(p->latest_pending_subchannel_list_); // Set our state to that of the pending subchannel list. if (p->subchannel_list_->in_transient_failure()) { @@ -391,7 +395,7 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( p->idle_ = true; p->channel_control_helper()->RequestReresolution(); p->selected_ = nullptr; - StopConnectivityWatchLocked(); + CancelConnectivityWatchLocked("selected subchannel failed; going IDLE"); p->channel_control_helper()->UpdateState( GRPC_CHANNEL_IDLE, UniquePtr(New(p->Ref()))); @@ -408,8 +412,6 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( connectivity_state, UniquePtr(New(p->Ref()))); } - // Renew notification. - RenewConnectivityWatchLocked(); } } return; @@ -426,13 +428,11 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( subchannel_list()->set_in_transient_failure(false); switch (connectivity_state) { case GRPC_CHANNEL_READY: { - // Renew notification. - RenewConnectivityWatchLocked(); ProcessUnselectedReadyLocked(); break; } case GRPC_CHANNEL_TRANSIENT_FAILURE: { - StopConnectivityWatchLocked(); + CancelConnectivityWatchLocked("connection attempt failed"); PickFirstSubchannelData* sd = this; size_t next_index = (sd->Index() + 1) % subchannel_list()->num_subchannels(); @@ -468,8 +468,6 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( GRPC_CHANNEL_CONNECTING, UniquePtr(New(p->Ref()))); } - // Renew notification. - RenewConnectivityWatchLocked(); break; } case GRPC_CHANNEL_SHUTDOWN: @@ -492,7 +490,7 @@ void PickFirst::PickFirstSubchannelData::ProcessUnselectedReadyLocked() { subchannel_list() == p->latest_pending_subchannel_list_.get()); // Case 2. Promote p->latest_pending_subchannel_list_ to p->subchannel_list_. if (subchannel_list() == p->latest_pending_subchannel_list_.get()) { - if (grpc_lb_pick_first_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { gpr_log(GPR_INFO, "Pick First %p promoting pending subchannel list %p to " "replace %p", @@ -506,7 +504,7 @@ void PickFirst::PickFirstSubchannelData::ProcessUnselectedReadyLocked() { p->channel_control_helper()->UpdateState( GRPC_CHANNEL_READY, UniquePtr(New(connected_subchannel()->Ref()))); - if (grpc_lb_pick_first_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", p, subchannel()); } } @@ -521,11 +519,19 @@ void PickFirst::PickFirstSubchannelData:: // If current state is READY, select the subchannel now, since we started // watching from this state and will not get a notification of it // transitioning into this state. - if (p->selected_ != this && current_state == GRPC_CHANNEL_READY) { - ProcessUnselectedReadyLocked(); + // If the current state is not READY, attempt to connect. + if (current_state == GRPC_CHANNEL_READY) { + if (p->selected_ != this) ProcessUnselectedReadyLocked(); + } else { + subchannel()->AttemptToConnect(); } } +class ParsedPickFirstConfig : public ParsedLoadBalancingConfig { + public: + const char* name() const override { return kPickFirst; } +}; + // // factory // @@ -538,6 +544,15 @@ class PickFirstFactory : public LoadBalancingPolicyFactory { } const char* name() const override { return kPickFirst; } + + RefCountedPtr ParseLoadBalancingConfig( + const grpc_json* json, grpc_error** error) const override { + if (json != nullptr) { + GPR_DEBUG_ASSERT(strcmp(json->key, name()) == 0); + } + return RefCountedPtr( + New()); + } }; } // namespace diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc index b913333fb45..1693032ea24 100644 --- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc @@ -83,9 +83,8 @@ class RoundRobin : public LoadBalancingPolicy { RoundRobinSubchannelData( SubchannelList* subchannel_list, - const ServerAddress& address, Subchannel* subchannel, - grpc_combiner* combiner) - : SubchannelData(subchannel_list, address, subchannel, combiner) {} + const ServerAddress& address, Subchannel* subchannel) + : SubchannelData(subchannel_list, address, subchannel) {} grpc_connectivity_state connectivity_state() const { return last_connectivity_state_; @@ -212,7 +211,7 @@ RoundRobin::Picker::Picker(RoundRobin* parent, // TODO(roth): rand(3) is not thread-safe. This should be replaced with // something better as part of https://github.com/grpc/grpc/issues/17891. last_picked_index_ = rand() % subchannels_.size(); - if (grpc_lb_round_robin_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) { gpr_log(GPR_INFO, "[RR %p picker %p] created picker from subchannel_list=%p " "with %" PRIuPTR " READY subchannels; last_picked_index_=%" PRIuPTR, @@ -224,7 +223,7 @@ RoundRobin::Picker::Picker(RoundRobin* parent, RoundRobin::PickResult RoundRobin::Picker::Pick(PickArgs* pick, grpc_error** error) { last_picked_index_ = (last_picked_index_ + 1) % subchannels_.size(); - if (grpc_lb_round_robin_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) { gpr_log(GPR_INFO, "[RR %p picker %p] returning index %" PRIuPTR ", connected_subchannel=%p", @@ -240,13 +239,13 @@ RoundRobin::PickResult RoundRobin::Picker::Pick(PickArgs* pick, // RoundRobin::RoundRobin(Args args) : LoadBalancingPolicy(std::move(args)) { - if (grpc_lb_round_robin_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) { gpr_log(GPR_INFO, "[RR %p] Created", this); } } RoundRobin::~RoundRobin() { - if (grpc_lb_round_robin_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) { gpr_log(GPR_INFO, "[RR %p] Destroying Round Robin policy", this); } GPR_ASSERT(subchannel_list_ == nullptr); @@ -255,7 +254,7 @@ RoundRobin::~RoundRobin() { void RoundRobin::ShutdownLocked() { AutoChildRefsUpdater guard(this); - if (grpc_lb_round_robin_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) { gpr_log(GPR_INFO, "[RR %p] Shutting down", this); } shutdown_ = true; @@ -320,6 +319,7 @@ void RoundRobin::RoundRobinSubchannelList::StartWatchingLocked() { for (size_t i = 0; i < num_subchannels(); i++) { if (subchannel(i)->subchannel() != nullptr) { subchannel(i)->StartConnectivityWatchLocked(); + subchannel(i)->subchannel()->AttemptToConnect(); } } // Now set the LB policy's state based on the subchannels' states. @@ -403,7 +403,7 @@ void RoundRobin::RoundRobinSubchannelList:: // therefore we would not be receiving a notification for them. GPR_ASSERT(p->latest_pending_subchannel_list_.get() == this); GPR_ASSERT(!shutting_down()); - if (grpc_lb_round_robin_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) { const size_t old_num_subchannels = p->subchannel_list_ != nullptr ? p->subchannel_list_->num_subchannels() @@ -424,7 +424,7 @@ void RoundRobin::RoundRobinSubchannelList:: void RoundRobin::RoundRobinSubchannelData::UpdateConnectivityStateLocked( grpc_connectivity_state connectivity_state) { RoundRobin* p = static_cast(subchannel_list()->policy()); - if (grpc_lb_round_robin_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) { gpr_log( GPR_INFO, "[RR %p] connectivity changed for subchannel %p, subchannel_list %p " @@ -448,17 +448,17 @@ void RoundRobin::RoundRobinSubchannelData::ProcessConnectivityChangeLocked( // Otherwise, if the subchannel was already in state TRANSIENT_FAILURE // when the subchannel list was created, we'd wind up in a constant // loop of re-resolution. + // Also attempt to reconnect. if (connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { - if (grpc_lb_round_robin_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) { gpr_log(GPR_INFO, "[RR %p] Subchannel %p has gone into TRANSIENT_FAILURE. " "Requesting re-resolution", p, subchannel()); } p->channel_control_helper()->RequestReresolution(); + subchannel()->AttemptToConnect(); } - // Renew connectivity watch. - RenewConnectivityWatchLocked(); // Update state counters. UpdateConnectivityStateLocked(connectivity_state); // Update overall state and renew notification. @@ -467,13 +467,13 @@ void RoundRobin::RoundRobinSubchannelData::ProcessConnectivityChangeLocked( void RoundRobin::UpdateLocked(UpdateArgs args) { AutoChildRefsUpdater guard(this); - if (grpc_lb_round_robin_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) { gpr_log(GPR_INFO, "[RR %p] received update with %" PRIuPTR " addresses", this, args.addresses.size()); } // Replace latest_pending_subchannel_list_. if (latest_pending_subchannel_list_ != nullptr) { - if (grpc_lb_round_robin_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_round_robin_trace)) { gpr_log(GPR_INFO, "[RR %p] Shutting down previous pending subchannel list %p", this, latest_pending_subchannel_list_.get()); @@ -503,6 +503,11 @@ void RoundRobin::UpdateLocked(UpdateArgs args) { } } +class ParsedRoundRobinConfig : public ParsedLoadBalancingConfig { + public: + const char* name() const override { return kRoundRobin; } +}; + // // factory // @@ -515,6 +520,15 @@ class RoundRobinFactory : public LoadBalancingPolicyFactory { } const char* name() const override { return kRoundRobin; } + + RefCountedPtr ParseLoadBalancingConfig( + const grpc_json* json, grpc_error** error) const override { + if (json != nullptr) { + GPR_DEBUG_ASSERT(strcmp(json->key, name()) == 0); + } + return RefCountedPtr( + New()); + } }; } // namespace diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h index 004ee04459b..93b4bbd369a 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h @@ -98,15 +98,13 @@ class SubchannelData { // Synchronously checks the subchannel's connectivity state. // Must not be called while there is a connectivity notification - // pending (i.e., between calling StartConnectivityWatchLocked() or - // RenewConnectivityWatchLocked() and the resulting invocation of - // ProcessConnectivityChangeLocked()). + // pending (i.e., between calling StartConnectivityWatchLocked() and + // calling CancelConnectivityWatchLocked()). grpc_connectivity_state CheckConnectivityStateLocked() { - GPR_ASSERT(!connectivity_notification_pending_); - pending_connectivity_state_unsafe_ = subchannel()->CheckConnectivity( - subchannel_list_->inhibit_health_checking()); - UpdateConnectedSubchannelLocked(); - return pending_connectivity_state_unsafe_; + GPR_ASSERT(pending_watcher_ == nullptr); + connectivity_state_ = subchannel()->CheckConnectivityState( + subchannel_list_->health_check_service_name(), &connected_subchannel_); + return connectivity_state_; } // Resets the connection backoff. @@ -115,23 +113,11 @@ class SubchannelData { void ResetBackoffLocked(); // Starts watching the connectivity state of the subchannel. - // ProcessConnectivityChangeLocked() will be called when the + // ProcessConnectivityChangeLocked() will be called whenever the // connectivity state changes. void StartConnectivityWatchLocked(); - // Renews watching the connectivity state of the subchannel. - void RenewConnectivityWatchLocked(); - - // Stops watching the connectivity state of the subchannel. - void StopConnectivityWatchLocked(); - // Cancels watching the connectivity state of the subchannel. - // Must be called only while there is a connectivity notification - // pending (i.e., between calling StartConnectivityWatchLocked() or - // RenewConnectivityWatchLocked() and the resulting invocation of - // ProcessConnectivityChangeLocked()). - // From within ProcessConnectivityChangeLocked(), use - // StopConnectivityWatchLocked() instead. void CancelConnectivityWatchLocked(const char* reason); // Cancels any pending connectivity watch and unrefs the subchannel. @@ -142,44 +128,80 @@ class SubchannelData { protected: SubchannelData( SubchannelList* subchannel_list, - const ServerAddress& address, Subchannel* subchannel, - grpc_combiner* combiner); + const ServerAddress& address, Subchannel* subchannel); virtual ~SubchannelData(); - // After StartConnectivityWatchLocked() or RenewConnectivityWatchLocked() - // is called, this method will be invoked when the subchannel's connectivity - // state changes. - // Implementations must invoke either RenewConnectivityWatchLocked() or - // StopConnectivityWatchLocked() before returning. + // After StartConnectivityWatchLocked() is called, this method will be + // invoked whenever the subchannel's connectivity state changes. + // To stop watching, use CancelConnectivityWatchLocked(). virtual void ProcessConnectivityChangeLocked( grpc_connectivity_state connectivity_state) GRPC_ABSTRACT; - // Unrefs the subchannel. - void UnrefSubchannelLocked(const char* reason); - private: - // Updates connected_subchannel_ based on pending_connectivity_state_unsafe_. - // Returns true if the connectivity state should be reported. - bool UpdateConnectedSubchannelLocked(); + // Watcher for subchannel connectivity state. + class Watcher : public Subchannel::ConnectivityStateWatcher { + public: + Watcher( + SubchannelData* subchannel_data, + RefCountedPtr subchannel_list) + : subchannel_data_(subchannel_data), + subchannel_list_(std::move(subchannel_list)) {} + + ~Watcher() { subchannel_list_.reset(DEBUG_LOCATION, "Watcher dtor"); } + + void OnConnectivityStateChange( + grpc_connectivity_state new_state, + RefCountedPtr connected_subchannel) override; + + grpc_pollset_set* interested_parties() override { + return subchannel_list_->policy()->interested_parties(); + } + + private: + // A fire-and-forget class that bounces into the combiner to process + // a connectivity state update. + class Updater { + public: + Updater( + SubchannelData* + subchannel_data, + RefCountedPtr> + subchannel_list, + grpc_connectivity_state state, + RefCountedPtr connected_subchannel); + + ~Updater() { + subchannel_list_.reset(DEBUG_LOCATION, "Watcher::Updater dtor"); + } + + private: + static void OnUpdateLocked(void* arg, grpc_error* error); - static void OnConnectivityChangedLocked(void* arg, grpc_error* error); + SubchannelData* subchannel_data_; + RefCountedPtr> + subchannel_list_; + const grpc_connectivity_state state_; + RefCountedPtr connected_subchannel_; + grpc_closure closure_; + }; + + SubchannelData* subchannel_data_; + RefCountedPtr subchannel_list_; + }; + + // Unrefs the subchannel. + void UnrefSubchannelLocked(const char* reason); // Backpointer to owning subchannel list. Not owned. SubchannelList* subchannel_list_; - - // The subchannel and connected subchannel. + // The subchannel. Subchannel* subchannel_; + // Will be non-null when the subchannel's state is being watched. + Subchannel::ConnectivityStateWatcher* pending_watcher_ = nullptr; + // Data updated by the watcher. + grpc_connectivity_state connectivity_state_; RefCountedPtr connected_subchannel_; - - // Notification that connectivity has changed on subchannel. - grpc_closure connectivity_changed_closure_; - // Is a connectivity notification pending? - bool connectivity_notification_pending_ = false; - // Connectivity state to be updated by - // grpc_subchannel_notify_on_state_change(), not guarded by - // the combiner. - grpc_connectivity_state pending_connectivity_state_unsafe_; }; // A list of subchannels. @@ -213,7 +235,9 @@ class SubchannelList : public InternallyRefCounted { // Accessors. LoadBalancingPolicy* policy() const { return policy_; } TraceFlag* tracer() const { return tracer_; } - bool inhibit_health_checking() const { return inhibit_health_checking_; } + const char* health_check_service_name() const { + return health_check_service_name_.get(); + } // Resets connection backoff of all subchannels. // TODO(roth): We will probably need to rethink this as part of moving @@ -251,7 +275,7 @@ class SubchannelList : public InternallyRefCounted { TraceFlag* tracer_; - bool inhibit_health_checking_; + UniquePtr health_check_service_name_; grpc_combiner* combiner_; @@ -268,6 +292,67 @@ class SubchannelList : public InternallyRefCounted { // implementation -- no user-servicable parts below // +// +// SubchannelData::Watcher +// + +template +void SubchannelData::Watcher:: + OnConnectivityStateChange( + grpc_connectivity_state new_state, + RefCountedPtr connected_subchannel) { + // Will delete itself. + New(subchannel_data_, + subchannel_list_->Ref(DEBUG_LOCATION, "Watcher::Updater"), + new_state, std::move(connected_subchannel)); +} + +template +SubchannelData::Watcher::Updater:: + Updater( + SubchannelData* subchannel_data, + RefCountedPtr> + subchannel_list, + grpc_connectivity_state state, + RefCountedPtr connected_subchannel) + : subchannel_data_(subchannel_data), + subchannel_list_(std::move(subchannel_list)), + state_(state), + connected_subchannel_(std::move(connected_subchannel)) { + GRPC_CLOSURE_INIT(&closure_, &OnUpdateLocked, this, + grpc_combiner_scheduler(subchannel_list_->combiner_)); + GRPC_CLOSURE_SCHED(&closure_, GRPC_ERROR_NONE); +} + +template +void SubchannelData::Watcher::Updater:: + OnUpdateLocked(void* arg, grpc_error* error) { + Updater* self = static_cast(arg); + SubchannelData* sd = self->subchannel_data_; + if (GRPC_TRACE_FLAG_ENABLED(*sd->subchannel_list_->tracer())) { + gpr_log(GPR_INFO, + "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR + " (subchannel %p): connectivity changed: state=%s, " + "connected_subchannel=%p, shutting_down=%d, pending_watcher=%p", + sd->subchannel_list_->tracer()->name(), + sd->subchannel_list_->policy(), sd->subchannel_list_, sd->Index(), + sd->subchannel_list_->num_subchannels(), sd->subchannel_, + grpc_connectivity_state_name(self->state_), + self->connected_subchannel_.get(), + sd->subchannel_list_->shutting_down(), sd->pending_watcher_); + } + if (!sd->subchannel_list_->shutting_down() && + sd->pending_watcher_ != nullptr) { + sd->connectivity_state_ = self->state_; + // Get or release ref to connected subchannel. + sd->connected_subchannel_ = std::move(self->connected_subchannel_); + // Call the subclass's ProcessConnectivityChangeLocked() method. + sd->ProcessConnectivityChangeLocked(sd->connectivity_state_); + } + // Clean up. + Delete(self); +} + // // SubchannelData // @@ -275,30 +360,23 @@ class SubchannelList : public InternallyRefCounted { template SubchannelData::SubchannelData( SubchannelList* subchannel_list, - const ServerAddress& address, Subchannel* subchannel, - grpc_combiner* combiner) + const ServerAddress& address, Subchannel* subchannel) : subchannel_list_(subchannel_list), subchannel_(subchannel), // We assume that the current state is IDLE. If not, we'll get a // callback telling us that. - pending_connectivity_state_unsafe_(GRPC_CHANNEL_IDLE) { - GRPC_CLOSURE_INIT( - &connectivity_changed_closure_, - (&SubchannelData::OnConnectivityChangedLocked), - this, grpc_combiner_scheduler(combiner)); -} + connectivity_state_(GRPC_CHANNEL_IDLE) {} template SubchannelData::~SubchannelData() { - UnrefSubchannelLocked("subchannel_data_destroy"); + GPR_ASSERT(subchannel_ == nullptr); } template void SubchannelData:: UnrefSubchannelLocked(const char* reason) { if (subchannel_ != nullptr) { - if (subchannel_list_->tracer()->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*subchannel_list_->tracer())) { gpr_log(GPR_INFO, "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR " (subchannel %p): unreffing subchannel", @@ -323,65 +401,28 @@ void SubchannelData void SubchannelData::StartConnectivityWatchLocked() { - if (subchannel_list_->tracer()->enabled()) { - gpr_log(GPR_INFO, - "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR - " (subchannel %p): starting watch: requesting connectivity change " - "notification (from %s)", - subchannel_list_->tracer()->name(), subchannel_list_->policy(), - subchannel_list_, Index(), subchannel_list_->num_subchannels(), - subchannel_, - grpc_connectivity_state_name(pending_connectivity_state_unsafe_)); - } - GPR_ASSERT(!connectivity_notification_pending_); - connectivity_notification_pending_ = true; - subchannel_list()->Ref(DEBUG_LOCATION, "connectivity_watch").release(); - subchannel_->NotifyOnStateChange( - subchannel_list_->policy()->interested_parties(), - &pending_connectivity_state_unsafe_, &connectivity_changed_closure_, - subchannel_list_->inhibit_health_checking()); -} - -template -void SubchannelData::RenewConnectivityWatchLocked() { - if (subchannel_list_->tracer()->enabled()) { - gpr_log(GPR_INFO, - "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR - " (subchannel %p): renewing watch: requesting connectivity change " - "notification (from %s)", - subchannel_list_->tracer()->name(), subchannel_list_->policy(), - subchannel_list_, Index(), subchannel_list_->num_subchannels(), - subchannel_, - grpc_connectivity_state_name(pending_connectivity_state_unsafe_)); - } - GPR_ASSERT(connectivity_notification_pending_); - subchannel_->NotifyOnStateChange( - subchannel_list_->policy()->interested_parties(), - &pending_connectivity_state_unsafe_, &connectivity_changed_closure_, - subchannel_list_->inhibit_health_checking()); -} - -template -void SubchannelData::StopConnectivityWatchLocked() { - if (subchannel_list_->tracer()->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*subchannel_list_->tracer())) { gpr_log(GPR_INFO, "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR - " (subchannel %p): stopping connectivity watch", + " (subchannel %p): starting watch (from %s)", subchannel_list_->tracer()->name(), subchannel_list_->policy(), subchannel_list_, Index(), subchannel_list_->num_subchannels(), - subchannel_); + subchannel_, grpc_connectivity_state_name(connectivity_state_)); } - GPR_ASSERT(connectivity_notification_pending_); - connectivity_notification_pending_ = false; - subchannel_list()->Unref(DEBUG_LOCATION, "connectivity_watch"); + GPR_ASSERT(pending_watcher_ == nullptr); + pending_watcher_ = + New(this, subchannel_list()->Ref(DEBUG_LOCATION, "Watcher")); + subchannel_->WatchConnectivityState( + connectivity_state_, + UniquePtr( + gpr_strdup(subchannel_list_->health_check_service_name())), + UniquePtr(pending_watcher_)); } template void SubchannelData:: CancelConnectivityWatchLocked(const char* reason) { - if (subchannel_list_->tracer()->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*subchannel_list_->tracer())) { gpr_log(GPR_INFO, "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR " (subchannel %p): canceling connectivity watch (%s)", @@ -389,91 +430,17 @@ void SubchannelData:: subchannel_list_, Index(), subchannel_list_->num_subchannels(), subchannel_, reason); } - GPR_ASSERT(connectivity_notification_pending_); - subchannel_->NotifyOnStateChange(nullptr, nullptr, - &connectivity_changed_closure_, - subchannel_list_->inhibit_health_checking()); -} - -template -bool SubchannelData::UpdateConnectedSubchannelLocked() { - // If the subchannel is READY, take a ref to the connected subchannel. - if (pending_connectivity_state_unsafe_ == GRPC_CHANNEL_READY) { - connected_subchannel_ = subchannel_->connected_subchannel(); - // If the subchannel became disconnected between the time that READY - // was reported and the time we got here (e.g., between when a - // notification callback is scheduled and when it was actually run in - // the combiner), then the connected subchannel may have disappeared out - // from under us. In that case, we don't actually want to consider the - // subchannel to be in state READY. Instead, we use IDLE as the - // basis for any future connectivity watch; this is the one state that - // the subchannel will never transition back into, so this ensures - // that we will get a notification for the next state, even if that state - // is READY again (e.g., if the subchannel has transitioned back to - // READY before the next watch gets requested). - if (connected_subchannel_ == nullptr) { - if (subchannel_list_->tracer()->enabled()) { - gpr_log(GPR_INFO, - "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR - " (subchannel %p): state is READY but connected subchannel is " - "null; moving to state IDLE", - subchannel_list_->tracer()->name(), subchannel_list_->policy(), - subchannel_list_, Index(), subchannel_list_->num_subchannels(), - subchannel_); - } - pending_connectivity_state_unsafe_ = GRPC_CHANNEL_IDLE; - return false; - } - } else { - // For any state other than READY, unref the connected subchannel. - connected_subchannel_.reset(); - } - return true; -} - -template -void SubchannelData:: - OnConnectivityChangedLocked(void* arg, grpc_error* error) { - SubchannelData* sd = static_cast(arg); - if (sd->subchannel_list_->tracer()->enabled()) { - gpr_log( - GPR_INFO, - "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR - " (subchannel %p): connectivity changed: state=%s, error=%s, " - "shutting_down=%d", - sd->subchannel_list_->tracer()->name(), sd->subchannel_list_->policy(), - sd->subchannel_list_, sd->Index(), - sd->subchannel_list_->num_subchannels(), sd->subchannel_, - grpc_connectivity_state_name(sd->pending_connectivity_state_unsafe_), - grpc_error_string(error), sd->subchannel_list_->shutting_down()); - } - // If shutting down, unref subchannel and stop watching. - if (sd->subchannel_list_->shutting_down() || error == GRPC_ERROR_CANCELLED) { - sd->UnrefSubchannelLocked("connectivity_shutdown"); - sd->StopConnectivityWatchLocked(); - return; - } - // Get or release ref to connected subchannel. - if (!sd->UpdateConnectedSubchannelLocked()) { - // We don't want to report this connectivity state, so renew the watch. - sd->RenewConnectivityWatchLocked(); - return; + if (pending_watcher_ != nullptr) { + subchannel_->CancelConnectivityStateWatch( + subchannel_list_->health_check_service_name(), pending_watcher_); + pending_watcher_ = nullptr; } - // Call the subclass's ProcessConnectivityChangeLocked() method. - sd->ProcessConnectivityChangeLocked(sd->pending_connectivity_state_unsafe_); } template void SubchannelData::ShutdownLocked() { - // If there's a pending notification for this subchannel, cancel it; - // the callback is responsible for unreffing the subchannel. - // Otherwise, unref the subchannel directly. - if (connectivity_notification_pending_) { - CancelConnectivityWatchLocked("shutdown"); - } else if (subchannel_ != nullptr) { - UnrefSubchannelLocked("shutdown"); - } + if (pending_watcher_ != nullptr) CancelConnectivityWatchLocked("shutdown"); + UnrefSubchannelLocked("shutdown"); } // @@ -490,23 +457,40 @@ SubchannelList::SubchannelList( policy_(policy), tracer_(tracer), combiner_(GRPC_COMBINER_REF(combiner, "subchannel_list")) { - if (tracer_->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) { gpr_log(GPR_INFO, "[%s %p] Creating subchannel list %p for %" PRIuPTR " subchannels", tracer_->name(), policy, this, addresses.size()); } subchannels_.reserve(addresses.size()); + // Find health check service name. + const bool inhibit_health_checking = grpc_channel_arg_get_bool( + grpc_channel_args_find(&args, GRPC_ARG_INHIBIT_HEALTH_CHECKING), false); + if (!inhibit_health_checking) { + const char* health_check_service_name = grpc_channel_arg_get_string( + grpc_channel_args_find(&args, "grpc.temp.health_check")); + if (health_check_service_name != nullptr) { + health_check_service_name_.reset(gpr_strdup(health_check_service_name)); + } + } // We need to remove the LB addresses in order to be able to compare the // subchannel keys of subchannels from a different batch of addresses. - // We also remove the inhibit-health-checking arg, since we are + // We also remove the health-checking-related args, since we are // handling that here. - inhibit_health_checking_ = grpc_channel_arg_get_bool( - grpc_channel_args_find(&args, GRPC_ARG_INHIBIT_HEALTH_CHECKING), false); - static const char* keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS, - GRPC_ARG_INHIBIT_HEALTH_CHECKING}; + // We remove the service config, since it will be passed into the + // subchannel via call context. + static const char* keys_to_remove[] = { + GRPC_ARG_SUBCHANNEL_ADDRESS, "grpc.temp.health_check", + GRPC_ARG_INHIBIT_HEALTH_CHECKING, GRPC_ARG_SERVICE_CONFIG}; // Create a subchannel for each address. for (size_t i = 0; i < addresses.size(); i++) { - GPR_ASSERT(!addresses[i].IsBalancer()); + // TODO(roth): we should ideally hide this from the LB policy code. In + // principle, if we're dealing with this special case in the client_channel + // code for selecting grpclb, then we should also strip out these addresses + // there if we're not using grpclb. + if (addresses[i].IsBalancer()) { + continue; + } InlinedVector args_to_add; const size_t subchannel_address_arg_index = args_to_add.size(); args_to_add.emplace_back( @@ -524,7 +508,7 @@ SubchannelList::SubchannelList( grpc_channel_args_destroy(new_args); if (subchannel == nullptr) { // Subchannel could not be created. - if (tracer_->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) { char* address_uri = grpc_sockaddr_to_uri(&addresses[i].address()); gpr_log(GPR_INFO, "[%s %p] could not create subchannel for address uri %s, " @@ -534,7 +518,7 @@ SubchannelList::SubchannelList( } continue; } - if (tracer_->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) { char* address_uri = grpc_sockaddr_to_uri(&addresses[i].address()); gpr_log(GPR_INFO, "[%s %p] subchannel list %p index %" PRIuPTR @@ -543,13 +527,13 @@ SubchannelList::SubchannelList( address_uri); gpr_free(address_uri); } - subchannels_.emplace_back(this, addresses[i], subchannel, combiner); + subchannels_.emplace_back(this, addresses[i], subchannel); } } template SubchannelList::~SubchannelList() { - if (tracer_->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) { gpr_log(GPR_INFO, "[%s %p] Destroying subchannel_list %p", tracer_->name(), policy_, this); } @@ -558,7 +542,7 @@ SubchannelList::~SubchannelList() { template void SubchannelList::ShutdownLocked() { - if (tracer_->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) { gpr_log(GPR_INFO, "[%s %p] Shutting down subchannel_list %p", tracer_->name(), policy_, this); } diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc index 000de59448b..819bad6c00d 100644 --- a/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc +++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc @@ -120,6 +120,33 @@ constexpr char kXds[] = "xds_experimental"; constexpr char kDefaultLocalityName[] = "xds_default_locality"; constexpr uint32_t kDefaultLocalityWeight = 3; +class ParsedXdsConfig : public ParsedLoadBalancingConfig { + public: + ParsedXdsConfig(const char* balancer_name, + RefCountedPtr child_policy, + RefCountedPtr fallback_policy) + : balancer_name_(balancer_name), + child_policy_(std::move(child_policy)), + fallback_policy_(std::move(fallback_policy)) {} + + const char* name() const override { return kXds; } + + const char* balancer_name() const { return balancer_name_; }; + + RefCountedPtr child_policy() const { + return child_policy_; + } + + RefCountedPtr fallback_policy() const { + return fallback_policy_; + } + + private: + const char* balancer_name_ = nullptr; + RefCountedPtr child_policy_; + RefCountedPtr fallback_policy_; +}; + class XdsLb : public LoadBalancingPolicy { public: explicit XdsLb(Args args); @@ -240,6 +267,10 @@ class XdsLb : public LoadBalancingPolicy { static void OnCallRetryTimerLocked(void* arg, grpc_error* error); void StartCallLocked(); + void StartConnectivityWatchLocked(); + void CancelConnectivityWatchLocked(); + static void OnConnectivityChangedLocked(void* arg, grpc_error* error); + private: // The owning LB policy. RefCountedPtr xdslb_policy_; @@ -247,6 +278,8 @@ class XdsLb : public LoadBalancingPolicy { // The channel and its status. grpc_channel* channel_; bool shutting_down_ = false; + grpc_connectivity_state connectivity_ = GRPC_CHANNEL_IDLE; + grpc_closure on_connectivity_changed_; // The data associated with the current LB call. It holds a ref to this LB // channel. It's instantiated every time we query for backends. It's reset @@ -299,6 +332,28 @@ class XdsLb : public LoadBalancingPolicy { PickerList pickers_; }; + class FallbackHelper : public ChannelControlHelper { + public: + explicit FallbackHelper(RefCountedPtr parent) + : parent_(std::move(parent)) {} + + Subchannel* CreateSubchannel(const grpc_channel_args& args) override; + grpc_channel* CreateChannel(const char* target, + const grpc_channel_args& args) override; + void UpdateState(grpc_connectivity_state state, + UniquePtr picker) override; + void RequestReresolution() override; + + void set_child(LoadBalancingPolicy* child) { child_ = child; } + + private: + bool CalledByPendingFallback() const; + bool CalledByCurrentFallback() const; + + RefCountedPtr parent_; + LoadBalancingPolicy* child_ = nullptr; + }; + class LocalityMap { public: class LocalityEntry : public InternallyRefCounted { @@ -308,7 +363,7 @@ class XdsLb : public LoadBalancingPolicy { ~LocalityEntry() = default; void UpdateLocked(xds_grpclb_serverlist* serverlist, - LoadBalancingPolicy::Config* child_policy_config, + ParsedLoadBalancingConfig* child_policy_config, const grpc_channel_args* args); void ShutdownLocked(); void ResetBackoffLocked(); @@ -355,7 +410,7 @@ class XdsLb : public LoadBalancingPolicy { }; void UpdateLocked(const LocalityList& locality_list, - LoadBalancingPolicy::Config* child_policy_config, + ParsedLoadBalancingConfig* child_policy_config, const grpc_channel_args* args, XdsLb* parent); void ShutdownLocked(); void ResetBackoffLocked(); @@ -395,15 +450,20 @@ class XdsLb : public LoadBalancingPolicy { // If parsing succeeds, updates \a balancer_name, and updates \a // child_policy_config_ and \a fallback_policy_config_ if they are also // found. Does nothing upon failure. - void ParseLbConfig(Config* xds_config); + void ParseLbConfig(const ParsedXdsConfig* xds_config); BalancerChannelState* LatestLbChannel() const { return pending_lb_chand_ != nullptr ? pending_lb_chand_.get() : lb_chand_.get(); } - // Callback to enter fallback mode. + // Methods for dealing with fallback state. + void MaybeCancelFallbackAtStartupChecks(); static void OnFallbackTimerLocked(void* arg, grpc_error* error); + void UpdateFallbackPolicyLocked(); + OrphanablePtr CreateFallbackPolicyLocked( + const char* name, const grpc_channel_args* args); + void MaybeExitFallbackMode(); // Who the client is trying to communicate with. const char* server_name_ = nullptr; @@ -428,19 +488,34 @@ class XdsLb : public LoadBalancingPolicy { // Timeout in milliseconds for the LB call. 0 means no deadline. int lb_call_timeout_ms_ = 0; + // Whether the checks for fallback at startup are ALL pending. There are + // several cases where this can be reset: + // 1. The fallback timer fires, we enter fallback mode. + // 2. Before the fallback timer fires, the LB channel becomes + // TRANSIENT_FAILURE or the LB call fails, we enter fallback mode. + // 3. Before the fallback timer fires, if any child policy in the locality map + // becomes READY, we cancel the fallback timer. + bool fallback_at_startup_checks_pending_ = false; // Timeout in milliseconds for before using fallback backend addresses. // 0 means not using fallback. - RefCountedPtr fallback_policy_config_; int lb_fallback_timeout_ms_ = 0; // The backend addresses from the resolver. - UniquePtr fallback_backend_addresses_; + ServerAddressList fallback_backend_addresses_; // Fallback timer. - bool fallback_timer_callback_pending_ = false; grpc_timer lb_fallback_timer_; grpc_closure lb_on_fallback_; + // The policy to use for the fallback backends. + RefCountedPtr fallback_policy_config_; + // Lock held when modifying the value of fallback_policy_ or + // pending_fallback_policy_. + Mutex fallback_policy_mu_; + // Non-null iff we are in fallback mode. + OrphanablePtr fallback_policy_; + OrphanablePtr pending_fallback_policy_; + // The policy to use for the backends. - RefCountedPtr child_policy_config_; + RefCountedPtr child_policy_config_; // Map of policies to use in the backend LocalityMap locality_map_; // TODO(mhaidry) : Add support for multiple maps of localities @@ -494,17 +569,90 @@ XdsLb::PickResult XdsLb::Picker::PickFromLocality(const uint32_t key, return pickers_[index].second->Pick(pick, error); } +// +// XdsLb::FallbackHelper +// + +bool XdsLb::FallbackHelper::CalledByPendingFallback() const { + GPR_ASSERT(child_ != nullptr); + return child_ == parent_->pending_fallback_policy_.get(); +} + +bool XdsLb::FallbackHelper::CalledByCurrentFallback() const { + GPR_ASSERT(child_ != nullptr); + return child_ == parent_->fallback_policy_.get(); +} + +Subchannel* XdsLb::FallbackHelper::CreateSubchannel( + const grpc_channel_args& args) { + if (parent_->shutting_down_ || + (!CalledByPendingFallback() && !CalledByCurrentFallback())) { + return nullptr; + } + return parent_->channel_control_helper()->CreateSubchannel(args); +} + +grpc_channel* XdsLb::FallbackHelper::CreateChannel( + const char* target, const grpc_channel_args& args) { + if (parent_->shutting_down_ || + (!CalledByPendingFallback() && !CalledByCurrentFallback())) { + return nullptr; + } + return parent_->channel_control_helper()->CreateChannel(target, args); +} + +void XdsLb::FallbackHelper::UpdateState(grpc_connectivity_state state, + UniquePtr picker) { + if (parent_->shutting_down_) return; + // If this request is from the pending fallback policy, ignore it until + // it reports READY, at which point we swap it into place. + if (CalledByPendingFallback()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { + gpr_log( + GPR_INFO, + "[xdslb %p helper %p] pending fallback policy %p reports state=%s", + parent_.get(), this, parent_->pending_fallback_policy_.get(), + grpc_connectivity_state_name(state)); + } + if (state != GRPC_CHANNEL_READY) return; + grpc_pollset_set_del_pollset_set( + parent_->fallback_policy_->interested_parties(), + parent_->interested_parties()); + MutexLock lock(&parent_->fallback_policy_mu_); + parent_->fallback_policy_ = std::move(parent_->pending_fallback_policy_); + } else if (!CalledByCurrentFallback()) { + // This request is from an outdated fallback policy, so ignore it. + return; + } + parent_->channel_control_helper()->UpdateState(state, std::move(picker)); +} + +void XdsLb::FallbackHelper::RequestReresolution() { + if (parent_->shutting_down_) return; + const LoadBalancingPolicy* latest_fallback_policy = + parent_->pending_fallback_policy_ != nullptr + ? parent_->pending_fallback_policy_.get() + : parent_->fallback_policy_.get(); + if (child_ != latest_fallback_policy) return; + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { + gpr_log(GPR_INFO, + "[xdslb %p] Re-resolution requested from the fallback policy (%p).", + parent_.get(), child_); + } + GPR_ASSERT(parent_->lb_chand_ != nullptr); + parent_->channel_control_helper()->RequestReresolution(); +} + // // serverlist parsing code // // Returns the backend addresses extracted from the given addresses. -UniquePtr ExtractBackendAddresses( - const ServerAddressList& addresses) { - auto backend_addresses = MakeUnique(); +ServerAddressList ExtractBackendAddresses(const ServerAddressList& addresses) { + ServerAddressList backend_addresses; for (size_t i = 0; i < addresses.size(); ++i) { if (!addresses[i].IsBalancer()) { - backend_addresses->emplace_back(addresses[i]); + backend_addresses.emplace_back(addresses[i]); } } return backend_addresses; @@ -584,6 +732,9 @@ XdsLb::BalancerChannelState::BalancerChannelState( .set_multiplier(GRPC_XDS_RECONNECT_BACKOFF_MULTIPLIER) .set_jitter(GRPC_XDS_RECONNECT_JITTER) .set_max_backoff(GRPC_XDS_RECONNECT_MAX_BACKOFF_SECONDS * 1000)) { + GRPC_CLOSURE_INIT(&on_connectivity_changed_, + &XdsLb::BalancerChannelState::OnConnectivityChangedLocked, + this, grpc_combiner_scheduler(xdslb_policy_->combiner())); channel_ = xdslb_policy_->channel_control_helper()->CreateChannel( balancer_name, args); GPR_ASSERT(channel_ != nullptr); @@ -603,7 +754,7 @@ void XdsLb::BalancerChannelState::Orphan() { void XdsLb::BalancerChannelState::StartCallRetryTimerLocked() { grpc_millis next_try = lb_call_backoff_.NextAttemptTime(); - if (grpc_lb_xds_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { gpr_log(GPR_INFO, "[xdslb %p] Failed to connect to LB server (lb_chand: %p)...", xdslb_policy_.get(), this); @@ -629,7 +780,7 @@ void XdsLb::BalancerChannelState::OnCallRetryTimerLocked(void* arg, lb_chand->retry_timer_callback_pending_ = false; if (!lb_chand->shutting_down_ && error == GRPC_ERROR_NONE && lb_chand->lb_calld_ == nullptr) { - if (grpc_lb_xds_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { gpr_log(GPR_INFO, "[xdslb %p] Restarting call to LB server (lb_chand: %p)", lb_chand->xdslb_policy_.get(), lb_chand); @@ -644,7 +795,7 @@ void XdsLb::BalancerChannelState::StartCallLocked() { GPR_ASSERT(channel_ != nullptr); GPR_ASSERT(lb_calld_ == nullptr); lb_calld_ = MakeOrphanable(Ref()); - if (grpc_lb_xds_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { gpr_log(GPR_INFO, "[xdslb %p] Query for backends (lb_chand: %p, lb_calld: %p)", xdslb_policy_.get(), this, lb_calld_.get()); @@ -652,6 +803,62 @@ void XdsLb::BalancerChannelState::StartCallLocked() { lb_calld_->StartQuery(); } +void XdsLb::BalancerChannelState::StartConnectivityWatchLocked() { + grpc_channel_element* client_channel_elem = + grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel_)); + GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter); + // Ref held by callback. + Ref(DEBUG_LOCATION, "watch_lb_channel_connectivity").release(); + grpc_client_channel_watch_connectivity_state( + client_channel_elem, + grpc_polling_entity_create_from_pollset_set( + xdslb_policy_->interested_parties()), + &connectivity_, &on_connectivity_changed_, nullptr); +} + +void XdsLb::BalancerChannelState::CancelConnectivityWatchLocked() { + grpc_channel_element* client_channel_elem = + grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel_)); + GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter); + grpc_client_channel_watch_connectivity_state( + client_channel_elem, + grpc_polling_entity_create_from_pollset_set( + xdslb_policy_->interested_parties()), + nullptr, &on_connectivity_changed_, nullptr); +} + +void XdsLb::BalancerChannelState::OnConnectivityChangedLocked( + void* arg, grpc_error* error) { + BalancerChannelState* self = static_cast(arg); + if (!self->shutting_down_ && + self->xdslb_policy_->fallback_at_startup_checks_pending_) { + if (self->connectivity_ != GRPC_CHANNEL_TRANSIENT_FAILURE) { + // Not in TRANSIENT_FAILURE. Renew connectivity watch. + grpc_channel_element* client_channel_elem = + grpc_channel_stack_last_element( + grpc_channel_get_channel_stack(self->channel_)); + GPR_ASSERT(client_channel_elem->filter == &grpc_client_channel_filter); + grpc_client_channel_watch_connectivity_state( + client_channel_elem, + grpc_polling_entity_create_from_pollset_set( + self->xdslb_policy_->interested_parties()), + &self->connectivity_, &self->on_connectivity_changed_, nullptr); + return; // Early out so we don't drop the ref below. + } + // In TRANSIENT_FAILURE. Cancel the fallback timer and go into + // fallback mode immediately. + gpr_log(GPR_INFO, + "[xdslb %p] Balancer channel in state TRANSIENT_FAILURE; " + "entering fallback mode", + self); + self->xdslb_policy_->fallback_at_startup_checks_pending_ = false; + grpc_timer_cancel(&self->xdslb_policy_->lb_fallback_timer_); + self->xdslb_policy_->UpdateFallbackPolicyLocked(); + } + // Done watching connectivity state, so drop ref. + self->Unref(DEBUG_LOCATION, "watch_lb_channel_connectivity"); +} + // // XdsLb::BalancerChannelState::BalancerCallState // @@ -724,7 +931,7 @@ void XdsLb::BalancerChannelState::BalancerCallState::Orphan() { void XdsLb::BalancerChannelState::BalancerCallState::StartQuery() { GPR_ASSERT(lb_call_ != nullptr); - if (grpc_lb_xds_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { gpr_log(GPR_INFO, "[xdslb %p] Starting LB call (lb_calld: %p, lb_call: %p)", xdslb_policy(), this, lb_call_); } @@ -897,6 +1104,14 @@ void XdsLb::BalancerChannelState::BalancerCallState:: (initial_response = xds_grpclb_initial_response_parse(response_slice)) != nullptr) { // Have NOT seen initial response, look for initial response. + // TODO(juanlishen): When we convert this to use the xds protocol, the + // balancer will send us a fallback timeout such that we should go into + // fallback mode if we have lost contact with the balancer after a certain + // period of time. We will need to save the timeout value here, and then + // when the balancer call ends, we will need to start a timer for the + // specified period of time, and if the timer fires, we go into fallback + // mode. We will also need to cancel the timer when we receive a serverlist + // from the balancer. if (initial_response->has_client_stats_report_interval) { const grpc_millis interval = xds_grpclb_duration_to_millis( &initial_response->client_stats_report_interval); @@ -905,7 +1120,7 @@ void XdsLb::BalancerChannelState::BalancerCallState:: GPR_MAX(GPR_MS_PER_SEC, interval); } } - if (grpc_lb_xds_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { if (lb_calld->client_stats_report_interval_ != 0) { gpr_log(GPR_INFO, "[xdslb %p] Received initial LB response message; " @@ -924,7 +1139,7 @@ void XdsLb::BalancerChannelState::BalancerCallState:: response_slice)) != nullptr) { // Have seen initial response, look for serverlist. GPR_ASSERT(lb_calld->lb_call_ != nullptr); - if (grpc_lb_xds_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { gpr_log(GPR_INFO, "[xdslb %p] Serverlist with %" PRIuPTR " servers received", xdslb_policy, serverlist->num_servers); @@ -938,81 +1153,66 @@ void XdsLb::BalancerChannelState::BalancerCallState:: gpr_free(ipport); } } - /* update serverlist */ - // TODO(juanlishen): Don't ingore empty serverlist. - if (serverlist->num_servers > 0) { - // Pending LB channel receives a serverlist; promote it. - // Note that this call can't be on a discarded pending channel, because - // such channels don't have any current call but we have checked this call - // is a current call. - if (!lb_calld->lb_chand_->IsCurrentChannel()) { - if (grpc_lb_xds_trace.enabled()) { - gpr_log(GPR_INFO, - "[xdslb %p] Promoting pending LB channel %p to replace " - "current LB channel %p", - xdslb_policy, lb_calld->lb_chand_.get(), - lb_calld->xdslb_policy()->lb_chand_.get()); - } - lb_calld->xdslb_policy()->lb_chand_ = - std::move(lb_calld->xdslb_policy()->pending_lb_chand_); - } - // Start sending client load report only after we start using the - // serverlist returned from the current LB call. - if (lb_calld->client_stats_report_interval_ > 0 && - lb_calld->client_stats_ == nullptr) { - lb_calld->client_stats_ = MakeRefCounted(); - // TODO(roth): We currently track this ref manually. Once the - // ClosureRef API is ready, we should pass the RefCountedPtr<> along - // with the callback. - auto self = lb_calld->Ref(DEBUG_LOCATION, "client_load_report"); - self.release(); - lb_calld->ScheduleNextClientLoadReportLocked(); - } - if (!xdslb_policy->locality_serverlist_.empty() && - xds_grpclb_serverlist_equals( - xdslb_policy->locality_serverlist_[0]->serverlist, serverlist)) { - if (grpc_lb_xds_trace.enabled()) { - gpr_log(GPR_INFO, - "[xdslb %p] Incoming server list identical to current, " - "ignoring.", - xdslb_policy); - } - xds_grpclb_destroy_serverlist(serverlist); - } else { /* new serverlist */ - if (!xdslb_policy->locality_serverlist_.empty()) { - /* dispose of the old serverlist */ - xds_grpclb_destroy_serverlist( - xdslb_policy->locality_serverlist_[0]->serverlist); - } else { - /* or dispose of the fallback */ - xdslb_policy->fallback_backend_addresses_.reset(); - if (xdslb_policy->fallback_timer_callback_pending_) { - grpc_timer_cancel(&xdslb_policy->lb_fallback_timer_); - } - /* Initialize locality serverlist, currently the list only handles - * one child */ - xdslb_policy->locality_serverlist_.emplace_back( - MakeUnique()); - xdslb_policy->locality_serverlist_[0]->locality_name = - static_cast(gpr_strdup(kDefaultLocalityName)); - xdslb_policy->locality_serverlist_[0]->locality_weight = - kDefaultLocalityWeight; - } - // and update the copy in the XdsLb instance. This - // serverlist instance will be destroyed either upon the next - // update or when the XdsLb instance is destroyed. - xdslb_policy->locality_serverlist_[0]->serverlist = serverlist; - xdslb_policy->locality_map_.UpdateLocked( - xdslb_policy->locality_serverlist_, - xdslb_policy->child_policy_config_.get(), xdslb_policy->args_, - xdslb_policy); + // Pending LB channel receives a serverlist; promote it. + // Note that this call can't be on a discarded pending channel, because + // such channels don't have any current call but we have checked this call + // is a current call. + if (!lb_calld->lb_chand_->IsCurrentChannel()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { + gpr_log(GPR_INFO, + "[xdslb %p] Promoting pending LB channel %p to replace " + "current LB channel %p", + xdslb_policy, lb_calld->lb_chand_.get(), + lb_calld->xdslb_policy()->lb_chand_.get()); } - } else { - if (grpc_lb_xds_trace.enabled()) { - gpr_log(GPR_INFO, "[xdslb %p] Received empty server list, ignoring.", + lb_calld->xdslb_policy()->lb_chand_ = + std::move(lb_calld->xdslb_policy()->pending_lb_chand_); + } + // Start sending client load report only after we start using the + // serverlist returned from the current LB call. + if (lb_calld->client_stats_report_interval_ > 0 && + lb_calld->client_stats_ == nullptr) { + lb_calld->client_stats_ = MakeRefCounted(); + lb_calld->Ref(DEBUG_LOCATION, "client_load_report").release(); + lb_calld->ScheduleNextClientLoadReportLocked(); + } + if (!xdslb_policy->locality_serverlist_.empty() && + xds_grpclb_serverlist_equals( + xdslb_policy->locality_serverlist_[0]->serverlist, serverlist)) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { + gpr_log(GPR_INFO, + "[xdslb %p] Incoming server list identical to current, " + "ignoring.", xdslb_policy); } xds_grpclb_destroy_serverlist(serverlist); + } else { // New serverlist. + // If the balancer tells us to drop all the calls, we should exit fallback + // mode immediately. + // TODO(juanlishen): When we add EDS drop, we should change to check + // drop_percentage. + if (serverlist->num_servers == 0) xdslb_policy->MaybeExitFallbackMode(); + if (!xdslb_policy->locality_serverlist_.empty()) { + xds_grpclb_destroy_serverlist( + xdslb_policy->locality_serverlist_[0]->serverlist); + } else { + // Initialize locality serverlist, currently the list only handles + // one child. + xdslb_policy->locality_serverlist_.emplace_back( + MakeUnique()); + xdslb_policy->locality_serverlist_[0]->locality_name = + static_cast(gpr_strdup(kDefaultLocalityName)); + xdslb_policy->locality_serverlist_[0]->locality_weight = + kDefaultLocalityWeight; + } + // Update the serverlist in the XdsLb instance. This serverlist + // instance will be destroyed either upon the next update or when the + // XdsLb instance is destroyed. + xdslb_policy->locality_serverlist_[0]->serverlist = serverlist; + xdslb_policy->locality_map_.UpdateLocked( + xdslb_policy->locality_serverlist_, + xdslb_policy->child_policy_config_.get(), xdslb_policy->args_, + xdslb_policy); } } else { // No valid initial response or serverlist found. @@ -1048,7 +1248,7 @@ void XdsLb::BalancerChannelState::BalancerCallState:: XdsLb* xdslb_policy = lb_calld->xdslb_policy(); BalancerChannelState* lb_chand = lb_calld->lb_chand_.get(); GPR_ASSERT(lb_calld->lb_call_ != nullptr); - if (grpc_lb_xds_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { char* status_details = grpc_slice_to_c_string(lb_calld->lb_call_status_details_); gpr_log(GPR_INFO, @@ -1067,7 +1267,7 @@ void XdsLb::BalancerChannelState::BalancerCallState:: if (lb_chand != xdslb_policy->LatestLbChannel()) { // This channel must be the current one and there is a pending one. Swap // in the pending one and we are done. - if (grpc_lb_xds_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { gpr_log(GPR_INFO, "[xdslb %p] Promoting pending LB channel %p to replace " "current LB channel %p", @@ -1089,6 +1289,18 @@ void XdsLb::BalancerChannelState::BalancerCallState:: lb_chand->StartCallRetryTimerLocked(); } xdslb_policy->channel_control_helper()->RequestReresolution(); + // If the fallback-at-startup checks are pending, go into fallback mode + // immediately. This short-circuits the timeout for the + // fallback-at-startup case. + if (xdslb_policy->fallback_at_startup_checks_pending_) { + gpr_log(GPR_INFO, + "[xdslb %p] Balancer call finished; entering fallback mode", + xdslb_policy); + xdslb_policy->fallback_at_startup_checks_pending_ = false; + grpc_timer_cancel(&xdslb_policy->lb_fallback_timer_); + lb_chand->CancelConnectivityWatchLocked(); + xdslb_policy->UpdateFallbackPolicyLocked(); + } } } lb_calld->Unref(DEBUG_LOCATION, "lb_call_ended"); @@ -1154,7 +1366,7 @@ XdsLb::XdsLb(Args args) grpc_uri* uri = grpc_uri_parse(server_uri, true); GPR_ASSERT(uri->path[0] != '\0'); server_name_ = gpr_strdup(uri->path[0] == '/' ? uri->path + 1 : uri->path); - if (grpc_lb_xds_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { gpr_log(GPR_INFO, "[xdslb %p] Will use '%s' as the server name for LB request.", this, server_name_); @@ -1164,7 +1376,7 @@ XdsLb::XdsLb(Args args) arg = grpc_channel_args_find(args.args, GRPC_ARG_GRPCLB_CALL_TIMEOUT_MS); lb_call_timeout_ms_ = grpc_channel_arg_get_integer(arg, {0, 0, INT_MAX}); // Record fallback timeout. - arg = grpc_channel_args_find(args.args, GRPC_ARG_GRPCLB_FALLBACK_TIMEOUT_MS); + arg = grpc_channel_args_find(args.args, GRPC_ARG_XDS_FALLBACK_TIMEOUT_MS); lb_fallback_timeout_ms_ = grpc_channel_arg_get_integer( arg, {GRPC_XDS_DEFAULT_FALLBACK_TIMEOUT_MS, 0, INT_MAX}); } @@ -1177,14 +1389,25 @@ XdsLb::~XdsLb() { void XdsLb::ShutdownLocked() { shutting_down_ = true; - if (fallback_timer_callback_pending_) { + if (fallback_at_startup_checks_pending_) { grpc_timer_cancel(&lb_fallback_timer_); } locality_map_.ShutdownLocked(); - // We destroy the LB channel here instead of in our destructor because - // destroying the channel triggers a last callback to - // OnBalancerChannelConnectivityChangedLocked(), and we need to be - // alive when that callback is invoked. + if (fallback_policy_ != nullptr) { + grpc_pollset_set_del_pollset_set(fallback_policy_->interested_parties(), + interested_parties()); + } + if (pending_fallback_policy_ != nullptr) { + grpc_pollset_set_del_pollset_set( + pending_fallback_policy_->interested_parties(), interested_parties()); + } + { + MutexLock lock(&fallback_policy_mu_); + fallback_policy_.reset(); + pending_fallback_policy_.reset(); + } + // We reset the LB channels here instead of in our destructor because they + // hold refs to XdsLb. { MutexLock lock(&lb_chand_mu_); lb_chand_.reset(); @@ -1204,12 +1427,31 @@ void XdsLb::ResetBackoffLocked() { grpc_channel_reset_connect_backoff(pending_lb_chand_->channel()); } locality_map_.ResetBackoffLocked(); + if (fallback_policy_ != nullptr) { + fallback_policy_->ResetBackoffLocked(); + } + if (pending_fallback_policy_ != nullptr) { + pending_fallback_policy_->ResetBackoffLocked(); + } } void XdsLb::FillChildRefsForChannelz(channelz::ChildRefsList* child_subchannels, channelz::ChildRefsList* child_channels) { - // Delegate to the child_policy_ to fill the children subchannels. + // Delegate to the locality_map_ to fill the children subchannels. locality_map_.FillChildRefsForChannelz(child_subchannels, child_channels); + { + // This must be done holding fallback_policy_mu_, since this method does not + // run in the combiner. + MutexLock lock(&fallback_policy_mu_); + if (fallback_policy_ != nullptr) { + fallback_policy_->FillChildRefsForChannelz(child_subchannels, + child_channels); + } + if (pending_fallback_policy_ != nullptr) { + pending_fallback_policy_->FillChildRefsForChannelz(child_subchannels, + child_channels); + } + } MutexLock lock(&lb_chand_mu_); if (lb_chand_ != nullptr) { grpc_core::channelz::ChannelNode* channel_node = @@ -1266,92 +1508,224 @@ void XdsLb::ProcessAddressesAndChannelArgsLocked( grpc_channel_args_destroy(lb_channel_args); } -void XdsLb::ParseLbConfig(Config* xds_config) { - const grpc_json* xds_config_json = xds_config->config(); - const char* balancer_name = nullptr; - grpc_json* child_policy = nullptr; - grpc_json* fallback_policy = nullptr; - for (const grpc_json* field = xds_config_json; field != nullptr; - field = field->next) { - if (field->key == nullptr) return; - if (strcmp(field->key, "balancerName") == 0) { - if (balancer_name != nullptr) return; // Duplicate. - if (field->type != GRPC_JSON_STRING) return; - balancer_name = field->value; - } else if (strcmp(field->key, "childPolicy") == 0) { - if (child_policy != nullptr) return; // Duplicate. - child_policy = ParseLoadBalancingConfig(field); - } else if (strcmp(field->key, "fallbackPolicy") == 0) { - if (fallback_policy != nullptr) return; // Duplicate. - fallback_policy = ParseLoadBalancingConfig(field); - } - } - if (balancer_name == nullptr) return; // Required field. - balancer_name_ = UniquePtr(gpr_strdup(balancer_name)); - if (child_policy != nullptr) { - child_policy_config_ = - MakeRefCounted(child_policy, xds_config->service_config()); - } - if (fallback_policy != nullptr) { - fallback_policy_config_ = - MakeRefCounted(fallback_policy, xds_config->service_config()); - } +void XdsLb::ParseLbConfig(const ParsedXdsConfig* xds_config) { + if (xds_config == nullptr || xds_config->balancer_name() == nullptr) return; + // TODO(yashykt) : does this need to be a gpr_strdup + balancer_name_ = UniquePtr(gpr_strdup(xds_config->balancer_name())); + child_policy_config_ = xds_config->child_policy(); + fallback_policy_config_ = xds_config->fallback_policy(); } void XdsLb::UpdateLocked(UpdateArgs args) { const bool is_initial_update = lb_chand_ == nullptr; - ParseLbConfig(args.config.get()); - // TODO(juanlishen): Pass fallback policy config update after fallback policy - // is added. + ParseLbConfig(static_cast(args.config.get())); if (balancer_name_ == nullptr) { gpr_log(GPR_ERROR, "[xdslb %p] LB config parsing fails.", this); return; } ProcessAddressesAndChannelArgsLocked(args.addresses, *args.args); - // Update the existing child policy. - // Note: We have disabled fallback mode in the code, so this child policy must - // have been created from a serverlist. - // TODO(vpowar): Handle the fallback_address changes when we add support for - // fallback in xDS. locality_map_.UpdateLocked(locality_serverlist_, child_policy_config_.get(), args_, this); - // If this is the initial update, start the fallback timer. + // Update the existing fallback policy. The fallback policy config and/or the + // fallback addresses may be new. + if (fallback_policy_ != nullptr) UpdateFallbackPolicyLocked(); + // If this is the initial update, start the fallback-at-startup checks. if (is_initial_update) { - if (lb_fallback_timeout_ms_ > 0 && locality_serverlist_.empty() && - !fallback_timer_callback_pending_) { - grpc_millis deadline = ExecCtx::Get()->Now() + lb_fallback_timeout_ms_; - Ref(DEBUG_LOCATION, "on_fallback_timer").release(); // Held by closure - GRPC_CLOSURE_INIT(&lb_on_fallback_, &XdsLb::OnFallbackTimerLocked, this, - grpc_combiner_scheduler(combiner())); - fallback_timer_callback_pending_ = true; - grpc_timer_init(&lb_fallback_timer_, deadline, &lb_on_fallback_); - // TODO(juanlishen): Monitor the connectivity state of the balancer - // channel. If the channel reports TRANSIENT_FAILURE before the - // fallback timeout expires, go into fallback mode early. - } + grpc_millis deadline = ExecCtx::Get()->Now() + lb_fallback_timeout_ms_; + Ref(DEBUG_LOCATION, "on_fallback_timer").release(); // Held by closure + GRPC_CLOSURE_INIT(&lb_on_fallback_, &XdsLb::OnFallbackTimerLocked, this, + grpc_combiner_scheduler(combiner())); + fallback_at_startup_checks_pending_ = true; + grpc_timer_init(&lb_fallback_timer_, deadline, &lb_on_fallback_); + // Start watching the channel's connectivity state. If the channel + // goes into state TRANSIENT_FAILURE, we go into fallback mode even if + // the fallback timeout has not elapsed. + lb_chand_->StartConnectivityWatchLocked(); } } // -// code for balancer channel and call +// fallback-related methods // +void XdsLb::MaybeCancelFallbackAtStartupChecks() { + if (!fallback_at_startup_checks_pending_) return; + gpr_log(GPR_INFO, + "[xdslb %p] Cancelling fallback timer and LB channel connectivity " + "watch", + this); + grpc_timer_cancel(&lb_fallback_timer_); + lb_chand_->CancelConnectivityWatchLocked(); + fallback_at_startup_checks_pending_ = false; +} + void XdsLb::OnFallbackTimerLocked(void* arg, grpc_error* error) { XdsLb* xdslb_policy = static_cast(arg); - xdslb_policy->fallback_timer_callback_pending_ = false; - // If we receive a serverlist after the timer fires but before this callback - // actually runs, don't fall back. - if (xdslb_policy->locality_serverlist_.empty() && + // If some fallback-at-startup check is done after the timer fires but before + // this callback actually runs, don't fall back. + if (xdslb_policy->fallback_at_startup_checks_pending_ && !xdslb_policy->shutting_down_ && error == GRPC_ERROR_NONE) { - if (grpc_lb_xds_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { gpr_log(GPR_INFO, - "[xdslb %p] Fallback timer fired. Not using fallback backends", + "[xdslb %p] Child policy not ready after fallback timeout; " + "entering fallback mode", xdslb_policy); } + xdslb_policy->fallback_at_startup_checks_pending_ = false; + xdslb_policy->UpdateFallbackPolicyLocked(); + xdslb_policy->lb_chand_->CancelConnectivityWatchLocked(); } xdslb_policy->Unref(DEBUG_LOCATION, "on_fallback_timer"); } +void XdsLb::UpdateFallbackPolicyLocked() { + if (shutting_down_) return; + // Construct update args. + UpdateArgs update_args; + update_args.addresses = fallback_backend_addresses_; + update_args.config = fallback_policy_config_ == nullptr + ? nullptr + : fallback_policy_config_->Ref(); + update_args.args = grpc_channel_args_copy(args_); + // If the child policy name changes, we need to create a new child + // policy. When this happens, we leave child_policy_ as-is and store + // the new child policy in pending_child_policy_. Once the new child + // policy transitions into state READY, we swap it into child_policy_, + // replacing the original child policy. So pending_child_policy_ is + // non-null only between when we apply an update that changes the child + // policy name and when the new child reports state READY. + // + // Updates can arrive at any point during this transition. We always + // apply updates relative to the most recently created child policy, + // even if the most recent one is still in pending_child_policy_. This + // is true both when applying the updates to an existing child policy + // and when determining whether we need to create a new policy. + // + // As a result of this, there are several cases to consider here: + // + // 1. We have no existing child policy (i.e., we have started up but + // have not yet received a serverlist from the balancer or gone + // into fallback mode; in this case, both child_policy_ and + // pending_child_policy_ are null). In this case, we create a + // new child policy and store it in child_policy_. + // + // 2. We have an existing child policy and have no pending child policy + // from a previous update (i.e., either there has not been a + // previous update that changed the policy name, or we have already + // finished swapping in the new policy; in this case, child_policy_ + // is non-null but pending_child_policy_ is null). In this case: + // a. If child_policy_->name() equals child_policy_name, then we + // update the existing child policy. + // b. If child_policy_->name() does not equal child_policy_name, + // we create a new policy. The policy will be stored in + // pending_child_policy_ and will later be swapped into + // child_policy_ by the helper when the new child transitions + // into state READY. + // + // 3. We have an existing child policy and have a pending child policy + // from a previous update (i.e., a previous update set + // pending_child_policy_ as per case 2b above and that policy has + // not yet transitioned into state READY and been swapped into + // child_policy_; in this case, both child_policy_ and + // pending_child_policy_ are non-null). In this case: + // a. If pending_child_policy_->name() equals child_policy_name, + // then we update the existing pending child policy. + // b. If pending_child_policy->name() does not equal + // child_policy_name, then we create a new policy. The new + // policy is stored in pending_child_policy_ (replacing the one + // that was there before, which will be immediately shut down) + // and will later be swapped into child_policy_ by the helper + // when the new child transitions into state READY. + const char* fallback_policy_name = fallback_policy_config_ == nullptr + ? "round_robin" + : fallback_policy_config_->name(); + const bool create_policy = + // case 1 + fallback_policy_ == nullptr || + // case 2b + (pending_fallback_policy_ == nullptr && + strcmp(fallback_policy_->name(), fallback_policy_name) != 0) || + // case 3b + (pending_fallback_policy_ != nullptr && + strcmp(pending_fallback_policy_->name(), fallback_policy_name) != 0); + LoadBalancingPolicy* policy_to_update = nullptr; + if (create_policy) { + // Cases 1, 2b, and 3b: create a new child policy. + // If child_policy_ is null, we set it (case 1), else we set + // pending_child_policy_ (cases 2b and 3b). + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { + gpr_log(GPR_INFO, "[xdslb %p] Creating new %sfallback policy %s", this, + fallback_policy_ == nullptr ? "" : "pending ", + fallback_policy_name); + } + auto new_policy = + CreateFallbackPolicyLocked(fallback_policy_name, update_args.args); + auto& lb_policy = fallback_policy_ == nullptr ? fallback_policy_ + : pending_fallback_policy_; + { + MutexLock lock(&fallback_policy_mu_); + lb_policy = std::move(new_policy); + } + policy_to_update = lb_policy.get(); + } else { + // Cases 2a and 3a: update an existing policy. + // If we have a pending child policy, send the update to the pending + // policy (case 3a), else send it to the current policy (case 2a). + policy_to_update = pending_fallback_policy_ != nullptr + ? pending_fallback_policy_.get() + : fallback_policy_.get(); + } + GPR_ASSERT(policy_to_update != nullptr); + // Update the policy. + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { + gpr_log( + GPR_INFO, "[xdslb %p] Updating %sfallback policy %p", this, + policy_to_update == pending_fallback_policy_.get() ? "pending " : "", + policy_to_update); + } + policy_to_update->UpdateLocked(std::move(update_args)); +} + +OrphanablePtr XdsLb::CreateFallbackPolicyLocked( + const char* name, const grpc_channel_args* args) { + FallbackHelper* helper = New(Ref()); + LoadBalancingPolicy::Args lb_policy_args; + lb_policy_args.combiner = combiner(); + lb_policy_args.args = args; + lb_policy_args.channel_control_helper = + UniquePtr(helper); + OrphanablePtr lb_policy = + LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy( + name, std::move(lb_policy_args)); + if (GPR_UNLIKELY(lb_policy == nullptr)) { + gpr_log(GPR_ERROR, "[xdslb %p] Failure creating fallback policy %s", this, + name); + return nullptr; + } + helper->set_child(lb_policy.get()); + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { + gpr_log(GPR_INFO, "[xdslb %p] Created new fallback policy %s (%p)", this, + name, lb_policy.get()); + } + // Add the xDS's interested_parties pollset_set to that of the newly created + // child policy. This will make the child policy progress upon activity on xDS + // LB, which in turn is tied to the application's call. + grpc_pollset_set_add_pollset_set(lb_policy->interested_parties(), + interested_parties()); + return lb_policy; +} + +void XdsLb::MaybeExitFallbackMode() { + if (fallback_policy_ == nullptr) return; + gpr_log(GPR_INFO, "[xdslb %p] Exiting fallback mode", this); + fallback_policy_.reset(); + pending_fallback_policy_.reset(); +} + +// +// XdsLb::LocalityMap +// + void XdsLb::LocalityMap::PruneLocalities(const LocalityList& locality_list) { for (auto iter = map_.begin(); iter != map_.end();) { bool found = false; @@ -1370,7 +1744,7 @@ void XdsLb::LocalityMap::PruneLocalities(const LocalityList& locality_list) { void XdsLb::LocalityMap::UpdateLocked( const LocalityList& locality_serverlist, - LoadBalancingPolicy::Config* child_policy_config, + ParsedLoadBalancingConfig* child_policy_config, const grpc_channel_args* args, XdsLb* parent) { if (parent->shutting_down_) return; for (size_t i = 0; i < locality_serverlist.size(); i++) { @@ -1391,18 +1765,18 @@ void XdsLb::LocalityMap::UpdateLocked( PruneLocalities(locality_serverlist); } -void grpc_core::XdsLb::LocalityMap::ShutdownLocked() { +void XdsLb::LocalityMap::ShutdownLocked() { MutexLock lock(&child_refs_mu_); map_.clear(); } -void grpc_core::XdsLb::LocalityMap::ResetBackoffLocked() { +void XdsLb::LocalityMap::ResetBackoffLocked() { for (auto& p : map_) { p.second->ResetBackoffLocked(); } } -void grpc_core::XdsLb::LocalityMap::FillChildRefsForChannelz( +void XdsLb::LocalityMap::FillChildRefsForChannelz( channelz::ChildRefsList* child_subchannels, channelz::ChildRefsList* child_channels) { MutexLock lock(&child_refs_mu_); @@ -1411,7 +1785,9 @@ void grpc_core::XdsLb::LocalityMap::FillChildRefsForChannelz( } } -// Locality Entry child policy methods +// +// XdsLb::LocalityMap::LocalityEntry +// grpc_channel_args* XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyArgsLocked( @@ -1449,7 +1825,7 @@ XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyLocked( return nullptr; } helper->set_child(lb_policy.get()); - if (grpc_lb_xds_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { gpr_log(GPR_INFO, "[xdslb %p] Created new child policy %s (%p)", this, name, lb_policy.get()); } @@ -1463,21 +1839,15 @@ XdsLb::LocalityMap::LocalityEntry::CreateChildPolicyLocked( void XdsLb::LocalityMap::LocalityEntry::UpdateLocked( xds_grpclb_serverlist* serverlist, - LoadBalancingPolicy::Config* child_policy_config, + ParsedLoadBalancingConfig* child_policy_config, const grpc_channel_args* args_in) { if (parent_->shutting_down_) return; - // This should never be invoked if we do not have serverlist_, as fallback - // mode is disabled for xDS plugin. - // TODO(juanlishen): Change this as part of implementing fallback mode. - GPR_ASSERT(serverlist != nullptr); - GPR_ASSERT(serverlist->num_servers > 0); // Construct update args. UpdateArgs update_args; update_args.addresses = ProcessServerlist(serverlist); update_args.config = child_policy_config == nullptr ? nullptr : child_policy_config->Ref(); update_args.args = CreateChildPolicyArgsLocked(args_in); - // If the child policy name changes, we need to create a new child // policy. When this happens, we leave child_policy_ as-is and store // the new child policy in pending_child_policy_. Once the new child @@ -1546,7 +1916,7 @@ void XdsLb::LocalityMap::LocalityEntry::UpdateLocked( // Cases 1, 2b, and 3b: create a new child policy. // If child_policy_ is null, we set it (case 1), else we set // pending_child_policy_ (cases 2b and 3b). - if (grpc_lb_xds_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { gpr_log(GPR_INFO, "[xdslb %p] Creating new %schild policy %s", this, child_policy_ == nullptr ? "" : "pending ", child_policy_name); } @@ -1569,7 +1939,7 @@ void XdsLb::LocalityMap::LocalityEntry::UpdateLocked( } GPR_ASSERT(policy_to_update != nullptr); // Update the policy. - if (grpc_lb_xds_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { gpr_log(GPR_INFO, "[xdslb %p] Updating %schild policy %p", this, policy_to_update == pending_child_policy_.get() ? "pending " : "", policy_to_update); @@ -1618,7 +1988,7 @@ void XdsLb::LocalityMap::LocalityEntry::Orphan() { } // -// LocalityEntry::Helper implementation +// XdsLb::LocalityEntry::Helper // bool XdsLb::LocalityMap::LocalityEntry::Helper::CalledByPendingChild() const { @@ -1655,7 +2025,7 @@ void XdsLb::LocalityMap::LocalityEntry::Helper::UpdateState( // If this request is from the pending child policy, ignore it until // it reports READY, at which point we swap it into place. if (CalledByPendingChild()) { - if (grpc_lb_xds_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { gpr_log(GPR_INFO, "[xdslb %p helper %p] pending child policy %p reports state=%s", entry_->parent_.get(), this, entry_->pending_child_policy_.get(), @@ -1671,9 +2041,13 @@ void XdsLb::LocalityMap::LocalityEntry::Helper::UpdateState( // This request is from an outdated child, so ignore it. return; } - // TODO(juanlishen): When in fallback mode, pass the child picker - // through without wrapping it. (Or maybe use a different helper for - // the fallback policy?) + // At this point, child_ must be the current child policy. + if (state == GRPC_CHANNEL_READY) { + entry_->parent_->MaybeCancelFallbackAtStartupChecks(); + entry_->parent_->MaybeExitFallbackMode(); + } + // If we are in fallback mode, ignore update request from the child policy. + if (entry_->parent_->fallback_policy_ != nullptr) return; GPR_ASSERT(entry_->parent_->lb_chand_ != nullptr); RefCountedPtr client_stats = entry_->parent_->lb_chand_->lb_calld() == nullptr @@ -1754,7 +2128,7 @@ void XdsLb::LocalityMap::LocalityEntry::Helper::RequestReresolution() { if (entry_->pending_child_policy_ != nullptr && !CalledByPendingChild()) { return; } - if (grpc_lb_xds_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_trace)) { gpr_log(GPR_INFO, "[xdslb %p] Re-resolution requested from the internal RR policy " "(%p).", @@ -1783,6 +2157,77 @@ class XdsFactory : public LoadBalancingPolicyFactory { } const char* name() const override { return kXds; } + + RefCountedPtr ParseLoadBalancingConfig( + const grpc_json* json, grpc_error** error) const override { + GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE); + if (json == nullptr) { + // xds was mentioned as a policy in the deprecated loadBalancingPolicy + // field or in the client API. + *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:loadBalancingPolicy error:Xds Parser has required field - " + "balancerName. Please use loadBalancingConfig field of service " + "config instead."); + return nullptr; + } + GPR_DEBUG_ASSERT(strcmp(json->key, name()) == 0); + + InlinedVector error_list; + const char* balancer_name = nullptr; + RefCountedPtr child_policy; + RefCountedPtr fallback_policy; + for (const grpc_json* field = json->child; field != nullptr; + field = field->next) { + if (field->key == nullptr) continue; + if (strcmp(field->key, "balancerName") == 0) { + if (balancer_name != nullptr) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:balancerName error:Duplicate entry")); + } + if (field->type != GRPC_JSON_STRING) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:balancerName error:type should be string")); + continue; + } + balancer_name = field->value; + } else if (strcmp(field->key, "childPolicy") == 0) { + if (child_policy != nullptr) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:childPolicy error:Duplicate entry")); + } + grpc_error* parse_error = GRPC_ERROR_NONE; + child_policy = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig( + field, &parse_error); + if (child_policy == nullptr) { + GPR_DEBUG_ASSERT(parse_error != GRPC_ERROR_NONE); + error_list.push_back(parse_error); + } + } else if (strcmp(field->key, "fallbackPolicy") == 0) { + if (fallback_policy != nullptr) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:fallbackPolicy error:Duplicate entry")); + } + grpc_error* parse_error = GRPC_ERROR_NONE; + fallback_policy = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig( + field, &parse_error); + if (fallback_policy == nullptr) { + GPR_DEBUG_ASSERT(parse_error != GRPC_ERROR_NONE); + error_list.push_back(parse_error); + } + } + } + if (balancer_name == nullptr) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:balancerName error:not found")); + } + if (error_list.empty()) { + return RefCountedPtr(New( + balancer_name, std::move(child_policy), std::move(fallback_policy))); + } else { + *error = GRPC_ERROR_CREATE_FROM_VECTOR("Xds Parser", &error_list); + return nullptr; + } + } }; } // namespace diff --git a/src/core/ext/filters/client_channel/lb_policy_factory.h b/src/core/ext/filters/client_channel/lb_policy_factory.h index 1da4b7c6956..aaf3e959542 100644 --- a/src/core/ext/filters/client_channel/lb_policy_factory.h +++ b/src/core/ext/filters/client_channel/lb_policy_factory.h @@ -37,9 +37,12 @@ class LoadBalancingPolicyFactory { /// Caller does NOT take ownership of result. virtual const char* name() const GRPC_ABSTRACT; + virtual RefCountedPtr ParseLoadBalancingConfig( + const grpc_json* json, grpc_error** error) const GRPC_ABSTRACT; + virtual ~LoadBalancingPolicyFactory() {} - GRPC_ABSTRACT_BASE_CLASS + GRPC_ABSTRACT_BASE_CLASS; }; } // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/lb_policy_registry.cc b/src/core/ext/filters/client_channel/lb_policy_registry.cc index 99980d5500d..973aa26d0f6 100644 --- a/src/core/ext/filters/client_channel/lb_policy_registry.cc +++ b/src/core/ext/filters/client_channel/lb_policy_registry.cc @@ -94,9 +94,112 @@ LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy( return factory->CreateLoadBalancingPolicy(std::move(args)); } -bool LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(const char* name) { +bool LoadBalancingPolicyRegistry::LoadBalancingPolicyExists( + const char* name, bool* requires_config) { GPR_ASSERT(g_state != nullptr); - return g_state->GetLoadBalancingPolicyFactory(name) != nullptr; + auto* factory = g_state->GetLoadBalancingPolicyFactory(name); + if (factory == nullptr) { + return false; + } + if (requires_config != nullptr) { + grpc_error* error = GRPC_ERROR_NONE; + // Check if the load balancing policy allows an empty config + *requires_config = + factory->ParseLoadBalancingConfig(nullptr, &error) == nullptr; + GRPC_ERROR_UNREF(error); + } + return true; +} + +namespace { +// Returns the JSON node of policy (with both policy name and config content) +// given the JSON node of a LoadBalancingConfig array. +grpc_json* ParseLoadBalancingConfigHelper(const grpc_json* lb_config_array, + grpc_error** error) { + GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE); + char* error_msg; + if (lb_config_array == nullptr || lb_config_array->type != GRPC_JSON_ARRAY) { + gpr_asprintf(&error_msg, "field:%s error:type should be array", + lb_config_array->key); + *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg); + gpr_free(error_msg); + return nullptr; + } + const char* field_name = lb_config_array->key; + // Find the first LB policy that this client supports. + for (const grpc_json* lb_config = lb_config_array->child; + lb_config != nullptr; lb_config = lb_config->next) { + if (lb_config->type != GRPC_JSON_OBJECT) { + gpr_asprintf(&error_msg, + "field:%s error:child entry should be of type object", + field_name); + *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg); + gpr_free(error_msg); + return nullptr; + } + grpc_json* policy = nullptr; + for (grpc_json* field = lb_config->child; field != nullptr; + field = field->next) { + if (field->key == nullptr || field->type != GRPC_JSON_OBJECT) { + gpr_asprintf(&error_msg, + "field:%s error:child entry should be of type object", + field_name); + *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg); + gpr_free(error_msg); + return nullptr; + } + if (policy != nullptr) { + gpr_asprintf(&error_msg, "field:%s error:oneOf violation", field_name); + *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg); + gpr_free(error_msg); + return nullptr; + } // Violate "oneof" type. + policy = field; + } + if (policy == nullptr) { + gpr_asprintf(&error_msg, "field:%s error:no policy found in child entry", + field_name); + *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg); + gpr_free(error_msg); + return nullptr; + } + // If we support this policy, then select it. + if (LoadBalancingPolicyRegistry::LoadBalancingPolicyExists(policy->key, + nullptr)) { + return policy; + } + } + gpr_asprintf(&error_msg, "field:%s error:No known policy", field_name); + *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg); + gpr_free(error_msg); + return nullptr; +} +} // namespace + +RefCountedPtr +LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(const grpc_json* json, + grpc_error** error) { + GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE); + GPR_ASSERT(g_state != nullptr); + const grpc_json* policy = ParseLoadBalancingConfigHelper(json, error); + if (policy == nullptr) { + return nullptr; + } else { + GPR_DEBUG_ASSERT(*error == GRPC_ERROR_NONE && json != nullptr); + // Find factory. + LoadBalancingPolicyFactory* factory = + g_state->GetLoadBalancingPolicyFactory(policy->key); + if (factory == nullptr) { + char* msg; + gpr_asprintf(&msg, "field:%s error:Factory not found to create policy", + json->key); + *error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); + gpr_free(msg); + return nullptr; + } + // Parse load balancing config via factory. + return factory->ParseLoadBalancingConfig(policy, error); + } } } // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/lb_policy_registry.h b/src/core/ext/filters/client_channel/lb_policy_registry.h index 7472ba9f8a8..6820cfc9334 100644 --- a/src/core/ext/filters/client_channel/lb_policy_registry.h +++ b/src/core/ext/filters/client_channel/lb_policy_registry.h @@ -49,8 +49,15 @@ class LoadBalancingPolicyRegistry { const char* name, LoadBalancingPolicy::Args args); /// Returns true if the LB policy factory specified by \a name exists in this - /// registry. - static bool LoadBalancingPolicyExists(const char* name); + /// registry. If the load balancing policy requires a config to be specified + /// then sets \a requires_config to true. + static bool LoadBalancingPolicyExists(const char* name, + bool* requires_config); + + /// Returns a parsed object of the load balancing policy to be used from a + /// LoadBalancingConfig array \a json. + static RefCountedPtr ParseLoadBalancingConfig( + const grpc_json* json, grpc_error** error); }; } // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc index 6994f63bee4..00358736a94 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc @@ -18,7 +18,7 @@ #include -#if GRPC_ARES == 1 && !defined(GRPC_UV) +#if GRPC_ARES == 1 #include #include @@ -32,12 +32,12 @@ #include "src/core/ext/filters/client_channel/http_connect_handshaker.h" #include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" +#include "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" #include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/service_config.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gprpp/manual_constructor.h" @@ -227,65 +227,94 @@ bool ValueInJsonArray(grpc_json* array, const char* value) { return false; } -char* ChooseServiceConfig(char* service_config_choice_json) { +char* ChooseServiceConfig(char* service_config_choice_json, + grpc_error** error) { grpc_json* choices_json = grpc_json_parse_string(service_config_choice_json); - if (choices_json == nullptr || choices_json->type != GRPC_JSON_ARRAY) { - gpr_log(GPR_ERROR, "cannot parse service config JSON string"); + if (choices_json == nullptr) { + *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Service Config JSON Parsing, error: could not parse"); + return nullptr; + } + if (choices_json->type != GRPC_JSON_ARRAY) { + *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Service Config Choices, error: should be of type array"); return nullptr; } char* service_config = nullptr; + InlinedVector error_list; + bool found_choice = false; // have we found a choice? for (grpc_json* choice = choices_json->child; choice != nullptr; choice = choice->next) { if (choice->type != GRPC_JSON_OBJECT) { - gpr_log(GPR_ERROR, "cannot parse service config JSON string"); - break; + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Service Config Choice, error: should be of type object")); + continue; } grpc_json* service_config_json = nullptr; + bool selected = true; // has this choice been rejected? for (grpc_json* field = choice->child; field != nullptr; field = field->next) { // Check client language, if specified. if (strcmp(field->key, "clientLanguage") == 0) { - if (field->type != GRPC_JSON_ARRAY || !ValueInJsonArray(field, "c++")) { - service_config_json = nullptr; - break; + if (field->type != GRPC_JSON_ARRAY) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:clientLanguage error:should be of type array")); + } else if (!ValueInJsonArray(field, "c++")) { + selected = false; } } // Check client hostname, if specified. if (strcmp(field->key, "clientHostname") == 0) { + if (field->type != GRPC_JSON_ARRAY) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:clientHostname error:should be of type array")); + continue; + } char* hostname = grpc_gethostname(); - if (hostname == nullptr || field->type != GRPC_JSON_ARRAY || - !ValueInJsonArray(field, hostname)) { - service_config_json = nullptr; - break; + if (hostname == nullptr || !ValueInJsonArray(field, hostname)) { + selected = false; } } // Check percentage, if specified. if (strcmp(field->key, "percentage") == 0) { if (field->type != GRPC_JSON_NUMBER) { - service_config_json = nullptr; - break; + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:percentage error:should be of type number")); + continue; } int random_pct = rand() % 100; int percentage; - if (sscanf(field->value, "%d", &percentage) != 1 || - random_pct > percentage || percentage == 0) { - service_config_json = nullptr; - break; + if (sscanf(field->value, "%d", &percentage) != 1) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:percentage error:should be of type integer")); + continue; + } + if (random_pct > percentage || percentage == 0) { + selected = false; } } // Save service config. if (strcmp(field->key, "serviceConfig") == 0) { if (field->type == GRPC_JSON_OBJECT) { service_config_json = field; + } else { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:serviceConfig error:should be of type object")); } } } - if (service_config_json != nullptr) { + if (!found_choice && selected && service_config_json != nullptr) { service_config = grpc_json_dump_to_string(service_config_json, 0); - break; + found_choice = true; } } grpc_json_destroy(choices_json); + if (!error_list.empty()) { + gpr_free(service_config); + service_config = nullptr; + *error = GRPC_ERROR_CREATE_FROM_VECTOR("Service Config Choices Parser", + &error_list); + } return service_config; } @@ -303,17 +332,15 @@ void AresDnsResolver::OnResolvedLocked(void* arg, grpc_error* error) { Result result; result.addresses = std::move(*r->addresses_); if (r->service_config_json_ != nullptr) { - char* service_config_string = - ChooseServiceConfig(r->service_config_json_); + char* service_config_string = ChooseServiceConfig( + r->service_config_json_, &result.service_config_error); gpr_free(r->service_config_json_); - if (service_config_string != nullptr) { + if (result.service_config_error == GRPC_ERROR_NONE && + service_config_string != nullptr) { GRPC_CARES_TRACE_LOG("resolver:%p selected service config choice: %s", r, service_config_string); - grpc_error* service_config_error = GRPC_ERROR_NONE; - result.service_config = - ServiceConfig::Create(service_config_string, &service_config_error); - // Error is currently unused. - GRPC_ERROR_UNREF(service_config_error); + result.service_config = ServiceConfig::Create( + service_config_string, &result.service_config_error); } gpr_free(service_config_string); } @@ -430,6 +457,13 @@ static grpc_error* blocking_resolve_address_ares( static grpc_address_resolver_vtable ares_resolver = { grpc_resolve_address_ares, blocking_resolve_address_ares}; +#ifdef GRPC_UV +/* TODO(murgatroid99): Remove this when we want the cares resolver to be the + * default when using libuv */ +static bool should_use_ares(const char* resolver_env) { + return resolver_env != nullptr && gpr_stricmp(resolver_env, "ares") == 0; +} +#else /* GRPC_UV */ static bool should_use_ares(const char* resolver_env) { // TODO(lidiz): Remove the "g_custom_iomgr_enabled" flag once c-ares support // custom IO managers (e.g. gevent). @@ -437,10 +471,12 @@ static bool should_use_ares(const char* resolver_env) { (resolver_env == nullptr || strlen(resolver_env) == 0 || gpr_stricmp(resolver_env, "ares") == 0); } +#endif /* GRPC_UV */ void grpc_resolver_dns_ares_init() { - char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER"); - if (should_use_ares(resolver_env)) { + grpc_core::UniquePtr resolver = + GPR_GLOBAL_CONFIG_GET(grpc_dns_resolver); + if (should_use_ares(resolver.get())) { gpr_log(GPR_DEBUG, "Using ares dns resolver"); address_sorting_init(); grpc_error* error = grpc_ares_init(); @@ -456,22 +492,21 @@ void grpc_resolver_dns_ares_init() { grpc_core::UniquePtr( grpc_core::New())); } - gpr_free(resolver_env); } void grpc_resolver_dns_ares_shutdown() { - char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER"); - if (should_use_ares(resolver_env)) { + grpc_core::UniquePtr resolver = + GPR_GLOBAL_CONFIG_GET(grpc_dns_resolver); + if (should_use_ares(resolver.get())) { address_sorting_shutdown(); grpc_ares_cleanup(); } - gpr_free(resolver_env); } -#else /* GRPC_ARES == 1 && !defined(GRPC_UV) */ +#else /* GRPC_ARES == 1 */ void grpc_resolver_dns_ares_init(void) {} void grpc_resolver_dns_ares_shutdown(void) {} -#endif /* GRPC_ARES == 1 && !defined(GRPC_UV) */ +#endif /* GRPC_ARES == 1 */ diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc index d99c2e30047..4ad80786519 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc @@ -18,7 +18,7 @@ #include #include "src/core/lib/iomgr/port.h" -#if GRPC_ARES == 1 && !defined(GRPC_UV) +#if GRPC_ARES == 1 #include #include @@ -84,6 +84,10 @@ struct grpc_ares_ev_driver { grpc_timer query_timeout; /** cancels queries on a timeout */ grpc_closure on_timeout_locked; + /** alarm to poll ares_process on in case fd events don't happen */ + grpc_timer ares_backup_poll_alarm; + /** polls ares_process on a periodic timer */ + grpc_closure on_ares_backup_poll_alarm_locked; }; static void grpc_ares_notify_on_event_locked(grpc_ares_ev_driver* ev_driver); @@ -130,6 +134,13 @@ static void fd_node_shutdown_locked(fd_node* fdn, const char* reason) { static void on_timeout_locked(void* arg, grpc_error* error); +static void on_ares_backup_poll_alarm_locked(void* arg, grpc_error* error); + +static void noop_inject_channel_config(ares_channel channel) {} + +void (*grpc_ares_test_only_inject_config)(ares_channel channel) = + noop_inject_channel_config; + grpc_error* grpc_ares_ev_driver_create_locked(grpc_ares_ev_driver** ev_driver, grpc_pollset_set* pollset_set, int query_timeout_ms, @@ -140,6 +151,7 @@ grpc_error* grpc_ares_ev_driver_create_locked(grpc_ares_ev_driver** ev_driver, memset(&opts, 0, sizeof(opts)); opts.flags |= ARES_FLAG_STAYOPEN; int status = ares_init_options(&(*ev_driver)->channel, &opts, ARES_OPT_FLAGS); + grpc_ares_test_only_inject_config((*ev_driver)->channel); GRPC_CARES_TRACE_LOG("request:%p grpc_ares_ev_driver_create_locked", request); if (status != ARES_SUCCESS) { char* err_msg; @@ -163,6 +175,9 @@ grpc_error* grpc_ares_ev_driver_create_locked(grpc_ares_ev_driver** ev_driver, ->polled_fd_factory->ConfigureAresChannelLocked((*ev_driver)->channel); GRPC_CLOSURE_INIT(&(*ev_driver)->on_timeout_locked, on_timeout_locked, *ev_driver, grpc_combiner_scheduler(combiner)); + GRPC_CLOSURE_INIT(&(*ev_driver)->on_ares_backup_poll_alarm_locked, + on_ares_backup_poll_alarm_locked, *ev_driver, + grpc_combiner_scheduler(combiner)); (*ev_driver)->query_timeout_ms = query_timeout_ms; return GRPC_ERROR_NONE; } @@ -174,6 +189,7 @@ void grpc_ares_ev_driver_on_queries_complete_locked( // fds; if it's not working, there are no fds to shut down. ev_driver->shutting_down = true; grpc_timer_cancel(&ev_driver->query_timeout); + grpc_timer_cancel(&ev_driver->ares_backup_poll_alarm); grpc_ares_ev_driver_unref(ev_driver); } @@ -204,6 +220,21 @@ static fd_node* pop_fd_node_locked(fd_node** head, ares_socket_t as) { return nullptr; } +static grpc_millis calculate_next_ares_backup_poll_alarm_ms( + grpc_ares_ev_driver* driver) { + // An alternative here could be to use ares_timeout to try to be more + // accurate, but that would require using "struct timeval"'s, which just makes + // things a bit more complicated. So just poll every second, as suggested + // by the c-ares code comments. + grpc_millis ms_until_next_ares_backup_poll_alarm = 1000; + GRPC_CARES_TRACE_LOG( + "request:%p ev_driver=%p. next ares process poll time in " + "%" PRId64 " ms", + driver->request, driver, ms_until_next_ares_backup_poll_alarm); + return ms_until_next_ares_backup_poll_alarm + + grpc_core::ExecCtx::Get()->Now(); +} + static void on_timeout_locked(void* arg, grpc_error* error) { grpc_ares_ev_driver* driver = static_cast(arg); GRPC_CARES_TRACE_LOG( @@ -216,8 +247,50 @@ static void on_timeout_locked(void* arg, grpc_error* error) { grpc_ares_ev_driver_unref(driver); } +/* In case of non-responsive DNS servers, dropped packets, etc., c-ares has + * intelligent timeout and retry logic, which we can take advantage of by + * polling ares_process_fd on time intervals. Overall, the c-ares library is + * meant to be called into and given a chance to proceed name resolution: + * a) when fd events happen + * b) when some time has passed without fd events having happened + * For the latter, we use this backup poller. Also see + * https://github.com/grpc/grpc/pull/17688 description for more details. */ +static void on_ares_backup_poll_alarm_locked(void* arg, grpc_error* error) { + grpc_ares_ev_driver* driver = static_cast(arg); + GRPC_CARES_TRACE_LOG( + "request:%p ev_driver=%p on_ares_backup_poll_alarm_locked. " + "driver->shutting_down=%d. " + "err=%s", + driver->request, driver, driver->shutting_down, grpc_error_string(error)); + if (!driver->shutting_down && error == GRPC_ERROR_NONE) { + fd_node* fdn = driver->fds; + while (fdn != nullptr) { + if (!fdn->already_shutdown) { + GRPC_CARES_TRACE_LOG( + "request:%p ev_driver=%p on_ares_backup_poll_alarm_locked; " + "ares_process_fd. fd=%s", + driver->request, driver, fdn->grpc_polled_fd->GetName()); + ares_socket_t as = fdn->grpc_polled_fd->GetWrappedAresSocketLocked(); + ares_process_fd(driver->channel, as, as); + } + fdn = fdn->next; + } + if (!driver->shutting_down) { + grpc_millis next_ares_backup_poll_alarm = + calculate_next_ares_backup_poll_alarm_ms(driver); + grpc_ares_ev_driver_ref(driver); + grpc_timer_init(&driver->ares_backup_poll_alarm, + next_ares_backup_poll_alarm, + &driver->on_ares_backup_poll_alarm_locked); + } + grpc_ares_notify_on_event_locked(driver); + } + grpc_ares_ev_driver_unref(driver); +} + static void on_readable_locked(void* arg, grpc_error* error) { fd_node* fdn = static_cast(arg); + GPR_ASSERT(fdn->readable_registered); grpc_ares_ev_driver* ev_driver = fdn->ev_driver; const ares_socket_t as = fdn->grpc_polled_fd->GetWrappedAresSocketLocked(); fdn->readable_registered = false; @@ -242,6 +315,7 @@ static void on_readable_locked(void* arg, grpc_error* error) { static void on_writable_locked(void* arg, grpc_error* error) { fd_node* fdn = static_cast(arg); + GPR_ASSERT(fdn->writable_registered); grpc_ares_ev_driver* ev_driver = fdn->ev_driver; const ares_socket_t as = fdn->grpc_polled_fd->GetWrappedAresSocketLocked(); fdn->writable_registered = false; @@ -351,6 +425,7 @@ void grpc_ares_ev_driver_start_locked(grpc_ares_ev_driver* ev_driver) { if (!ev_driver->working) { ev_driver->working = true; grpc_ares_notify_on_event_locked(ev_driver); + // Initialize overall DNS resolution timeout alarm grpc_millis timeout = ev_driver->query_timeout_ms == 0 ? GRPC_MILLIS_INF_FUTURE @@ -362,7 +437,14 @@ void grpc_ares_ev_driver_start_locked(grpc_ares_ev_driver* ev_driver) { grpc_ares_ev_driver_ref(ev_driver); grpc_timer_init(&ev_driver->query_timeout, timeout, &ev_driver->on_timeout_locked); + // Initialize the backup poll alarm + grpc_millis next_ares_backup_poll_alarm = + calculate_next_ares_backup_poll_alarm_ms(ev_driver); + grpc_ares_ev_driver_ref(ev_driver); + grpc_timer_init(&ev_driver->ares_backup_poll_alarm, + next_ares_backup_poll_alarm, + &ev_driver->on_ares_backup_poll_alarm_locked); } } -#endif /* GRPC_ARES == 1 && !defined(GRPC_UV) */ +#endif /* GRPC_ARES == 1 */ diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h index b8cefd9470e..2d172eb3d1e 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h @@ -54,6 +54,9 @@ void grpc_ares_ev_driver_on_queries_complete_locked( /* Shutdown all the grpc_fds used by \a ev_driver */ void grpc_ares_ev_driver_shutdown_locked(grpc_ares_ev_driver* ev_driver); +/* Exposed in this header for C-core tests only */ +extern void (*grpc_ares_test_only_inject_config)(ares_channel channel); + namespace grpc_core { /* A wrapped fd that integrates with the grpc iomgr of the current platform. diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc new file mode 100644 index 00000000000..04e36fbcee7 --- /dev/null +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc @@ -0,0 +1,179 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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 + +#include "src/core/lib/iomgr/port.h" +#if GRPC_ARES == 1 && defined(GRPC_UV) + +#include +#include + +#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h" + +#include +#include +#include +#include +#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" +#include "src/core/lib/gpr/string.h" +#include "src/core/lib/iomgr/combiner.h" + +namespace grpc_core { + +void ares_uv_poll_cb(uv_poll_t* handle, int status, int events); + +void ares_uv_poll_close_cb(uv_handle_t* handle) { Delete(handle); } + +class GrpcPolledFdLibuv : public GrpcPolledFd { + public: + GrpcPolledFdLibuv(ares_socket_t as, grpc_combiner* combiner) + : as_(as), combiner_(combiner) { + gpr_asprintf(&name_, "c-ares socket: %" PRIdPTR, (intptr_t)as); + handle_ = New(); + uv_poll_init_socket(uv_default_loop(), handle_, as); + handle_->data = this; + GRPC_COMBINER_REF(combiner_, "libuv ares event driver"); + } + + ~GrpcPolledFdLibuv() { + gpr_free(name_); + GRPC_COMBINER_UNREF(combiner_, "libuv ares event driver"); + } + + void RegisterForOnReadableLocked(grpc_closure* read_closure) override { + GPR_ASSERT(read_closure_ == nullptr); + GPR_ASSERT((poll_events_ & UV_READABLE) == 0); + read_closure_ = read_closure; + poll_events_ |= UV_READABLE; + uv_poll_start(handle_, poll_events_, ares_uv_poll_cb); + } + + void RegisterForOnWriteableLocked(grpc_closure* write_closure) override { + GPR_ASSERT(write_closure_ == nullptr); + GPR_ASSERT((poll_events_ & UV_WRITABLE) == 0); + write_closure_ = write_closure; + poll_events_ |= UV_WRITABLE; + uv_poll_start(handle_, poll_events_, ares_uv_poll_cb); + } + + bool IsFdStillReadableLocked() override { + /* uv_poll_t is based on poll, which is level triggered. So, if cares + * leaves some data unread, the event will trigger again. */ + return false; + } + + void ShutdownInternalLocked(grpc_error* error) { + uv_poll_stop(handle_); + uv_close(reinterpret_cast(handle_), ares_uv_poll_close_cb); + if (read_closure_ != nullptr) { + GRPC_CLOSURE_SCHED(read_closure_, GRPC_ERROR_CANCELLED); + } + if (write_closure_ != nullptr) { + GRPC_CLOSURE_SCHED(write_closure_, GRPC_ERROR_CANCELLED); + } + } + + void ShutdownLocked(grpc_error* error) override { + if (grpc_core::ExecCtx::Get() == nullptr) { + grpc_core::ExecCtx exec_ctx; + ShutdownInternalLocked(error); + } else { + ShutdownInternalLocked(error); + } + } + + ares_socket_t GetWrappedAresSocketLocked() override { return as_; } + + const char* GetName() override { return name_; } + + char* name_; + ares_socket_t as_; + uv_poll_t* handle_; + grpc_closure* read_closure_ = nullptr; + grpc_closure* write_closure_ = nullptr; + int poll_events_ = 0; + grpc_combiner* combiner_; +}; + +struct AresUvPollCbArg { + AresUvPollCbArg(uv_poll_t* handle, int status, int events) + : handle(handle), status(status), events(events) {} + + uv_poll_t* handle; + int status; + int events; +}; + +static void ares_uv_poll_cb_locked(void* arg, grpc_error* error) { + grpc_core::UniquePtr arg_struct( + reinterpret_cast(arg)); + uv_poll_t* handle = arg_struct->handle; + int status = arg_struct->status; + int events = arg_struct->events; + GrpcPolledFdLibuv* polled_fd = + reinterpret_cast(handle->data); + if (status < 0) { + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("cares polling error"); + error = + grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, + grpc_slice_from_static_string(uv_strerror(status))); + } + if (events & UV_READABLE) { + GPR_ASSERT(polled_fd->read_closure_ != nullptr); + GRPC_CLOSURE_SCHED(polled_fd->read_closure_, error); + polled_fd->read_closure_ = nullptr; + polled_fd->poll_events_ &= ~UV_READABLE; + } + if (events & UV_WRITABLE) { + GPR_ASSERT(polled_fd->write_closure_ != nullptr); + GRPC_CLOSURE_SCHED(polled_fd->write_closure_, error); + polled_fd->write_closure_ = nullptr; + polled_fd->poll_events_ &= ~UV_WRITABLE; + } + uv_poll_start(handle, polled_fd->poll_events_, ares_uv_poll_cb); +} + +void ares_uv_poll_cb(uv_poll_t* handle, int status, int events) { + grpc_core::ExecCtx exec_ctx; + GrpcPolledFdLibuv* polled_fd = + reinterpret_cast(handle->data); + AresUvPollCbArg* arg = New(handle, status, events); + GRPC_CLOSURE_SCHED( + GRPC_CLOSURE_CREATE(ares_uv_poll_cb_locked, arg, + grpc_combiner_scheduler(polled_fd->combiner_)), + GRPC_ERROR_NONE); +} + +class GrpcPolledFdFactoryLibuv : public GrpcPolledFdFactory { + public: + GrpcPolledFd* NewGrpcPolledFdLocked(ares_socket_t as, + grpc_pollset_set* driver_pollset_set, + grpc_combiner* combiner) override { + return New(as, combiner); + } + + void ConfigureAresChannelLocked(ares_channel channel) override {} +}; + +UniquePtr NewGrpcPolledFdFactory(grpc_combiner* combiner) { + return UniquePtr(New()); +} + +} // namespace grpc_core + +#endif /* GRPC_ARES == 1 && defined(GRPC_UV) */ diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc index 9570e32c150..85f5cd84ca0 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc @@ -18,7 +18,7 @@ #include #include "src/core/lib/iomgr/port.h" -#if GRPC_ARES == 1 && defined(GPR_WINDOWS) +#if GRPC_ARES == 1 && defined(GRPC_WINDOWS_SOCKET_ARES_EV_DRIVER) #include @@ -109,6 +109,7 @@ class GrpcPolledFdWindows : public GrpcPolledFd { read_closure_ = read_closure; GPR_ASSERT(GRPC_SLICE_LENGTH(read_buf_) == 0); grpc_slice_unref_internal(read_buf_); + GPR_ASSERT(!read_buf_has_data_); read_buf_ = GRPC_SLICE_MALLOC(4192); WSABUF buffer; buffer.buf = (char*)GRPC_SLICE_START_PTR(read_buf_); @@ -175,7 +176,7 @@ class GrpcPolledFdWindows : public GrpcPolledFd { GRPC_CARES_TRACE_LOG( "RecvFrom called on fd:|%s|. Current read buf length:|%d|", GetName(), GRPC_SLICE_LENGTH(read_buf_)); - if (GRPC_SLICE_LENGTH(read_buf_) == 0) { + if (!read_buf_has_data_) { WSASetLastError(WSAEWOULDBLOCK); return -1; } @@ -186,6 +187,9 @@ class GrpcPolledFdWindows : public GrpcPolledFd { } read_buf_ = grpc_slice_sub_no_ref(read_buf_, bytes_read, GRPC_SLICE_LENGTH(read_buf_)); + if (GRPC_SLICE_LENGTH(read_buf_) == 0) { + read_buf_has_data_ = false; + } /* c-ares overloads this recv_from virtual socket function to receive * data on both UDP and TCP sockets, and from is nullptr for TCP. */ if (from != nullptr) { @@ -302,6 +306,11 @@ class GrpcPolledFdWindows : public GrpcPolledFd { polled_fd->OnIocpReadableInner(error); } + // TODO(apolcyn): improve this error handling to be less conversative. + // An e.g. ECONNRESET error here should result in errors when + // c-ares reads from this socket later, but it shouldn't necessarily cancel + // the entire resolution attempt. Doing so will allow the "inject broken + // nameserver list" test to pass on Windows. void OnIocpReadableInner(grpc_error* error) { if (error == GRPC_ERROR_NONE) { if (winsocket_->read_info.wsa_error != 0) { @@ -323,6 +332,7 @@ class GrpcPolledFdWindows : public GrpcPolledFd { if (error == GRPC_ERROR_NONE) { read_buf_ = grpc_slice_sub_no_ref(read_buf_, 0, winsocket_->read_info.bytes_transfered); + read_buf_has_data_ = true; } else { grpc_slice_unref_internal(read_buf_); read_buf_ = grpc_empty_slice(); @@ -370,6 +380,7 @@ class GrpcPolledFdWindows : public GrpcPolledFd { char recv_from_source_addr_[200]; ares_socklen_t recv_from_source_addr_len_; grpc_slice read_buf_; + bool read_buf_has_data_ = false; grpc_slice write_buf_; grpc_closure* read_closure_ = nullptr; grpc_closure* write_closure_ = nullptr; @@ -445,7 +456,8 @@ class SockToPolledFdMap { */ static ares_socket_t Socket(int af, int type, int protocol, void* user_data) { SockToPolledFdMap* map = static_cast(user_data); - SOCKET s = WSASocket(af, type, protocol, nullptr, 0, WSA_FLAG_OVERLAPPED); + SOCKET s = WSASocket(af, type, protocol, nullptr, 0, + grpc_get_default_wsa_socket_flags()); if (s == INVALID_SOCKET) { return s; } diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc index 37b0b365eed..ad0f1460121 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc @@ -18,7 +18,7 @@ #include -#if GRPC_ARES == 1 && !defined(GRPC_UV) +#if GRPC_ARES == 1 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/lib/iomgr/sockaddr.h" @@ -101,7 +101,7 @@ static void log_address_sorting_list(const ServerAddressList& addresses, } void grpc_cares_wrapper_address_sorting_sort(ServerAddressList* addresses) { - if (grpc_trace_cares_address_sorting.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_cares_address_sorting)) { log_address_sorting_list(*addresses, "input"); } address_sorting_sortable* sortables = (address_sorting_sortable*)gpr_zalloc( @@ -120,7 +120,7 @@ void grpc_cares_wrapper_address_sorting_sort(ServerAddressList* addresses) { } gpr_free(sortables); *addresses = std::move(sorted); - if (grpc_trace_cares_address_sorting.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_cares_address_sorting)) { log_address_sorting_list(*addresses, "output"); } } @@ -154,6 +154,10 @@ void grpc_ares_complete_request_locked(grpc_ares_request* r) { static grpc_ares_hostbyname_request* create_hostbyname_request_locked( grpc_ares_request* parent_request, char* host, uint16_t port, bool is_balancer) { + GRPC_CARES_TRACE_LOG( + "request:%p create_hostbyname_request_locked host:%s port:%d " + "is_balancer:%d", + parent_request, host, port, is_balancer); grpc_ares_hostbyname_request* hr = static_cast( gpr_zalloc(sizeof(grpc_ares_hostbyname_request))); hr->parent_request = parent_request; @@ -251,6 +255,8 @@ static void on_srv_query_done_locked(void* arg, int status, int timeouts, GRPC_CARES_TRACE_LOG("request:%p on_srv_query_done_locked ARES_SUCCESS", r); struct ares_srv_reply* reply; const int parse_status = ares_parse_srv_reply(abuf, alen, &reply); + GRPC_CARES_TRACE_LOG("request:%p ares_parse_srv_reply: %d", r, + parse_status); if (parse_status == ARES_SUCCESS) { ares_channel* channel = grpc_ares_ev_driver_get_channel_locked(r->ev_driver); @@ -516,6 +522,76 @@ static bool target_matches_localhost(const char* name) { return out; } +#ifdef GRPC_ARES_RESOLVE_LOCALHOST_MANUALLY +static bool inner_maybe_resolve_localhost_manually_locked( + const char* name, const char* default_port, + grpc_core::UniquePtr* addrs, char** host, + char** port) { + gpr_split_host_port(name, host, port); + if (*host == nullptr) { + gpr_log(GPR_ERROR, + "Failed to parse %s into host:port during manual localhost " + "resolution check.", + name); + return false; + } + if (*port == nullptr) { + if (default_port == nullptr) { + gpr_log(GPR_ERROR, + "No port or default port for %s during manual localhost " + "resolution check.", + name); + return false; + } + *port = gpr_strdup(default_port); + } + if (gpr_stricmp(*host, "localhost") == 0) { + GPR_ASSERT(*addrs == nullptr); + *addrs = grpc_core::MakeUnique(); + uint16_t numeric_port = grpc_strhtons(*port); + // Append the ipv6 loopback address. + struct sockaddr_in6 ipv6_loopback_addr; + memset(&ipv6_loopback_addr, 0, sizeof(ipv6_loopback_addr)); + ((char*)&ipv6_loopback_addr.sin6_addr)[15] = 1; + ipv6_loopback_addr.sin6_family = AF_INET6; + ipv6_loopback_addr.sin6_port = numeric_port; + (*addrs)->emplace_back(&ipv6_loopback_addr, sizeof(ipv6_loopback_addr), + nullptr /* args */); + // Append the ipv4 loopback address. + struct sockaddr_in ipv4_loopback_addr; + memset(&ipv4_loopback_addr, 0, sizeof(ipv4_loopback_addr)); + ((char*)&ipv4_loopback_addr.sin_addr)[0] = 0x7f; + ((char*)&ipv4_loopback_addr.sin_addr)[3] = 0x01; + ipv4_loopback_addr.sin_family = AF_INET; + ipv4_loopback_addr.sin_port = numeric_port; + (*addrs)->emplace_back(&ipv4_loopback_addr, sizeof(ipv4_loopback_addr), + nullptr /* args */); + // Let the address sorter figure out which one should be tried first. + grpc_cares_wrapper_address_sorting_sort(addrs->get()); + return true; + } + return false; +} + +static bool grpc_ares_maybe_resolve_localhost_manually_locked( + const char* name, const char* default_port, + grpc_core::UniquePtr* addrs) { + char* host = nullptr; + char* port = nullptr; + bool out = inner_maybe_resolve_localhost_manually_locked(name, default_port, + addrs, &host, &port); + gpr_free(host); + gpr_free(port); + return out; +} +#else /* GRPC_ARES_RESOLVE_LOCALHOST_MANUALLY */ +static bool grpc_ares_maybe_resolve_localhost_manually_locked( + const char* name, const char* default_port, + grpc_core::UniquePtr* addrs) { + return false; +} +#endif /* GRPC_ARES_RESOLVE_LOCALHOST_MANUALLY */ + static grpc_ares_request* grpc_dns_lookup_ares_locked_impl( const char* dns_server, const char* name, const char* default_port, grpc_pollset_set* interested_parties, grpc_closure* on_done, @@ -687,4 +763,4 @@ void (*grpc_resolve_address_ares)( grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_resolved_addresses** addrs) = grpc_resolve_address_ares_impl; -#endif /* GRPC_ARES == 1 && !defined(GRPC_UV) */ +#endif /* GRPC_ARES == 1 */ diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h index 28082504565..cc977c06b25 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h @@ -26,16 +26,18 @@ #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/iomgr/resolve_address.h" -#define GRPC_DNS_ARES_DEFAULT_QUERY_TIMEOUT_MS 10000 +#define GRPC_DNS_ARES_DEFAULT_QUERY_TIMEOUT_MS 120000 extern grpc_core::TraceFlag grpc_trace_cares_address_sorting; extern grpc_core::TraceFlag grpc_trace_cares_resolver; -#define GRPC_CARES_TRACE_LOG(format, ...) \ - if (grpc_trace_cares_resolver.enabled()) { \ - gpr_log(GPR_DEBUG, "(c-ares resolver) " format, __VA_ARGS__); \ - } +#define GRPC_CARES_TRACE_LOG(format, ...) \ + do { \ + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_cares_resolver)) { \ + gpr_log(GPR_DEBUG, "(c-ares resolver) " format, __VA_ARGS__); \ + } \ + } while (0) typedef struct grpc_ares_request grpc_ares_request; @@ -85,14 +87,6 @@ void grpc_ares_complete_request_locked(grpc_ares_request* request); /* E.g., return false if ipv6 is known to not be available. */ bool grpc_ares_query_ipv6(); -/* Maybe (depending on the current platform) checks if "name" matches - * "localhost" and if so fills in addrs with the correct sockaddr structures. - * Returns a bool indicating whether or not such an action was performed. - * See https://github.com/grpc/grpc/issues/15158. */ -bool grpc_ares_maybe_resolve_localhost_manually_locked( - const char* name, const char* default_port, - grpc_core::UniquePtr* addrs); - /* Sorts destinations in lb_addrs according to RFC 6724. */ void grpc_cares_wrapper_address_sorting_sort( grpc_core::ServerAddressList* addresses); diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc index 1f4701c9994..d2de88eaa1e 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc @@ -18,7 +18,7 @@ #include -#if GRPC_ARES != 1 || defined(GRPC_UV) +#if GRPC_ARES != 1 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" @@ -62,4 +62,4 @@ void (*grpc_resolve_address_ares)( grpc_pollset_set* interested_parties, grpc_closure* on_done, grpc_resolved_addresses** addrs) = grpc_resolve_address_ares_impl; -#endif /* GRPC_ARES != 1 || defined(GRPC_UV) */ +#endif /* GRPC_ARES != 1 */ diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc new file mode 100644 index 00000000000..f85feb674dd --- /dev/null +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc @@ -0,0 +1,39 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * 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 + +#include "src/core/lib/iomgr/port.h" +#if GRPC_ARES == 1 && defined(GRPC_UV) + +#include + +#include "src/core/ext/filters/client_channel/parse_address.h" +#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" +#include "src/core/ext/filters/client_channel/server_address.h" +#include "src/core/lib/gpr/host_port.h" +#include "src/core/lib/gpr/string.h" + +bool grpc_ares_query_ipv6() { + /* The libuv grpc code currently does not have the code to probe for this, + * so we assume for now that IPv6 is always available in contexts where this + * code will be used. */ + return true; +} + +#endif /* GRPC_ARES == 1 && defined(GRPC_UV) */ diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc index 028d8442169..23c0fec74f3 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc @@ -26,10 +26,4 @@ bool grpc_ares_query_ipv6() { return grpc_ipv6_loopback_available(); } -bool grpc_ares_maybe_resolve_localhost_manually_locked( - const char* name, const char* default_port, - grpc_core::UniquePtr* addrs) { - return false; -} - #endif /* GRPC_ARES == 1 && defined(GRPC_POSIX_SOCKET_ARES_EV_DRIVER) */ diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc index 202452f1b2b..06cd5722ce3 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc @@ -19,7 +19,7 @@ #include #include "src/core/lib/iomgr/port.h" -#if GRPC_ARES == 1 && defined(GPR_WINDOWS) +#if GRPC_ARES == 1 && defined(GRPC_WINDOWS_SOCKET_ARES_EV_DRIVER) #include @@ -32,66 +32,4 @@ bool grpc_ares_query_ipv6() { return grpc_ipv6_loopback_available(); } -static bool inner_maybe_resolve_localhost_manually_locked( - const char* name, const char* default_port, - grpc_core::UniquePtr* addrs, char** host, - char** port) { - gpr_split_host_port(name, host, port); - if (*host == nullptr) { - gpr_log(GPR_ERROR, - "Failed to parse %s into host:port during Windows localhost " - "resolution check.", - name); - return false; - } - if (*port == nullptr) { - if (default_port == nullptr) { - gpr_log(GPR_ERROR, - "No port or default port for %s during Windows localhost " - "resolution check.", - name); - return false; - } - *port = gpr_strdup(default_port); - } - if (gpr_stricmp(*host, "localhost") == 0) { - GPR_ASSERT(*addrs == nullptr); - *addrs = grpc_core::MakeUnique(); - uint16_t numeric_port = grpc_strhtons(*port); - // Append the ipv6 loopback address. - struct sockaddr_in6 ipv6_loopback_addr; - memset(&ipv6_loopback_addr, 0, sizeof(ipv6_loopback_addr)); - ((char*)&ipv6_loopback_addr.sin6_addr)[15] = 1; - ipv6_loopback_addr.sin6_family = AF_INET6; - ipv6_loopback_addr.sin6_port = numeric_port; - (*addrs)->emplace_back(&ipv6_loopback_addr, sizeof(ipv6_loopback_addr), - nullptr /* args */); - // Append the ipv4 loopback address. - struct sockaddr_in ipv4_loopback_addr; - memset(&ipv4_loopback_addr, 0, sizeof(ipv4_loopback_addr)); - ((char*)&ipv4_loopback_addr.sin_addr)[0] = 0x7f; - ((char*)&ipv4_loopback_addr.sin_addr)[3] = 0x01; - ipv4_loopback_addr.sin_family = AF_INET; - ipv4_loopback_addr.sin_port = numeric_port; - (*addrs)->emplace_back(&ipv4_loopback_addr, sizeof(ipv4_loopback_addr), - nullptr /* args */); - // Let the address sorter figure out which one should be tried first. - grpc_cares_wrapper_address_sorting_sort(addrs->get()); - return true; - } - return false; -} - -bool grpc_ares_maybe_resolve_localhost_manually_locked( - const char* name, const char* default_port, - grpc_core::UniquePtr* addrs) { - char* host = nullptr; - char* port = nullptr; - bool out = inner_maybe_resolve_localhost_manually_locked(name, default_port, - addrs, &host, &port); - gpr_free(host); - gpr_free(port); - return out; -} - -#endif /* GRPC_ARES == 1 && defined(GPR_WINDOWS) */ +#endif /* GRPC_ARES == 1 && defined(GRPC_WINDOWS_SOCKET_ARES_EV_DRIVER) */ diff --git a/src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc b/src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc new file mode 100644 index 00000000000..07a617c14d5 --- /dev/null +++ b/src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc @@ -0,0 +1,28 @@ +// +// Copyright 2019 gRPC authors. +// +// 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. +// + +// This is similar to the sockaddr resolver, except that it supports a +// bunch of query args that are useful for dependency injection in tests. + +#include + +#include "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h" + +GPR_GLOBAL_CONFIG_DEFINE_STRING( + grpc_dns_resolver, "", + "Declares which DNS resolver to use. The default is ares if gRPC is built " + "with c-ares support. Otherwise, the value of this environment variable is " + "ignored.") diff --git a/src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h b/src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h new file mode 100644 index 00000000000..d0a3486ea38 --- /dev/null +++ b/src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h @@ -0,0 +1,29 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_DNS_RESOLVER_SELECTION_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_DNS_RESOLVER_SELECTION_H + +#include + +#include "src/core/lib/gprpp/global_config.h" + +GPR_GLOBAL_CONFIG_DECLARE_STRING(grpc_dns_resolver); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_DNS_RESOLVER_SELECTION_H \ + */ diff --git a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc index 164d308c0dd..5ab75d02793 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc @@ -26,11 +26,11 @@ #include #include +#include "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" #include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gprpp/manual_constructor.h" @@ -274,8 +274,9 @@ class NativeDnsResolverFactory : public ResolverFactory { } // namespace grpc_core void grpc_resolver_dns_native_init() { - char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER"); - if (resolver_env != nullptr && gpr_stricmp(resolver_env, "native") == 0) { + grpc_core::UniquePtr resolver = + GPR_GLOBAL_CONFIG_GET(grpc_dns_resolver); + if (gpr_stricmp(resolver.get(), "native") == 0) { gpr_log(GPR_DEBUG, "Using native dns resolver"); grpc_core::ResolverRegistry::Builder::RegisterResolverFactory( grpc_core::UniquePtr( @@ -291,7 +292,6 @@ void grpc_resolver_dns_native_init() { grpc_core::New())); } } - gpr_free(resolver_env); } void grpc_resolver_dns_native_shutdown() {} diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc index 85b9bea6f70..7f613ee21bc 100644 --- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc @@ -175,11 +175,13 @@ void FakeResolverResponseGenerator::SetResponseLocked(void* arg, resolver->next_result_ = std::move(closure_arg->result); resolver->has_next_result_ = true; resolver->MaybeSendResultLocked(); + closure_arg->generator->Unref(); Delete(closure_arg); } void FakeResolverResponseGenerator::SetResponse(Resolver::Result result) { if (resolver_ != nullptr) { + Ref().release(); // ref to be held by closure SetResponseClosureArg* closure_arg = New(); closure_arg->generator = this; closure_arg->result = std::move(result); diff --git a/src/core/ext/filters/client_channel/resolver_result_parsing.cc b/src/core/ext/filters/client_channel/resolver_result_parsing.cc index 7148e16e70b..6a811a2d936 100644 --- a/src/core/ext/filters/client_channel/resolver_result_parsing.cc +++ b/src/core/ext/filters/client_channel/resolver_result_parsing.cc @@ -35,6 +35,7 @@ #include "src/core/lib/channel/status_util.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gprpp/memory.h" +#include "src/core/lib/gprpp/optional.h" #include "src/core/lib/uri/uri_parser.h" // As per the retry design, we do not allow more than 5 retry attempts. @@ -43,206 +44,22 @@ namespace grpc_core { namespace internal { -ProcessedResolverResult::ProcessedResolverResult( - Resolver::Result* resolver_result, bool parse_retry) - : service_config_(resolver_result->service_config) { - // If resolver did not return a service config, use the default - // specified via the client API. - if (service_config_ == nullptr) { - const char* service_config_json = grpc_channel_arg_get_string( - grpc_channel_args_find(resolver_result->args, GRPC_ARG_SERVICE_CONFIG)); - if (service_config_json != nullptr) { - grpc_error* error = GRPC_ERROR_NONE; - service_config_ = ServiceConfig::Create(service_config_json, &error); - // Error is currently unused. - GRPC_ERROR_UNREF(error); - } - } else { - // Add the service config JSON to channel args so that it's - // accessible in the subchannel. - // TODO(roth): Consider whether there's a better way to pass the - // service config down into the subchannel stack, such as maybe via - // call context or metadata. This would avoid the problem of having - // to recreate all subchannels whenever the service config changes. - // It would also avoid the need to pass in the resolver result in - // mutable form, both here and in - // ResolvingLoadBalancingPolicy::ProcessResolverResultCallback(). - grpc_arg arg = grpc_channel_arg_string_create( - const_cast(GRPC_ARG_SERVICE_CONFIG), - const_cast(service_config_->service_config_json())); - grpc_channel_args* new_args = - grpc_channel_args_copy_and_add(resolver_result->args, &arg, 1); - grpc_channel_args_destroy(resolver_result->args); - resolver_result->args = new_args; - } - // Process service config. - ProcessServiceConfig(*resolver_result, parse_retry); - // If no LB config was found above, just find the LB policy name then. - if (lb_policy_name_ == nullptr) ProcessLbPolicyName(*resolver_result); -} - -void ProcessedResolverResult::ProcessServiceConfig( - const Resolver::Result& resolver_result, bool parse_retry) { - if (service_config_ == nullptr) return; - service_config_json_ = - UniquePtr(gpr_strdup(service_config_->service_config_json())); - if (parse_retry) { - const grpc_arg* channel_arg = - grpc_channel_args_find(resolver_result.args, GRPC_ARG_SERVER_URI); - const char* server_uri = grpc_channel_arg_get_string(channel_arg); - GPR_ASSERT(server_uri != nullptr); - grpc_uri* uri = grpc_uri_parse(server_uri, true); - GPR_ASSERT(uri->path[0] != '\0'); - server_name_ = uri->path[0] == '/' ? uri->path + 1 : uri->path; - service_config_->ParseGlobalParams(ParseServiceConfig, this); - grpc_uri_destroy(uri); - } else { - service_config_->ParseGlobalParams(ParseServiceConfig, this); - } - method_params_table_ = service_config_->CreateMethodConfigTable( - ClientChannelMethodParams::CreateFromJson); -} - -void ProcessedResolverResult::ProcessLbPolicyName( - const Resolver::Result& resolver_result) { - // Prefer the LB policy name found in the service config. Note that this is - // checking the deprecated loadBalancingPolicy field, rather than the new - // loadBalancingConfig field. - if (service_config_ != nullptr) { - lb_policy_name_.reset( - gpr_strdup(service_config_->GetLoadBalancingPolicyName())); - // Convert to lower-case. - if (lb_policy_name_ != nullptr) { - char* lb_policy_name = lb_policy_name_.get(); - for (size_t i = 0; i < strlen(lb_policy_name); ++i) { - lb_policy_name[i] = tolower(lb_policy_name[i]); - } - } - } - // Otherwise, find the LB policy name set by the client API. - if (lb_policy_name_ == nullptr) { - const grpc_arg* channel_arg = - grpc_channel_args_find(resolver_result.args, GRPC_ARG_LB_POLICY_NAME); - lb_policy_name_.reset(gpr_strdup(grpc_channel_arg_get_string(channel_arg))); - } - // Special case: If at least one balancer address is present, we use - // the grpclb policy, regardless of what the resolver has returned. - bool found_balancer_address = false; - for (size_t i = 0; i < resolver_result.addresses.size(); ++i) { - const ServerAddress& address = resolver_result.addresses[i]; - if (address.IsBalancer()) { - found_balancer_address = true; - break; - } - } - if (found_balancer_address) { - if (lb_policy_name_ != nullptr && - strcmp(lb_policy_name_.get(), "grpclb") != 0) { - gpr_log(GPR_INFO, - "resolver requested LB policy %s but provided at least one " - "balancer address -- forcing use of grpclb LB policy", - lb_policy_name_.get()); - } - lb_policy_name_.reset(gpr_strdup("grpclb")); - } - // Use pick_first if nothing was specified and we didn't select grpclb - // above. - if (lb_policy_name_ == nullptr) { - lb_policy_name_.reset(gpr_strdup("pick_first")); - } +namespace { +size_t g_client_channel_service_config_parser_index; } -void ProcessedResolverResult::ParseServiceConfig( - const grpc_json* field, ProcessedResolverResult* parsing_state) { - parsing_state->ParseLbConfigFromServiceConfig(field); - if (parsing_state->server_name_ != nullptr) { - parsing_state->ParseRetryThrottleParamsFromServiceConfig(field); - } +size_t ClientChannelServiceConfigParser::ParserIndex() { + return g_client_channel_service_config_parser_index; } -void ProcessedResolverResult::ParseLbConfigFromServiceConfig( - const grpc_json* field) { - if (lb_policy_config_ != nullptr) return; // Already found. - if (field->key == nullptr || strcmp(field->key, "loadBalancingConfig") != 0) { - return; // Not the LB config global parameter. - } - const grpc_json* policy = - LoadBalancingPolicy::ParseLoadBalancingConfig(field); - if (policy != nullptr) { - lb_policy_name_.reset(gpr_strdup(policy->key)); - lb_policy_config_ = - MakeRefCounted(policy, service_config_); - } -} - -void ProcessedResolverResult::ParseRetryThrottleParamsFromServiceConfig( - const grpc_json* field) { - if (strcmp(field->key, "retryThrottling") == 0) { - if (retry_throttle_data_ != nullptr) return; // Duplicate. - if (field->type != GRPC_JSON_OBJECT) return; - int max_milli_tokens = 0; - int milli_token_ratio = 0; - for (grpc_json* sub_field = field->child; sub_field != nullptr; - sub_field = sub_field->next) { - if (sub_field->key == nullptr) return; - if (strcmp(sub_field->key, "maxTokens") == 0) { - if (max_milli_tokens != 0) return; // Duplicate. - if (sub_field->type != GRPC_JSON_NUMBER) return; - max_milli_tokens = gpr_parse_nonnegative_int(sub_field->value); - if (max_milli_tokens == -1) return; - max_milli_tokens *= 1000; - } else if (strcmp(sub_field->key, "tokenRatio") == 0) { - if (milli_token_ratio != 0) return; // Duplicate. - if (sub_field->type != GRPC_JSON_NUMBER) return; - // We support up to 3 decimal digits. - size_t whole_len = strlen(sub_field->value); - uint32_t multiplier = 1; - uint32_t decimal_value = 0; - const char* decimal_point = strchr(sub_field->value, '.'); - if (decimal_point != nullptr) { - whole_len = static_cast(decimal_point - sub_field->value); - multiplier = 1000; - size_t decimal_len = strlen(decimal_point + 1); - if (decimal_len > 3) decimal_len = 3; - if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len, - &decimal_value)) { - return; - } - uint32_t decimal_multiplier = 1; - for (size_t i = 0; i < (3 - decimal_len); ++i) { - decimal_multiplier *= 10; - } - decimal_value *= decimal_multiplier; - } - uint32_t whole_value; - if (!gpr_parse_bytes_to_uint32(sub_field->value, whole_len, - &whole_value)) { - return; - } - milli_token_ratio = - static_cast((whole_value * multiplier) + decimal_value); - if (milli_token_ratio <= 0) return; - } - } - retry_throttle_data_ = - grpc_core::internal::ServerRetryThrottleMap::GetDataForServer( - server_name_, max_milli_tokens, milli_token_ratio); - } +void ClientChannelServiceConfigParser::Register() { + g_client_channel_service_config_parser_index = + ServiceConfig::RegisterParser(UniquePtr( + New())); } namespace { -bool ParseWaitForReady( - grpc_json* field, ClientChannelMethodParams::WaitForReady* wait_for_ready) { - if (field->type != GRPC_JSON_TRUE && field->type != GRPC_JSON_FALSE) { - return false; - } - *wait_for_ready = field->type == GRPC_JSON_TRUE - ? ClientChannelMethodParams::WAIT_FOR_READY_TRUE - : ClientChannelMethodParams::WAIT_FOR_READY_FALSE; - return true; -} - // Parses a JSON field of the form generated for a google.proto.Duration // proto message, as per: // https://developers.google.com/protocol-buffers/docs/proto3#json @@ -275,18 +92,36 @@ bool ParseDuration(grpc_json* field, grpc_millis* duration) { return true; } -UniquePtr ParseRetryPolicy( - grpc_json* field) { - auto retry_policy = MakeUnique(); - if (field->type != GRPC_JSON_OBJECT) return nullptr; +UniquePtr ParseRetryPolicy( + grpc_json* field, grpc_error** error) { + GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE); + auto retry_policy = + MakeUnique(); + if (field->type != GRPC_JSON_OBJECT) { + *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryPolicy error:should be of type object"); + return nullptr; + } + InlinedVector error_list; for (grpc_json* sub_field = field->child; sub_field != nullptr; sub_field = sub_field->next) { - if (sub_field->key == nullptr) return nullptr; + if (sub_field->key == nullptr) continue; if (strcmp(sub_field->key, "maxAttempts") == 0) { - if (retry_policy->max_attempts != 0) return nullptr; // Duplicate. - if (sub_field->type != GRPC_JSON_NUMBER) return nullptr; + if (retry_policy->max_attempts != 0) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:maxAttempts error:Duplicate entry")); + } // Duplicate. Continue Parsing + if (sub_field->type != GRPC_JSON_NUMBER) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:maxAttempts error:should be of type number")); + continue; + } retry_policy->max_attempts = gpr_parse_nonnegative_int(sub_field->value); - if (retry_policy->max_attempts <= 1) return nullptr; + if (retry_policy->max_attempts <= 1) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:maxAttempts error:should be at least 2")); + continue; + } if (retry_policy->max_attempts > MAX_MAX_RETRY_ATTEMPTS) { gpr_log(GPR_ERROR, "service config: clamped retryPolicy.maxAttempts at %d", @@ -294,78 +129,375 @@ UniquePtr ParseRetryPolicy( retry_policy->max_attempts = MAX_MAX_RETRY_ATTEMPTS; } } else if (strcmp(sub_field->key, "initialBackoff") == 0) { - if (retry_policy->initial_backoff > 0) return nullptr; // Duplicate. + if (retry_policy->initial_backoff > 0) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:initialBackoff error:Duplicate entry")); + } // Duplicate, continue parsing. if (!ParseDuration(sub_field, &retry_policy->initial_backoff)) { - return nullptr; + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:initialBackoff error:Failed to parse")); + continue; + } + if (retry_policy->initial_backoff == 0) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:initialBackoff error:must be greater than 0")); } - if (retry_policy->initial_backoff == 0) return nullptr; } else if (strcmp(sub_field->key, "maxBackoff") == 0) { - if (retry_policy->max_backoff > 0) return nullptr; // Duplicate. + if (retry_policy->max_backoff > 0) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:maxBackoff error:Duplicate entry")); + } // Duplicate, continue parsing. if (!ParseDuration(sub_field, &retry_policy->max_backoff)) { - return nullptr; + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:maxBackoff error:failed to parse")); + continue; + } + if (retry_policy->max_backoff == 0) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:maxBackoff error:should be greater than 0")); } - if (retry_policy->max_backoff == 0) return nullptr; } else if (strcmp(sub_field->key, "backoffMultiplier") == 0) { - if (retry_policy->backoff_multiplier != 0) return nullptr; // Duplicate. - if (sub_field->type != GRPC_JSON_NUMBER) return nullptr; + if (retry_policy->backoff_multiplier != 0) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:backoffMultiplier error:Duplicate entry")); + } // Duplicate, continue parsing. + if (sub_field->type != GRPC_JSON_NUMBER) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:backoffMultiplier error:should be of type number")); + continue; + } if (sscanf(sub_field->value, "%f", &retry_policy->backoff_multiplier) != 1) { - return nullptr; + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:backoffMultiplier error:failed to parse")); + continue; + } + if (retry_policy->backoff_multiplier <= 0) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:backoffMultiplier error:should be greater than 0")); } - if (retry_policy->backoff_multiplier <= 0) return nullptr; } else if (strcmp(sub_field->key, "retryableStatusCodes") == 0) { if (!retry_policy->retryable_status_codes.Empty()) { - return nullptr; // Duplicate. + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryableStatusCodes error:Duplicate entry")); + } // Duplicate, continue parsing. + if (sub_field->type != GRPC_JSON_ARRAY) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryableStatusCodes error:should be of type array")); + continue; } - if (sub_field->type != GRPC_JSON_ARRAY) return nullptr; for (grpc_json* element = sub_field->child; element != nullptr; element = element->next) { - if (element->type != GRPC_JSON_STRING) return nullptr; + if (element->type != GRPC_JSON_STRING) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryableStatusCodes error:status codes should be of type " + "string")); + continue; + } grpc_status_code status; if (!grpc_status_code_from_string(element->value, &status)) { - return nullptr; + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryableStatusCodes error:failed to parse status code")); + continue; } retry_policy->retryable_status_codes.Add(status); } - if (retry_policy->retryable_status_codes.Empty()) return nullptr; + if (retry_policy->retryable_status_codes.Empty()) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryableStatusCodes error:should be non-empty")); + }; } } // Make sure required fields are set. - if (retry_policy->max_attempts == 0 || retry_policy->initial_backoff == 0 || - retry_policy->max_backoff == 0 || retry_policy->backoff_multiplier == 0 || - retry_policy->retryable_status_codes.Empty()) { + if (error_list.empty()) { + if (retry_policy->max_attempts == 0 || retry_policy->initial_backoff == 0 || + retry_policy->max_backoff == 0 || + retry_policy->backoff_multiplier == 0 || + retry_policy->retryable_status_codes.Empty()) { + *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryPolicy error:Missing required field(s)"); + return nullptr; + } + } + *error = GRPC_ERROR_CREATE_FROM_VECTOR("retryPolicy", &error_list); + return *error == GRPC_ERROR_NONE ? std::move(retry_policy) : nullptr; +} + +const char* ParseHealthCheckConfig(const grpc_json* field, grpc_error** error) { + GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE); + const char* service_name = nullptr; + GPR_DEBUG_ASSERT(strcmp(field->key, "healthCheckConfig") == 0); + if (field->type != GRPC_JSON_OBJECT) { + *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:healthCheckConfig error:should be of type object"); + return nullptr; + } + InlinedVector error_list; + for (grpc_json* sub_field = field->child; sub_field != nullptr; + sub_field = sub_field->next) { + if (sub_field->key == nullptr) { + GPR_DEBUG_ASSERT(false); + continue; + } + if (strcmp(sub_field->key, "serviceName") == 0) { + if (service_name != nullptr) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:serviceName error:Duplicate " + "entry")); + } // Duplicate. Continue parsing + if (sub_field->type != GRPC_JSON_STRING) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:serviceName error:should be of type string")); + continue; + } + service_name = sub_field->value; + } + } + if (!error_list.empty()) { return nullptr; } - return retry_policy; + *error = + GRPC_ERROR_CREATE_FROM_VECTOR("field:healthCheckConfig", &error_list); + return service_name; } } // namespace -RefCountedPtr -ClientChannelMethodParams::CreateFromJson(const grpc_json* json) { - RefCountedPtr method_params = - MakeRefCounted(); +UniquePtr +ClientChannelServiceConfigParser::ParseGlobalParams(const grpc_json* json, + grpc_error** error) { + GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE); + InlinedVector error_list; + RefCountedPtr parsed_lb_config; + UniquePtr lb_policy_name; + Optional retry_throttling; + const char* health_check_service_name = nullptr; + for (grpc_json* field = json->child; field != nullptr; field = field->next) { + if (field->key == nullptr) { + continue; // Not the LB config global parameter + } + // Parsed Load balancing config + if (strcmp(field->key, "loadBalancingConfig") == 0) { + if (parsed_lb_config != nullptr) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:loadBalancingConfig error:Duplicate entry")); + } // Duplicate, continue parsing. + grpc_error* parse_error = GRPC_ERROR_NONE; + parsed_lb_config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig( + field, &parse_error); + if (parsed_lb_config == nullptr) { + error_list.push_back(parse_error); + } + } + // Parse deprecated loadBalancingPolicy + if (strcmp(field->key, "loadBalancingPolicy") == 0) { + if (lb_policy_name != nullptr) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:loadBalancingPolicy error:Duplicate entry")); + } // Duplicate, continue parsing. + if (field->type != GRPC_JSON_STRING) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:loadBalancingPolicy error:type should be string")); + continue; + } + lb_policy_name.reset(gpr_strdup(field->value)); + char* lb_policy = lb_policy_name.get(); + if (lb_policy != nullptr) { + for (size_t i = 0; i < strlen(lb_policy); ++i) { + lb_policy[i] = tolower(lb_policy[i]); + } + } + bool requires_config = false; + if (!LoadBalancingPolicyRegistry::LoadBalancingPolicyExists( + lb_policy, &requires_config)) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:loadBalancingPolicy error:Unknown lb policy")); + } else if (requires_config) { + char* error_msg; + gpr_asprintf(&error_msg, + "field:loadBalancingPolicy error:%s requires a config. " + "Please use loadBalancingConfig instead.", + lb_policy); + error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_msg)); + gpr_free(error_msg); + } + } + // Parse retry throttling + if (strcmp(field->key, "retryThrottling") == 0) { + if (retry_throttling.has_value()) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryThrottling error:Duplicate entry")); + } // Duplicate, continue parsing. + if (field->type != GRPC_JSON_OBJECT) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryThrottling error:Type should be object")); + continue; + } + Optional max_milli_tokens; + Optional milli_token_ratio; + for (grpc_json* sub_field = field->child; sub_field != nullptr; + sub_field = sub_field->next) { + if (sub_field->key == nullptr) continue; + if (strcmp(sub_field->key, "maxTokens") == 0) { + if (max_milli_tokens.has_value()) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryThrottling field:maxTokens error:Duplicate " + "entry")); + } // Duplicate, continue parsing. + if (sub_field->type != GRPC_JSON_NUMBER) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryThrottling field:maxTokens error:Type should be " + "number")); + } else { + max_milli_tokens.set(gpr_parse_nonnegative_int(sub_field->value) * + 1000); + if (max_milli_tokens.value() <= 0) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryThrottling field:maxTokens error:should be " + "greater than zero")); + } + } + } else if (strcmp(sub_field->key, "tokenRatio") == 0) { + if (milli_token_ratio.has_value()) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryThrottling field:tokenRatio error:Duplicate " + "entry")); + } // Duplicate, continue parsing. + if (sub_field->type != GRPC_JSON_NUMBER) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryThrottling field:tokenRatio error:type should be " + "number")); + } else { + // We support up to 3 decimal digits. + size_t whole_len = strlen(sub_field->value); + uint32_t multiplier = 1; + uint32_t decimal_value = 0; + const char* decimal_point = strchr(sub_field->value, '.'); + if (decimal_point != nullptr) { + whole_len = static_cast(decimal_point - sub_field->value); + multiplier = 1000; + size_t decimal_len = strlen(decimal_point + 1); + if (decimal_len > 3) decimal_len = 3; + if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len, + &decimal_value)) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryThrottling field:tokenRatio error:Failed " + "parsing")); + continue; + } + uint32_t decimal_multiplier = 1; + for (size_t i = 0; i < (3 - decimal_len); ++i) { + decimal_multiplier *= 10; + } + decimal_value *= decimal_multiplier; + } + uint32_t whole_value; + if (!gpr_parse_bytes_to_uint32(sub_field->value, whole_len, + &whole_value)) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryThrottling field:tokenRatio error:Failed " + "parsing")); + continue; + } + milli_token_ratio.set( + static_cast((whole_value * multiplier) + decimal_value)); + if (milli_token_ratio.value() <= 0) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryThrottling field:tokenRatio error:value should " + "be greater than 0")); + } + } + } + } + ClientChannelGlobalParsedConfig::RetryThrottling data; + if (!max_milli_tokens.has_value()) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryThrottling field:maxTokens error:Not found")); + } else { + data.max_milli_tokens = max_milli_tokens.value(); + } + if (!milli_token_ratio.has_value()) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryThrottling field:tokenRatio error:Not found")); + } else { + data.milli_token_ratio = milli_token_ratio.value(); + } + retry_throttling.set(data); + } + if (strcmp(field->key, "healthCheckConfig") == 0) { + if (health_check_service_name != nullptr) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:healthCheckConfig error:Duplicate entry")); + } // Duplicate continue parsing + grpc_error* parsing_error = GRPC_ERROR_NONE; + health_check_service_name = ParseHealthCheckConfig(field, &parsing_error); + if (parsing_error != GRPC_ERROR_NONE) { + error_list.push_back(parsing_error); + } + } + } + *error = GRPC_ERROR_CREATE_FROM_VECTOR("Client channel global parser", + &error_list); + if (*error == GRPC_ERROR_NONE) { + return UniquePtr( + New( + std::move(parsed_lb_config), std::move(lb_policy_name), + retry_throttling, health_check_service_name)); + } + return nullptr; +} + +UniquePtr +ClientChannelServiceConfigParser::ParsePerMethodParams(const grpc_json* json, + grpc_error** error) { + GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE); + InlinedVector error_list; + Optional wait_for_ready; + grpc_millis timeout = 0; + UniquePtr retry_policy; for (grpc_json* field = json->child; field != nullptr; field = field->next) { if (field->key == nullptr) continue; if (strcmp(field->key, "waitForReady") == 0) { - if (method_params->wait_for_ready_ != WAIT_FOR_READY_UNSET) { - return nullptr; // Duplicate. - } - if (!ParseWaitForReady(field, &method_params->wait_for_ready_)) { - return nullptr; + if (wait_for_ready.has_value()) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:waitForReady error:Duplicate entry")); + } // Duplicate, continue parsing. + if (field->type == GRPC_JSON_TRUE) { + wait_for_ready.set(true); + } else if (field->type == GRPC_JSON_FALSE) { + wait_for_ready.set(false); + } else { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:waitForReady error:Type should be true/false")); } } else if (strcmp(field->key, "timeout") == 0) { - if (method_params->timeout_ > 0) return nullptr; // Duplicate. - if (!ParseDuration(field, &method_params->timeout_)) return nullptr; + if (timeout > 0) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:timeout error:Duplicate entry")); + } // Duplicate, continue parsing. + if (!ParseDuration(field, &timeout)) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:timeout error:Failed parsing")); + }; } else if (strcmp(field->key, "retryPolicy") == 0) { - if (method_params->retry_policy_ != nullptr) { - return nullptr; // Duplicate. + if (retry_policy != nullptr) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:retryPolicy error:Duplicate entry")); + } // Duplicate, continue parsing. + grpc_error* error = GRPC_ERROR_NONE; + retry_policy = ParseRetryPolicy(field, &error); + if (retry_policy == nullptr) { + error_list.push_back(error); } - method_params->retry_policy_ = ParseRetryPolicy(field); - if (method_params->retry_policy_ == nullptr) return nullptr; } } - return method_params; + *error = GRPC_ERROR_CREATE_FROM_VECTOR("Client channel parser", &error_list); + if (*error == GRPC_ERROR_NONE) { + return UniquePtr( + New(timeout, wait_for_ready, + std::move(retry_policy))); + } + return nullptr; } } // namespace internal diff --git a/src/core/ext/filters/client_channel/resolver_result_parsing.h b/src/core/ext/filters/client_channel/resolver_result_parsing.h index 1a46278f38b..7750791c779 100644 --- a/src/core/ext/filters/client_channel/resolver_result_parsing.h +++ b/src/core/ext/filters/client_channel/resolver_result_parsing.h @@ -22,10 +22,12 @@ #include #include "src/core/ext/filters/client_channel/lb_policy.h" +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/resolver.h" #include "src/core/ext/filters/client_channel/retry_throttle.h" #include "src/core/ext/filters/client_channel/service_config.h" #include "src/core/lib/channel/status_util.h" +#include "src/core/lib/gprpp/optional.h" #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/exec_ctx.h" // for grpc_millis @@ -35,76 +37,48 @@ namespace grpc_core { namespace internal { -class ClientChannelMethodParams; - -// A table mapping from a method name to its method parameters. -typedef SliceHashTable> - ClientChannelMethodParamsTable; - -// A container of processed fields from the resolver result. Simplifies the -// usage of resolver result. -class ProcessedResolverResult { +class ClientChannelGlobalParsedConfig : public ServiceConfig::ParsedConfig { public: - // Processes the resolver result and populates the relative members - // for later consumption. Tries to parse retry parameters only if parse_retry - // is true. - ProcessedResolverResult(Resolver::Result* resolver_result, bool parse_retry); - - // Getters. Any managed object's ownership is transferred. - UniquePtr service_config_json() { - return std::move(service_config_json_); + struct RetryThrottling { + intptr_t max_milli_tokens = 0; + intptr_t milli_token_ratio = 0; + }; + + ClientChannelGlobalParsedConfig( + RefCountedPtr parsed_lb_config, + UniquePtr parsed_deprecated_lb_policy, + const Optional& retry_throttling, + const char* health_check_service_name) + : parsed_lb_config_(std::move(parsed_lb_config)), + parsed_deprecated_lb_policy_(std::move(parsed_deprecated_lb_policy)), + retry_throttling_(retry_throttling), + health_check_service_name_(health_check_service_name) {} + + Optional retry_throttling() const { + return retry_throttling_; } - RefCountedPtr retry_throttle_data() { - return std::move(retry_throttle_data_); + + RefCountedPtr parsed_lb_config() const { + return parsed_lb_config_; } - RefCountedPtr method_params_table() { - return std::move(method_params_table_); + + const char* parsed_deprecated_lb_policy() const { + return parsed_deprecated_lb_policy_.get(); } - UniquePtr lb_policy_name() { return std::move(lb_policy_name_); } - RefCountedPtr lb_policy_config() { - return std::move(lb_policy_config_); + + const char* health_check_service_name() const { + return health_check_service_name_; } private: - // Finds the service config; extracts LB config and (maybe) retry throttle - // params from it. - void ProcessServiceConfig(const Resolver::Result& resolver_result, - bool parse_retry); - - // Finds the LB policy name (when no LB config was found). - void ProcessLbPolicyName(const Resolver::Result& resolver_result); - - // Parses the service config. Intended to be used by - // ServiceConfig::ParseGlobalParams. - static void ParseServiceConfig(const grpc_json* field, - ProcessedResolverResult* parsing_state); - // Parses the LB config from service config. - void ParseLbConfigFromServiceConfig(const grpc_json* field); - // Parses the retry throttle parameters from service config. - void ParseRetryThrottleParamsFromServiceConfig(const grpc_json* field); - - // Service config. - UniquePtr service_config_json_; - RefCountedPtr service_config_; - // LB policy. - UniquePtr lb_policy_name_; - RefCountedPtr lb_policy_config_; - // Retry throttle data. - char* server_name_ = nullptr; - RefCountedPtr retry_throttle_data_; - // Method params table. - RefCountedPtr method_params_table_; + RefCountedPtr parsed_lb_config_; + UniquePtr parsed_deprecated_lb_policy_; + Optional retry_throttling_; + const char* health_check_service_name_; }; -// The parameters of a method. -class ClientChannelMethodParams : public RefCounted { +class ClientChannelMethodParsedConfig : public ServiceConfig::ParsedConfig { public: - enum WaitForReady { - WAIT_FOR_READY_UNSET = 0, - WAIT_FOR_READY_FALSE, - WAIT_FOR_READY_TRUE - }; - struct RetryPolicy { int max_attempts = 0; grpc_millis initial_backoff = 0; @@ -113,30 +87,35 @@ class ClientChannelMethodParams : public RefCounted { StatusCodeSet retryable_status_codes; }; - /// Creates a method_parameters object from \a json. - /// Intended for use with ServiceConfig::CreateMethodConfigTable(). - static RefCountedPtr CreateFromJson( - const grpc_json* json); + ClientChannelMethodParsedConfig(grpc_millis timeout, + const Optional& wait_for_ready, + UniquePtr retry_policy) + : timeout_(timeout), + wait_for_ready_(wait_for_ready), + retry_policy_(std::move(retry_policy)) {} grpc_millis timeout() const { return timeout_; } - WaitForReady wait_for_ready() const { return wait_for_ready_; } + + Optional wait_for_ready() const { return wait_for_ready_; } + const RetryPolicy* retry_policy() const { return retry_policy_.get(); } private: - // So New() can call our private ctor. - template - friend T* grpc_core::New(Args&&... args); + grpc_millis timeout_ = 0; + Optional wait_for_ready_; + UniquePtr retry_policy_; +}; - // So Delete() can call our private dtor. - template - friend void grpc_core::Delete(T*); +class ClientChannelServiceConfigParser : public ServiceConfig::Parser { + public: + UniquePtr ParseGlobalParams( + const grpc_json* json, grpc_error** error) override; - ClientChannelMethodParams() {} - virtual ~ClientChannelMethodParams() {} + UniquePtr ParsePerMethodParams( + const grpc_json* json, grpc_error** error) override; - grpc_millis timeout_ = 0; - WaitForReady wait_for_ready_ = WAIT_FOR_READY_UNSET; - UniquePtr retry_policy_; + static size_t ParserIndex(); + static void Register(); }; } // namespace internal diff --git a/src/core/ext/filters/client_channel/resolving_lb_policy.cc b/src/core/ext/filters/client_channel/resolving_lb_policy.cc index 4ccd8be29c0..4e383f65dd1 100644 --- a/src/core/ext/filters/client_channel/resolving_lb_policy.cc +++ b/src/core/ext/filters/client_channel/resolving_lb_policy.cc @@ -77,7 +77,7 @@ class ResolvingLoadBalancingPolicy::ResolverResultHandler : parent_(std::move(parent)) {} ~ResolverResultHandler() { - if (parent_->tracer_->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*(parent_->tracer_))) { gpr_log(GPR_INFO, "resolving_lb=%p: resolver shutdown complete", parent_.get()); } @@ -125,7 +125,7 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper // If this request is from the pending child policy, ignore it until // it reports READY, at which point we swap it into place. if (CalledByPendingChild()) { - if (parent_->tracer_->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*(parent_->tracer_))) { gpr_log(GPR_INFO, "resolving_lb=%p helper=%p: pending child policy %p reports " "state=%s", @@ -151,7 +151,7 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper if (parent_->pending_lb_policy_ != nullptr && !CalledByPendingChild()) { return; } - if (parent_->tracer_->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*(parent_->tracer_))) { gpr_log(GPR_INFO, "resolving_lb=%p: started name re-resolving", parent_.get()); } @@ -183,7 +183,8 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper ResolvingLoadBalancingPolicy::ResolvingLoadBalancingPolicy( Args args, TraceFlag* tracer, UniquePtr target_uri, - UniquePtr child_policy_name, RefCountedPtr child_lb_config, + UniquePtr child_policy_name, + RefCountedPtr child_lb_config, grpc_error** error) : LoadBalancingPolicy(std::move(args)), tracer_(tracer), @@ -240,7 +241,7 @@ void ResolvingLoadBalancingPolicy::ShutdownLocked() { resolver_.reset(); MutexLock lock(&lb_policy_mu_); if (lb_policy_ != nullptr) { - if (tracer_->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) { gpr_log(GPR_INFO, "resolving_lb=%p: shutting down lb_policy=%p", this, lb_policy_.get()); } @@ -249,7 +250,7 @@ void ResolvingLoadBalancingPolicy::ShutdownLocked() { lb_policy_.reset(); } if (pending_lb_policy_ != nullptr) { - if (tracer_->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) { gpr_log(GPR_INFO, "resolving_lb=%p: shutting down pending lb_policy=%p", this, pending_lb_policy_.get()); } @@ -297,7 +298,7 @@ void ResolvingLoadBalancingPolicy::FillChildRefsForChannelz( } void ResolvingLoadBalancingPolicy::StartResolvingLocked() { - if (tracer_->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) { gpr_log(GPR_INFO, "resolving_lb=%p: starting name resolution", this); } GPR_ASSERT(!started_resolving_); @@ -313,7 +314,7 @@ void ResolvingLoadBalancingPolicy::OnResolverError(grpc_error* error) { GRPC_ERROR_UNREF(error); return; } - if (tracer_->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) { gpr_log(GPR_INFO, "resolving_lb=%p: resolver transient failure: %s", this, grpc_error_string(error)); } @@ -331,7 +332,8 @@ void ResolvingLoadBalancingPolicy::OnResolverError(grpc_error* error) { } void ResolvingLoadBalancingPolicy::CreateOrUpdateLbPolicyLocked( - const char* lb_policy_name, RefCountedPtr lb_policy_config, + const char* lb_policy_name, + RefCountedPtr lb_policy_config, Resolver::Result result, TraceStringVector* trace_strings) { // If the child policy name changes, we need to create a new child // policy. When this happens, we leave child_policy_ as-is and store @@ -396,7 +398,7 @@ void ResolvingLoadBalancingPolicy::CreateOrUpdateLbPolicyLocked( // Cases 1, 2b, and 3b: create a new child policy. // If lb_policy_ is null, we set it (case 1), else we set // pending_lb_policy_ (cases 2b and 3b). - if (tracer_->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) { gpr_log(GPR_INFO, "resolving_lb=%p: Creating new %schild policy %s", this, lb_policy_ == nullptr ? "" : "pending ", lb_policy_name); } @@ -417,7 +419,7 @@ void ResolvingLoadBalancingPolicy::CreateOrUpdateLbPolicyLocked( } GPR_ASSERT(policy_to_update != nullptr); // Update the policy. - if (tracer_->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) { gpr_log(GPR_INFO, "resolving_lb=%p: Updating %schild policy %p", this, policy_to_update == pending_lb_policy_.get() ? "pending " : "", policy_to_update); @@ -456,7 +458,7 @@ ResolvingLoadBalancingPolicy::CreateLbPolicyLocked( return nullptr; } helper->set_child(lb_policy.get()); - if (tracer_->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) { gpr_log(GPR_INFO, "resolving_lb=%p: created new LB policy \"%s\" (%p)", this, lb_policy_name, lb_policy.get()); } @@ -512,7 +514,7 @@ void ResolvingLoadBalancingPolicy::OnResolverResultChangedLocked( Resolver::Result result) { // Handle race conditions. if (resolver_ == nullptr) return; - if (tracer_->enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(*tracer_)) { gpr_log(GPR_INFO, "resolving_lb=%p: got resolver result", this); } // We only want to trace the address resolution in the follow cases: @@ -528,20 +530,34 @@ void ResolvingLoadBalancingPolicy::OnResolverResultChangedLocked( const bool resolution_contains_addresses = result.addresses.size() > 0; // Process the resolver result. const char* lb_policy_name = nullptr; - RefCountedPtr lb_policy_config; + RefCountedPtr lb_policy_config; bool service_config_changed = false; + char* service_config_error_string = nullptr; if (process_resolver_result_ != nullptr) { - service_config_changed = - process_resolver_result_(process_resolver_result_user_data_, &result, - &lb_policy_name, &lb_policy_config); + grpc_error* service_config_error = GRPC_ERROR_NONE; + service_config_changed = process_resolver_result_( + process_resolver_result_user_data_, &result, &lb_policy_name, + &lb_policy_config, &service_config_error); + if (service_config_error != GRPC_ERROR_NONE) { + service_config_error_string = + gpr_strdup(grpc_error_string(service_config_error)); + if (lb_policy_name == nullptr) { + // Use an empty lb_policy_name as an indicator that we received an + // invalid service config and we don't have a fallback service config. + OnResolverError(service_config_error); + } else { + GRPC_ERROR_UNREF(service_config_error); + } + } } else { lb_policy_name = child_policy_name_.get(); lb_policy_config = child_lb_config_; } - GPR_ASSERT(lb_policy_name != nullptr); - // Create or update LB policy, as needed. - CreateOrUpdateLbPolicyLocked(lb_policy_name, std::move(lb_policy_config), - std::move(result), &trace_strings); + if (lb_policy_name != nullptr) { + // Create or update LB policy, as needed. + CreateOrUpdateLbPolicyLocked(lb_policy_name, lb_policy_config, + std::move(result), &trace_strings); + } // Add channel trace event. if (channelz_node() != nullptr) { if (service_config_changed) { @@ -549,10 +565,15 @@ void ResolvingLoadBalancingPolicy::OnResolverResultChangedLocked( // config in the trace, at the risk of bloating the trace logs. trace_strings.push_back(gpr_strdup("Service config changed")); } + if (service_config_error_string != nullptr) { + trace_strings.push_back(service_config_error_string); + service_config_error_string = nullptr; + } MaybeAddTraceMessagesForAddressChangesLocked(resolution_contains_addresses, &trace_strings); ConcatenateAndAddChannelTraceLocked(&trace_strings); } + gpr_free(service_config_error_string); } } // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/resolving_lb_policy.h b/src/core/ext/filters/client_channel/resolving_lb_policy.h index c9349769dd2..0ca6c9563f9 100644 --- a/src/core/ext/filters/client_channel/resolving_lb_policy.h +++ b/src/core/ext/filters/client_channel/resolving_lb_policy.h @@ -23,6 +23,7 @@ #include "src/core/ext/filters/client_channel/client_channel_channelz.h" #include "src/core/ext/filters/client_channel/lb_policy.h" +#include "src/core/ext/filters/client_channel/lb_policy_factory.h" #include "src/core/ext/filters/client_channel/resolver.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_stack.h" @@ -53,20 +54,24 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy { public: // If error is set when this returns, then construction failed, and // the caller may not use the new object. - ResolvingLoadBalancingPolicy(Args args, TraceFlag* tracer, - UniquePtr target_uri, - UniquePtr child_policy_name, - RefCountedPtr child_lb_config, - grpc_error** error); + ResolvingLoadBalancingPolicy( + Args args, TraceFlag* tracer, UniquePtr target_uri, + UniquePtr child_policy_name, + RefCountedPtr child_lb_config, + grpc_error** error); // Private ctor, to be used by client_channel only! // // Synchronous callback that takes the resolver result and sets // lb_policy_name and lb_policy_config to point to the right data. // Returns true if the service config has changed since the last result. + // If the returned service_config_error is not none and lb_policy_name is + // empty, it means that we don't have a valid service config to use, and we + // should set the channel to be in TRANSIENT_FAILURE. typedef bool (*ProcessResolverResultCallback)( void* user_data, Resolver::Result* result, const char** lb_policy_name, - RefCountedPtr* lb_policy_config); + RefCountedPtr* lb_policy_config, + grpc_error** service_config_error); // If error is set when this returns, then construction failed, and // the caller may not use the new object. ResolvingLoadBalancingPolicy( @@ -102,10 +107,10 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy { void StartResolvingLocked(); void OnResolverError(grpc_error* error); - void CreateOrUpdateLbPolicyLocked(const char* lb_policy_name, - RefCountedPtr lb_policy_config, - Resolver::Result result, - TraceStringVector* trace_strings); + void CreateOrUpdateLbPolicyLocked( + const char* lb_policy_name, + RefCountedPtr lb_policy_config, + Resolver::Result result, TraceStringVector* trace_strings); OrphanablePtr CreateLbPolicyLocked( const char* lb_policy_name, const grpc_channel_args& args, TraceStringVector* trace_strings); @@ -121,7 +126,7 @@ class ResolvingLoadBalancingPolicy : public LoadBalancingPolicy { ProcessResolverResultCallback process_resolver_result_ = nullptr; void* process_resolver_result_user_data_ = nullptr; UniquePtr child_policy_name_; - RefCountedPtr child_lb_config_; + RefCountedPtr child_lb_config_; // Resolver and associated state. OrphanablePtr resolver_; diff --git a/src/core/ext/filters/client_channel/service_config.cc b/src/core/ext/filters/client_channel/service_config.cc index d9e64ccf5a8..d41859bf45a 100644 --- a/src/core/ext/filters/client_channel/service_config.cc +++ b/src/core/ext/filters/client_channel/service_config.cc @@ -34,28 +34,10 @@ namespace grpc_core { namespace { -typedef InlinedVector, +typedef InlinedVector, ServiceConfig::kNumPreallocatedParsers> ServiceConfigParserList; -ServiceConfigParserList* registered_parsers; - -// Consumes all the errors in the vector and forms a referencing error from -// them. If the vector is empty, return GRPC_ERROR_NONE. -template -grpc_error* CreateErrorFromVector(const char* desc, - InlinedVector* error_list) { - grpc_error* error = GRPC_ERROR_NONE; - if (error_list->size() != 0) { - error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( - desc, error_list->data(), error_list->size()); - // Remove refs to all errors in error_list. - for (size_t i = 0; i < error_list->size(); i++) { - GRPC_ERROR_UNREF((*error_list)[i]); - } - error_list->clear(); - } - return error; -} +ServiceConfigParserList* g_registered_parsers; } // namespace RefCountedPtr ServiceConfig::Create(const char* json, @@ -107,35 +89,37 @@ grpc_error* ServiceConfig::ParseGlobalParams(const grpc_json* json_tree) { GPR_DEBUG_ASSERT(json_tree_->type == GRPC_JSON_OBJECT); GPR_DEBUG_ASSERT(json_tree_->key == nullptr); InlinedVector error_list; - for (size_t i = 0; i < registered_parsers->size(); i++) { + for (size_t i = 0; i < g_registered_parsers->size(); i++) { grpc_error* parser_error = GRPC_ERROR_NONE; auto parsed_obj = - (*registered_parsers)[i]->ParseGlobalParams(json_tree, &parser_error); + (*g_registered_parsers)[i]->ParseGlobalParams(json_tree, &parser_error); if (parser_error != GRPC_ERROR_NONE) { error_list.push_back(parser_error); } - parsed_global_service_config_objects_.push_back(std::move(parsed_obj)); + parsed_global_configs_.push_back(std::move(parsed_obj)); } - return CreateErrorFromVector("Global Params", &error_list); + return GRPC_ERROR_CREATE_FROM_VECTOR("Global Params", &error_list); } -grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigObjectsTable( +grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigVectorTable( const grpc_json* json, - SliceHashTable::Entry* entries, - size_t* idx) { - auto objs_vector = MakeUnique(); + SliceHashTable::Entry* entries, size_t* idx) { + auto objs_vector = MakeUnique(); InlinedVector error_list; - for (size_t i = 0; i < registered_parsers->size(); i++) { + for (size_t i = 0; i < g_registered_parsers->size(); i++) { grpc_error* parser_error = GRPC_ERROR_NONE; auto parsed_obj = - (*registered_parsers)[i]->ParsePerMethodParams(json, &parser_error); + (*g_registered_parsers)[i]->ParsePerMethodParams(json, &parser_error); if (parser_error != GRPC_ERROR_NONE) { error_list.push_back(parser_error); } objs_vector->push_back(std::move(parsed_obj)); } - const auto* vector_ptr = objs_vector.get(); - service_config_objects_vectors_storage_.push_back(std::move(objs_vector)); + parsed_method_config_vectors_storage_.push_back(std::move(objs_vector)); + const auto* vector_ptr = + parsed_method_config_vectors_storage_ + [parsed_method_config_vectors_storage_.size() - 1] + .get(); // Construct list of paths. InlinedVector, 10> paths; for (grpc_json* child = json->child; child != nullptr; child = child->next) { @@ -169,13 +153,13 @@ grpc_error* ServiceConfig::ParseJsonMethodConfigToServiceConfigObjectsTable( ++*idx; } wrap_error: - return CreateErrorFromVector("methodConfig", &error_list); + return GRPC_ERROR_CREATE_FROM_VECTOR("methodConfig", &error_list); } grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_json* json_tree) { GPR_DEBUG_ASSERT(json_tree_->type == GRPC_JSON_OBJECT); GPR_DEBUG_ASSERT(json_tree_->key == nullptr); - SliceHashTable::Entry* entries = nullptr; + SliceHashTable::Entry* entries = nullptr; size_t num_entries = 0; InlinedVector error_list; for (grpc_json* field = json_tree->child; field != nullptr; @@ -202,14 +186,13 @@ grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_json* json_tree) { } num_entries += static_cast(count); } - entries = static_cast< - SliceHashTable::Entry*>(gpr_zalloc( - num_entries * - sizeof(SliceHashTable::Entry))); + entries = static_cast::Entry*>( + gpr_zalloc(num_entries * + sizeof(SliceHashTable::Entry))); size_t idx = 0; for (grpc_json* method = field->child; method != nullptr; method = method->next) { - grpc_error* error = ParseJsonMethodConfigToServiceConfigObjectsTable( + grpc_error* error = ParseJsonMethodConfigToServiceConfigVectorTable( method, entries, &idx); if (error != GRPC_ERROR_NONE) { error_list.push_back(error); @@ -221,33 +204,16 @@ grpc_error* ServiceConfig::ParsePerMethodParams(const grpc_json* json_tree) { } } if (entries != nullptr) { - parsed_method_service_config_objects_table_ = - SliceHashTable::Create( - num_entries, entries, nullptr); + parsed_method_configs_table_ = + SliceHashTable::Create(num_entries, entries, + nullptr); gpr_free(entries); } - return CreateErrorFromVector("Method Params", &error_list); + return GRPC_ERROR_CREATE_FROM_VECTOR("Method Params", &error_list); } ServiceConfig::~ServiceConfig() { grpc_json_destroy(json_tree_); } -const char* ServiceConfig::GetLoadBalancingPolicyName() const { - if (json_tree_->type != GRPC_JSON_OBJECT || json_tree_->key != nullptr) { - return nullptr; - } - const char* lb_policy_name = nullptr; - for (grpc_json* field = json_tree_->child; field != nullptr; - field = field->next) { - if (field->key == nullptr) return nullptr; - if (strcmp(field->key, "loadBalancingPolicy") == 0) { - if (lb_policy_name != nullptr) return nullptr; // Duplicate. - if (field->type != GRPC_JSON_STRING) return nullptr; - lb_policy_name = field->value; - } - } - return lb_policy_name; -} - int ServiceConfig::CountNamesInMethodConfig(grpc_json* json) { int num_names = 0; for (grpc_json* field = json->child; field != nullptr; field = field->next) { @@ -319,9 +285,12 @@ UniquePtr ServiceConfig::ParseJsonMethodName(grpc_json* json, return UniquePtr(path); } -const ServiceConfig::ServiceConfigObjectsVector* const* -ServiceConfig::GetMethodServiceConfigObjectsVector(const grpc_slice& path) { - const auto* value = parsed_method_service_config_objects_table_->Get(path); +const ServiceConfig::ParsedConfigVector* +ServiceConfig::GetMethodParsedConfigVector(const grpc_slice& path) { + if (parsed_method_configs_table_.get() == nullptr) { + return nullptr; + } + const auto* value = parsed_method_configs_table_->Get(path); // If we didn't find a match for the path, try looking for a wildcard // entry (i.e., change "/service/method" to "/service/*"). if (value == nullptr) { @@ -334,27 +303,27 @@ ServiceConfig::GetMethodServiceConfigObjectsVector(const grpc_slice& path) { buf[len + 1] = '\0'; grpc_slice wildcard_path = grpc_slice_from_copied_string(buf); gpr_free(buf); - value = parsed_method_service_config_objects_table_->Get(wildcard_path); + value = parsed_method_configs_table_->Get(wildcard_path); grpc_slice_unref_internal(wildcard_path); gpr_free(path_str); if (value == nullptr) return nullptr; } - return value; + return *value; } -size_t ServiceConfig::RegisterParser(UniquePtr parser) { - registered_parsers->push_back(std::move(parser)); - return registered_parsers->size() - 1; +size_t ServiceConfig::RegisterParser(UniquePtr parser) { + g_registered_parsers->push_back(std::move(parser)); + return g_registered_parsers->size() - 1; } void ServiceConfig::Init() { - GPR_ASSERT(registered_parsers == nullptr); - registered_parsers = New(); + GPR_ASSERT(g_registered_parsers == nullptr); + g_registered_parsers = New(); } void ServiceConfig::Shutdown() { - Delete(registered_parsers); - registered_parsers = nullptr; + Delete(g_registered_parsers); + g_registered_parsers = nullptr; } } // namespace grpc_core diff --git a/src/core/ext/filters/client_channel/service_config.h b/src/core/ext/filters/client_channel/service_config.h index 0f2d2b387ae..189a0b9bca2 100644 --- a/src/core/ext/filters/client_channel/service_config.h +++ b/src/core/ext/filters/client_channel/service_config.h @@ -55,41 +55,73 @@ namespace grpc_core { -/// This is the base class that all service config parsers MUST use to store -/// parsed service config data. -class ServiceConfigParsedObject { +class ServiceConfig : public RefCounted { public: - virtual ~ServiceConfigParsedObject() = default; + /// This is the base class that all service config parsers MUST use to store + /// parsed service config data. + class ParsedConfig { + public: + virtual ~ParsedConfig() = default; + + GRPC_ABSTRACT_BASE_CLASS; + }; + + /// This is the base class that all service config parsers should derive from. + class Parser { + public: + virtual ~Parser() = default; + + virtual UniquePtr ParseGlobalParams(const grpc_json* json, + grpc_error** error) { + GPR_DEBUG_ASSERT(error != nullptr); + return nullptr; + } - GRPC_ABSTRACT_BASE_CLASS; -}; + virtual UniquePtr ParsePerMethodParams(const grpc_json* json, + grpc_error** error) { + GPR_DEBUG_ASSERT(error != nullptr); + return nullptr; + } -/// This is the base class that all service config parsers should derive from. -class ServiceConfigParser { - public: - virtual ~ServiceConfigParser() = default; + GRPC_ABSTRACT_BASE_CLASS; + }; - virtual UniquePtr ParseGlobalParams( - const grpc_json* json, grpc_error** error) { - GPR_DEBUG_ASSERT(error != nullptr); - return nullptr; - } + static constexpr int kNumPreallocatedParsers = 4; + typedef InlinedVector, kNumPreallocatedParsers> + ParsedConfigVector; + + /// When a service config is applied to a call in the client_channel_filter, + /// we create an instance of this object and store it in the call_data for + /// client_channel. A pointer to this object is also stored in the + /// call_context, so that future filters can easily access method and global + /// parameters for the call. + class CallData { + public: + CallData() = default; + CallData(RefCountedPtr svc_cfg, const grpc_slice& path) + : service_config_(std::move(svc_cfg)) { + if (service_config_ != nullptr) { + method_params_vector_ = + service_config_->GetMethodParsedConfigVector(path); + } + } - virtual UniquePtr ParsePerMethodParams( - const grpc_json* json, grpc_error** error) { - GPR_DEBUG_ASSERT(error != nullptr); - return nullptr; - } + ServiceConfig* service_config() { return service_config_.get(); } - GRPC_ABSTRACT_BASE_CLASS; -}; + ParsedConfig* GetMethodParsedConfig(size_t index) const { + return method_params_vector_ != nullptr + ? (*method_params_vector_)[index].get() + : nullptr; + } -class ServiceConfig : public RefCounted { - public: - static constexpr int kNumPreallocatedParsers = 4; - typedef InlinedVector, - kNumPreallocatedParsers> - ServiceConfigObjectsVector; + ParsedConfig* GetGlobalParsedConfig(size_t index) const { + return service_config_->GetGlobalParsedConfig(index); + } + + private: + RefCountedPtr service_config_; + const ParsedConfigVector* method_params_vector_ = nullptr; + }; /// Creates a new service config from parsing \a json_string. /// Returns null on parse error. @@ -100,57 +132,26 @@ class ServiceConfig : public RefCounted { const char* service_config_json() const { return service_config_json_.get(); } - /// Invokes \a process_json() for each global parameter in the service - /// config. \a arg is passed as the second argument to \a process_json(). - template - using ProcessJson = void (*)(const grpc_json*, T*); - template - void ParseGlobalParams(ProcessJson process_json, T* arg) const; - - /// Gets the LB policy name from \a service_config. - /// Returns NULL if no LB policy name was specified. - /// Caller does NOT take ownership. - const char* GetLoadBalancingPolicyName() const; - - /// Creates a method config table based on the data in \a json. - /// The table's keys are request paths. The table's value type is - /// returned by \a create_value(), based on data parsed from the JSON tree. - /// Returns null on error. - template - using CreateValue = RefCountedPtr (*)(const grpc_json* method_config_json); - template - RefCountedPtr>> CreateMethodConfigTable( - CreateValue create_value) const; - - /// A helper function for looking up values in the table returned by - /// \a CreateMethodConfigTable(). - /// Gets the method config for the specified \a path, which should be of - /// the form "/service/method". - /// Returns null if the method has no config. - /// Caller does NOT own a reference to the result. - template - static RefCountedPtr MethodConfigTableLookup( - const SliceHashTable>& table, const grpc_slice& path); - - /// Retrieves the parsed global service config object at index \a index. - ServiceConfigParsedObject* GetParsedGlobalServiceConfigObject(int index) { - GPR_DEBUG_ASSERT( - index < static_cast(parsed_global_service_config_objects_.size())); - return parsed_global_service_config_objects_[index].get(); + /// Retrieves the global parsed config at index \a index. The + /// lifetime of the returned object is tied to the lifetime of the + /// ServiceConfig object. + ParsedConfig* GetGlobalParsedConfig(size_t index) { + GPR_DEBUG_ASSERT(index < parsed_global_configs_.size()); + return parsed_global_configs_[index].get(); } - /// Retrieves the vector of method service config objects for a given path \a - /// path. - const ServiceConfigObjectsVector* const* GetMethodServiceConfigObjectsVector( - const grpc_slice& path); + /// Retrieves the vector of parsed configs for the method identified + /// by \a path. The lifetime of the returned vector and contained objects + /// is tied to the lifetime of the ServiceConfig object. + const ParsedConfigVector* GetMethodParsedConfigVector(const grpc_slice& path); /// Globally register a service config parser. On successful registration, it /// returns the index at which the parser was registered. On failure, -1 is /// returned. Each new service config update will go through all the /// registered parser. Each parser is responsible for reading the service - /// config json and returning a parsed object. This parsed object can later be + /// config json and returning a parsed config. This parsed config can later be /// retrieved using the same index that was returned at registration time. - static size_t RegisterParser(UniquePtr parser); + static size_t RegisterParser(UniquePtr parser); static void Init(); @@ -178,163 +179,27 @@ class ServiceConfig : public RefCounted { static UniquePtr ParseJsonMethodName(grpc_json* json, grpc_error** error); - // Parses the method config from \a json. Adds an entry to \a entries for - // each name found, incrementing \a idx for each entry added. - // Returns false on error. - template - static bool ParseJsonMethodConfig( - grpc_json* json, CreateValue create_value, - typename SliceHashTable>::Entry* entries, size_t* idx); - - grpc_error* ParseJsonMethodConfigToServiceConfigObjectsTable( + grpc_error* ParseJsonMethodConfigToServiceConfigVectorTable( const grpc_json* json, - SliceHashTable::Entry* entries, - size_t* idx); + SliceHashTable::Entry* entries, size_t* idx); UniquePtr service_config_json_; UniquePtr json_string_; // Underlying storage for json_tree. grpc_json* json_tree_; - InlinedVector, kNumPreallocatedParsers> - parsed_global_service_config_objects_; - // A map from the method name to the service config objects vector. Note that - // we are using a raw pointer and not a unique pointer so that we can use the - // same vector for multiple names. - RefCountedPtr> - parsed_method_service_config_objects_table_; + InlinedVector, kNumPreallocatedParsers> + parsed_global_configs_; + // A map from the method name to the parsed config vector. Note that we are + // using a raw pointer and not a unique pointer so that we can use the same + // vector for multiple names. + RefCountedPtr> + parsed_method_configs_table_; // Storage for all the vectors that are being used in - // parsed_method_service_config_objects_table_. - InlinedVector, 32> - service_config_objects_vectors_storage_; + // parsed_method_configs_table_. + InlinedVector, 32> + parsed_method_config_vectors_storage_; }; -// -// implementation -- no user-serviceable parts below -// - -template -void ServiceConfig::ParseGlobalParams(ProcessJson process_json, - T* arg) const { - if (json_tree_->type != GRPC_JSON_OBJECT || json_tree_->key != nullptr) { - return; - } - for (grpc_json* field = json_tree_->child; field != nullptr; - field = field->next) { - if (field->key == nullptr) return; - if (strcmp(field->key, "methodConfig") == 0) continue; - process_json(field, arg); - } -} - -template -bool ServiceConfig::ParseJsonMethodConfig( - grpc_json* json, CreateValue create_value, - typename SliceHashTable>::Entry* entries, size_t* idx) { - // Construct value. - RefCountedPtr method_config = create_value(json); - if (method_config == nullptr) return false; - // Construct list of paths. - InlinedVector, 10> paths; - for (grpc_json* child = json->child; child != nullptr; child = child->next) { - if (child->key == nullptr) continue; - if (strcmp(child->key, "name") == 0) { - if (child->type != GRPC_JSON_ARRAY) return false; - for (grpc_json* name = child->child; name != nullptr; name = name->next) { - grpc_error* error = GRPC_ERROR_NONE; - UniquePtr path = ParseJsonMethodName(name, &error); - // We are not reporting the error here. - GRPC_ERROR_UNREF(error); - if (path == nullptr) return false; - paths.push_back(std::move(path)); - } - } - } - if (paths.size() == 0) return false; // No names specified. - // Add entry for each path. - for (size_t i = 0; i < paths.size(); ++i) { - entries[*idx].key = grpc_slice_from_copied_string(paths[i].get()); - entries[*idx].value = method_config; // Takes a new ref. - ++*idx; - } - // Success. - return true; -} - -template -RefCountedPtr>> -ServiceConfig::CreateMethodConfigTable(CreateValue create_value) const { - // Traverse parsed JSON tree. - if (json_tree_->type != GRPC_JSON_OBJECT || json_tree_->key != nullptr) { - return nullptr; - } - size_t num_entries = 0; - typename SliceHashTable>::Entry* entries = nullptr; - for (grpc_json* field = json_tree_->child; field != nullptr; - field = field->next) { - if (field->key == nullptr) return nullptr; - if (strcmp(field->key, "methodConfig") == 0) { - if (entries != nullptr) return nullptr; // Duplicate. - if (field->type != GRPC_JSON_ARRAY) return nullptr; - // Find number of entries. - for (grpc_json* method = field->child; method != nullptr; - method = method->next) { - int count = CountNamesInMethodConfig(method); - if (count <= 0) return nullptr; - num_entries += static_cast(count); - } - // Populate method config table entries. - entries = static_cast>::Entry*>( - gpr_zalloc(num_entries * - sizeof(typename SliceHashTable>::Entry))); - size_t idx = 0; - for (grpc_json* method = field->child; method != nullptr; - method = method->next) { - if (!ParseJsonMethodConfig(method, create_value, entries, &idx)) { - for (size_t i = 0; i < idx; ++i) { - grpc_slice_unref_internal(entries[i].key); - entries[i].value.reset(); - } - gpr_free(entries); - return nullptr; - } - } - GPR_ASSERT(idx == num_entries); - } - } - // Instantiate method config table. - RefCountedPtr>> method_config_table; - if (entries != nullptr) { - method_config_table = - SliceHashTable>::Create(num_entries, entries, nullptr); - gpr_free(entries); - } - return method_config_table; -} - -template -RefCountedPtr ServiceConfig::MethodConfigTableLookup( - const SliceHashTable>& table, const grpc_slice& path) { - const RefCountedPtr* value = table.Get(path); - // If we didn't find a match for the path, try looking for a wildcard - // entry (i.e., change "/service/method" to "/service/*"). - if (value == nullptr) { - char* path_str = grpc_slice_to_c_string(path); - const char* sep = strrchr(path_str, '/') + 1; - const size_t len = (size_t)(sep - path_str); - char* buf = (char*)gpr_malloc(len + 2); // '*' and NUL - memcpy(buf, path_str, len); - buf[len] = '*'; - buf[len + 1] = '\0'; - grpc_slice wildcard_path = grpc_slice_from_copied_string(buf); - gpr_free(buf); - value = table.Get(wildcard_path); - grpc_slice_unref_internal(wildcard_path); - gpr_free(path_str); - if (value == nullptr) return nullptr; - } - return RefCountedPtr(*value); -} - } // namespace grpc_core #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SERVICE_CONFIG_H */ diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc index e29cd0a6dc3..cd778976166 100644 --- a/src/core/ext/filters/client_channel/subchannel.cc +++ b/src/core/ext/filters/client_channel/subchannel.cc @@ -121,7 +121,7 @@ RefCountedPtr ConnectedSubchannel::CreateCall( const size_t allocation_size = GetInitialCallSizeEstimate(args.parent_data_size); RefCountedPtr call( - new (gpr_arena_alloc(args.arena, allocation_size)) + new (args.arena->Alloc(allocation_size)) SubchannelCall(Ref(DEBUG_LOCATION, "subchannel_call"), args)); grpc_call_stack* callstk = SUBCHANNEL_CALL_TO_CALL_STACK(call.get()); const grpc_call_element_args call_args = { @@ -303,8 +303,7 @@ void SubchannelCall::IncrementRefCount(const grpc_core::DebugLocation& location, // Subchannel::ConnectedSubchannelStateWatcher // -class Subchannel::ConnectedSubchannelStateWatcher - : public InternallyRefCounted { +class Subchannel::ConnectedSubchannelStateWatcher { public: // Must be instantiated while holding c->mu. explicit ConnectedSubchannelStateWatcher(Subchannel* c) : subchannel_(c) { @@ -312,38 +311,17 @@ class Subchannel::ConnectedSubchannelStateWatcher GRPC_SUBCHANNEL_WEAK_REF(subchannel_, "state_watcher"); GRPC_SUBCHANNEL_WEAK_UNREF(subchannel_, "connecting"); // Start watching for connectivity state changes. - // Callback uses initial ref to this. GRPC_CLOSURE_INIT(&on_connectivity_changed_, OnConnectivityChanged, this, grpc_schedule_on_exec_ctx); c->connected_subchannel_->NotifyOnStateChange(c->pollset_set_, &pending_connectivity_state_, &on_connectivity_changed_); - // Start health check if needed. - grpc_connectivity_state health_state = GRPC_CHANNEL_READY; - if (c->health_check_service_name_ != nullptr) { - health_check_client_ = MakeOrphanable( - c->health_check_service_name_.get(), c->connected_subchannel_, - c->pollset_set_, c->channelz_node_); - GRPC_CLOSURE_INIT(&on_health_changed_, OnHealthChanged, this, - grpc_schedule_on_exec_ctx); - Ref().release(); // Ref for health callback tracked manually. - health_check_client_->NotifyOnHealthChange(&health_state_, - &on_health_changed_); - health_state = GRPC_CHANNEL_CONNECTING; - } - // Report initial state. - c->SetConnectivityStateLocked(GRPC_CHANNEL_READY, "subchannel_connected"); - grpc_connectivity_state_set(&c->state_and_health_tracker_, health_state, - "subchannel_connected"); } ~ConnectedSubchannelStateWatcher() { GRPC_SUBCHANNEL_WEAK_UNREF(subchannel_, "state_watcher"); } - // Must be called while holding subchannel_->mu. - void Orphan() override { health_check_client_.reset(); } - private: static void OnConnectivityChanged(void* arg, grpc_error* error) { auto* self = static_cast(arg); @@ -363,20 +341,10 @@ class Subchannel::ConnectedSubchannelStateWatcher self->pending_connectivity_state_)); } c->connected_subchannel_.reset(); - c->connected_subchannel_watcher_.reset(); - self->last_connectivity_state_ = GRPC_CHANNEL_TRANSIENT_FAILURE; - c->SetConnectivityStateLocked(GRPC_CHANNEL_TRANSIENT_FAILURE, - "reflect_child"); - grpc_connectivity_state_set(&c->state_and_health_tracker_, - GRPC_CHANNEL_TRANSIENT_FAILURE, - "reflect_child"); + c->SetConnectivityStateLocked(GRPC_CHANNEL_TRANSIENT_FAILURE); c->backoff_begun_ = false; c->backoff_.Reset(); - c->MaybeStartConnectingLocked(); - } else { - self->last_connectivity_state_ = GRPC_CHANNEL_SHUTDOWN; } - self->health_check_client_.reset(); break; } default: { @@ -384,96 +352,246 @@ class Subchannel::ConnectedSubchannelStateWatcher // a callback for READY, because that was the state we started // this watch from. And a connected subchannel should never go // from READY to CONNECTING or IDLE. - self->last_connectivity_state_ = self->pending_connectivity_state_; - c->SetConnectivityStateLocked(self->pending_connectivity_state_, - "reflect_child"); - if (self->pending_connectivity_state_ != GRPC_CHANNEL_READY) { - grpc_connectivity_state_set(&c->state_and_health_tracker_, - self->pending_connectivity_state_, - "reflect_child"); - } + c->SetConnectivityStateLocked(self->pending_connectivity_state_); c->connected_subchannel_->NotifyOnStateChange( nullptr, &self->pending_connectivity_state_, &self->on_connectivity_changed_); - self = nullptr; // So we don't unref below. + return; // So we don't delete ourself below. } } } - // Don't unref until we've released the lock, because this might + // Don't delete until we've released the lock, because this might // cause the subchannel (which contains the lock) to be destroyed. - if (self != nullptr) self->Unref(); + Delete(self); + } + + Subchannel* subchannel_; + grpc_closure on_connectivity_changed_; + grpc_connectivity_state pending_connectivity_state_ = GRPC_CHANNEL_READY; +}; + +// +// Subchannel::ConnectivityStateWatcherList +// + +void Subchannel::ConnectivityStateWatcherList::AddWatcherLocked( + UniquePtr watcher) { + watcher->next_ = head_; + head_ = watcher.release(); +} + +void Subchannel::ConnectivityStateWatcherList::RemoveWatcherLocked( + ConnectivityStateWatcher* watcher) { + for (ConnectivityStateWatcher** w = &head_; *w != nullptr; w = &(*w)->next_) { + if (*w == watcher) { + *w = watcher->next_; + Delete(watcher); + return; + } + } + GPR_UNREACHABLE_CODE(return ); +} + +void Subchannel::ConnectivityStateWatcherList::NotifyLocked( + Subchannel* subchannel, grpc_connectivity_state state) { + for (ConnectivityStateWatcher* w = head_; w != nullptr; w = w->next_) { + RefCountedPtr connected_subchannel; + if (state == GRPC_CHANNEL_READY) { + connected_subchannel = subchannel->connected_subchannel_; + } + // TODO(roth): In principle, it seems wrong to send this notification + // to the watcher while holding the subchannel's mutex, since it could + // lead to a deadlock if the watcher calls back into the subchannel + // before returning back to us. In practice, this doesn't happen, + // because the LB policy code that watches subchannels always bounces + // the notification into the client_channel control-plane combiner + // before processing it. But if we ever have any other callers here, + // we will probably need to change this. + w->OnConnectivityStateChange(state, std::move(connected_subchannel)); + } +} + +void Subchannel::ConnectivityStateWatcherList::Clear() { + while (head_ != nullptr) { + ConnectivityStateWatcher* next = head_->next_; + Delete(head_); + head_ = next; + } +} + +// +// Subchannel::HealthWatcherMap::HealthWatcher +// + +// State needed for tracking the connectivity state with a particular +// health check service name. +class Subchannel::HealthWatcherMap::HealthWatcher + : public InternallyRefCounted { + public: + HealthWatcher(Subchannel* c, UniquePtr health_check_service_name, + grpc_connectivity_state subchannel_state) + : subchannel_(c), + health_check_service_name_(std::move(health_check_service_name)), + state_(subchannel_state == GRPC_CHANNEL_READY ? GRPC_CHANNEL_CONNECTING + : subchannel_state) { + GRPC_SUBCHANNEL_WEAK_REF(subchannel_, "health_watcher"); + GRPC_CLOSURE_INIT(&on_health_changed_, OnHealthChanged, this, + grpc_schedule_on_exec_ctx); + // If the subchannel is already connected, start health checking. + if (subchannel_state == GRPC_CHANNEL_READY) StartHealthCheckingLocked(); + } + + ~HealthWatcher() { + GRPC_SUBCHANNEL_WEAK_UNREF(subchannel_, "health_watcher"); + } + + const char* health_check_service_name() const { + return health_check_service_name_.get(); + } + + grpc_connectivity_state state() const { return state_; } + + void AddWatcherLocked(grpc_connectivity_state initial_state, + UniquePtr watcher) { + if (state_ != initial_state) { + RefCountedPtr connected_subchannel; + if (state_ == GRPC_CHANNEL_READY) { + connected_subchannel = subchannel_->connected_subchannel_; + } + watcher->OnConnectivityStateChange(state_, + std::move(connected_subchannel)); + } + watcher_list_.AddWatcherLocked(std::move(watcher)); + } + + void RemoveWatcherLocked(ConnectivityStateWatcher* watcher) { + watcher_list_.RemoveWatcherLocked(watcher); + } + + bool HasWatchers() const { return !watcher_list_.empty(); } + + void NotifyLocked(grpc_connectivity_state state) { + if (state == GRPC_CHANNEL_READY) { + // If we had not already notified for CONNECTING state, do so now. + // (We may have missed this earlier, because if the transition + // from IDLE to CONNECTING to READY was too quick, the connected + // subchannel may not have sent us a notification for CONNECTING.) + if (state_ != GRPC_CHANNEL_CONNECTING) { + state_ = GRPC_CHANNEL_CONNECTING; + watcher_list_.NotifyLocked(subchannel_, state_); + } + // If we've become connected, start health checking. + StartHealthCheckingLocked(); + } else { + state_ = state; + watcher_list_.NotifyLocked(subchannel_, state_); + // We're not connected, so stop health checking. + health_check_client_.reset(); + } + } + + void Orphan() override { + watcher_list_.Clear(); + health_check_client_.reset(); + Unref(); + } + + private: + void StartHealthCheckingLocked() { + GPR_ASSERT(health_check_client_ == nullptr); + health_check_client_ = MakeOrphanable( + health_check_service_name_.get(), subchannel_->connected_subchannel_, + subchannel_->pollset_set_, subchannel_->channelz_node_); + Ref().release(); // Ref for health callback tracked manually. + health_check_client_->NotifyOnHealthChange(&state_, &on_health_changed_); } static void OnHealthChanged(void* arg, grpc_error* error) { - auto* self = static_cast(arg); + auto* self = static_cast(arg); Subchannel* c = self->subchannel_; { MutexLock lock(&c->mu_); - if (self->health_state_ != GRPC_CHANNEL_SHUTDOWN && + if (self->state_ != GRPC_CHANNEL_SHUTDOWN && self->health_check_client_ != nullptr) { - if (self->last_connectivity_state_ == GRPC_CHANNEL_READY) { - grpc_connectivity_state_set(&c->state_and_health_tracker_, - self->health_state_, "health_changed"); - } + self->watcher_list_.NotifyLocked(c, self->state_); + // Renew watch. self->health_check_client_->NotifyOnHealthChange( - &self->health_state_, &self->on_health_changed_); - self = nullptr; // So we don't unref below. + &self->state_, &self->on_health_changed_); + return; // So we don't unref below. } } // Don't unref until we've released the lock, because this might // cause the subchannel (which contains the lock) to be destroyed. - if (self != nullptr) self->Unref(); + self->Unref(); } Subchannel* subchannel_; - grpc_closure on_connectivity_changed_; - grpc_connectivity_state pending_connectivity_state_ = GRPC_CHANNEL_READY; - grpc_connectivity_state last_connectivity_state_ = GRPC_CHANNEL_READY; + UniquePtr health_check_service_name_; OrphanablePtr health_check_client_; grpc_closure on_health_changed_; - grpc_connectivity_state health_state_ = GRPC_CHANNEL_CONNECTING; + grpc_connectivity_state state_; + ConnectivityStateWatcherList watcher_list_; }; // -// Subchannel::ExternalStateWatcher +// Subchannel::HealthWatcherMap // -struct Subchannel::ExternalStateWatcher { - ExternalStateWatcher(Subchannel* subchannel, grpc_pollset_set* pollset_set, - grpc_closure* notify) - : subchannel(subchannel), pollset_set(pollset_set), notify(notify) { - GRPC_SUBCHANNEL_WEAK_REF(subchannel, "external_state_watcher+init"); - GRPC_CLOSURE_INIT(&on_state_changed, OnStateChanged, this, - grpc_schedule_on_exec_ctx); +void Subchannel::HealthWatcherMap::AddWatcherLocked( + Subchannel* subchannel, grpc_connectivity_state initial_state, + UniquePtr health_check_service_name, + UniquePtr watcher) { + // If the health check service name is not already present in the map, + // add it. + auto it = map_.find(health_check_service_name.get()); + HealthWatcher* health_watcher; + if (it == map_.end()) { + const char* key = health_check_service_name.get(); + auto w = MakeOrphanable( + subchannel, std::move(health_check_service_name), subchannel->state_); + health_watcher = w.get(); + map_[key] = std::move(w); + } else { + health_watcher = it->second.get(); } + // Add the watcher to the entry. + health_watcher->AddWatcherLocked(initial_state, std::move(watcher)); +} - static void OnStateChanged(void* arg, grpc_error* error) { - ExternalStateWatcher* w = static_cast(arg); - grpc_closure* follow_up = w->notify; - if (w->pollset_set != nullptr) { - grpc_pollset_set_del_pollset_set(w->subchannel->pollset_set_, - w->pollset_set); - } - { - MutexLock lock(&w->subchannel->mu_); - if (w->subchannel->external_state_watcher_list_ == w) { - w->subchannel->external_state_watcher_list_ = w->next; - } - if (w->next != nullptr) w->next->prev = w->prev; - if (w->prev != nullptr) w->prev->next = w->next; - } - GRPC_SUBCHANNEL_WEAK_UNREF(w->subchannel, "external_state_watcher+done"); - Delete(w); - GRPC_CLOSURE_SCHED(follow_up, GRPC_ERROR_REF(error)); +void Subchannel::HealthWatcherMap::RemoveWatcherLocked( + const char* health_check_service_name, ConnectivityStateWatcher* watcher) { + auto it = map_.find(health_check_service_name); + GPR_ASSERT(it != map_.end()); + it->second->RemoveWatcherLocked(watcher); + // If we just removed the last watcher for this service name, remove + // the map entry. + if (!it->second->HasWatchers()) map_.erase(it); +} + +void Subchannel::HealthWatcherMap::NotifyLocked(grpc_connectivity_state state) { + for (const auto& p : map_) { + p.second->NotifyLocked(state); } +} - Subchannel* subchannel; - grpc_pollset_set* pollset_set; - grpc_closure* notify; - grpc_closure on_state_changed; - ExternalStateWatcher* next = nullptr; - ExternalStateWatcher* prev = nullptr; -}; +grpc_connectivity_state +Subchannel::HealthWatcherMap::CheckConnectivityStateLocked( + Subchannel* subchannel, const char* health_check_service_name) { + auto it = map_.find(health_check_service_name); + if (it == map_.end()) { + // If the health check service name is not found in the map, we're + // not currently doing a health check for that service name. If the + // subchannel's state without health checking is READY, report + // CONNECTING, since that's what we'd be in as soon as we do start a + // watch. Otherwise, report the channel's state without health checking. + return subchannel->state_ == GRPC_CHANNEL_READY ? GRPC_CHANNEL_CONNECTING + : subchannel->state_; + } + HealthWatcher* health_watcher = it->second.get(); + return health_watcher->state(); +} + +void Subchannel::HealthWatcherMap::ShutdownLocked() { map_.clear(); } // // Subchannel @@ -529,25 +647,6 @@ BackOff::Options ParseArgsForBackoffValues( .set_max_backoff(max_backoff_ms); } -struct HealthCheckParams { - UniquePtr service_name; - - static void Parse(const grpc_json* field, HealthCheckParams* params) { - if (strcmp(field->key, "healthCheckConfig") == 0) { - if (field->type != GRPC_JSON_OBJECT) return; - for (grpc_json* sub_field = field->child; sub_field != nullptr; - sub_field = sub_field->next) { - if (sub_field->key == nullptr) return; - if (strcmp(sub_field->key, "serviceName") == 0) { - if (params->service_name != nullptr) return; // Duplicate. - if (sub_field->type != GRPC_JSON_STRING) return; - params->service_name.reset(gpr_strdup(sub_field->value)); - } - } - } - } -}; - } // namespace Subchannel::Subchannel(SubchannelKey* key, grpc_connector* connector, @@ -579,25 +678,6 @@ Subchannel::Subchannel(SubchannelKey* key, grpc_connector* connector, if (new_args != nullptr) grpc_channel_args_destroy(new_args); GRPC_CLOSURE_INIT(&on_connecting_finished_, OnConnectingFinished, this, grpc_schedule_on_exec_ctx); - grpc_connectivity_state_init(&state_tracker_, GRPC_CHANNEL_IDLE, - "subchannel"); - grpc_connectivity_state_init(&state_and_health_tracker_, GRPC_CHANNEL_IDLE, - "subchannel"); - // Check whether we should enable health checking. - const char* service_config_json = grpc_channel_arg_get_string( - grpc_channel_args_find(args_, GRPC_ARG_SERVICE_CONFIG)); - if (service_config_json != nullptr) { - grpc_error* service_config_error = GRPC_ERROR_NONE; - RefCountedPtr service_config = - ServiceConfig::Create(service_config_json, &service_config_error); - // service_config_error is currently unused. - GRPC_ERROR_UNREF(service_config_error); - if (service_config != nullptr) { - HealthCheckParams params; - service_config->ParseGlobalParams(HealthCheckParams::Parse, ¶ms); - health_check_service_name_ = std::move(params.service_name); - } - } const grpc_arg* arg = grpc_channel_args_find(args_, GRPC_ARG_ENABLE_CHANNELZ); const bool channelz_enabled = grpc_channel_arg_get_bool(arg, GRPC_ENABLE_CHANNELZ_DEFAULT); @@ -624,8 +704,6 @@ Subchannel::~Subchannel() { channelz_node_->MarkSubchannelDestroyed(); } grpc_channel_args_destroy(args_); - grpc_connectivity_state_destroy(&state_tracker_); - grpc_connectivity_state_destroy(&state_and_health_tracker_); grpc_connector_unref(connector_); grpc_pollset_set_destroy(pollset_set_); Delete(key_); @@ -729,55 +807,67 @@ const char* Subchannel::GetTargetAddress() { return addr_str; } -RefCountedPtr Subchannel::connected_subchannel() { - MutexLock lock(&mu_); - return connected_subchannel_; -} - channelz::SubchannelNode* Subchannel::channelz_node() { return channelz_node_.get(); } -grpc_connectivity_state Subchannel::CheckConnectivity( - bool inhibit_health_checking) { - grpc_connectivity_state_tracker* tracker = - inhibit_health_checking ? &state_tracker_ : &state_and_health_tracker_; - grpc_connectivity_state state = grpc_connectivity_state_check(tracker); +grpc_connectivity_state Subchannel::CheckConnectivityState( + const char* health_check_service_name, + RefCountedPtr* connected_subchannel) { + MutexLock lock(&mu_); + grpc_connectivity_state state; + if (health_check_service_name == nullptr) { + state = state_; + } else { + state = health_watcher_map_.CheckConnectivityStateLocked( + this, health_check_service_name); + } + if (connected_subchannel != nullptr && state == GRPC_CHANNEL_READY) { + *connected_subchannel = connected_subchannel_; + } return state; } -void Subchannel::NotifyOnStateChange(grpc_pollset_set* interested_parties, - grpc_connectivity_state* state, - grpc_closure* notify, - bool inhibit_health_checking) { - grpc_connectivity_state_tracker* tracker = - inhibit_health_checking ? &state_tracker_ : &state_and_health_tracker_; - ExternalStateWatcher* w; - if (state == nullptr) { - MutexLock lock(&mu_); - for (w = external_state_watcher_list_; w != nullptr; w = w->next) { - if (w->notify == notify) { - grpc_connectivity_state_notify_on_state_change(tracker, nullptr, - &w->on_state_changed); - } +void Subchannel::WatchConnectivityState( + grpc_connectivity_state initial_state, + UniquePtr health_check_service_name, + UniquePtr watcher) { + MutexLock lock(&mu_); + grpc_pollset_set* interested_parties = watcher->interested_parties(); + if (interested_parties != nullptr) { + grpc_pollset_set_add_pollset_set(pollset_set_, interested_parties); + } + if (health_check_service_name == nullptr) { + if (state_ != initial_state) { + watcher->OnConnectivityStateChange(state_, connected_subchannel_); } + watcher_list_.AddWatcherLocked(std::move(watcher)); } else { - w = New(this, interested_parties, notify); - if (interested_parties != nullptr) { - grpc_pollset_set_add_pollset_set(pollset_set_, interested_parties); - } - MutexLock lock(&mu_); - if (external_state_watcher_list_ != nullptr) { - w->next = external_state_watcher_list_; - w->next->prev = w; - } - external_state_watcher_list_ = w; - grpc_connectivity_state_notify_on_state_change(tracker, state, - &w->on_state_changed); - MaybeStartConnectingLocked(); + health_watcher_map_.AddWatcherLocked(this, initial_state, + std::move(health_check_service_name), + std::move(watcher)); + } +} + +void Subchannel::CancelConnectivityStateWatch( + const char* health_check_service_name, ConnectivityStateWatcher* watcher) { + MutexLock lock(&mu_); + grpc_pollset_set* interested_parties = watcher->interested_parties(); + if (interested_parties != nullptr) { + grpc_pollset_set_del_pollset_set(pollset_set_, interested_parties); + } + if (health_check_service_name == nullptr) { + watcher_list_.RemoveWatcherLocked(watcher); + } else { + health_watcher_map_.RemoveWatcherLocked(health_check_service_name, watcher); } } +void Subchannel::AttemptToConnect() { + MutexLock lock(&mu_); + MaybeStartConnectingLocked(); +} + void Subchannel::ResetBackoff() { MutexLock lock(&mu_); backoff_.Reset(); @@ -849,15 +939,19 @@ const char* SubchannelConnectivityStateChangeString( } // namespace -void Subchannel::SetConnectivityStateLocked(grpc_connectivity_state state, - const char* reason) { +// Note: Must be called with a state that is different from the current state. +void Subchannel::SetConnectivityStateLocked(grpc_connectivity_state state) { + state_ = state; if (channelz_node_ != nullptr) { channelz_node_->AddTraceEvent( channelz::ChannelTrace::Severity::Info, grpc_slice_from_static_string( SubchannelConnectivityStateChangeString(state))); } - grpc_connectivity_state_set(&state_tracker_, state, reason); + // Notify non-health watchers. + watcher_list_.NotifyLocked(this, state); + // Notify health watchers. + health_watcher_map_.NotifyLocked(state); } void Subchannel::MaybeStartConnectingLocked() { @@ -873,11 +967,6 @@ void Subchannel::MaybeStartConnectingLocked() { // Already connected: don't restart. return; } - if (!grpc_connectivity_state_has_watchers(&state_tracker_) && - !grpc_connectivity_state_has_watchers(&state_and_health_tracker_)) { - // Nobody is interested in connecting: so don't just yet. - return; - } connecting_ = true; GRPC_SUBCHANNEL_WEAK_REF(this, "connecting"); if (!backoff_begun_) { @@ -934,9 +1023,7 @@ void Subchannel::ContinueConnectingLocked() { next_attempt_deadline_ = backoff_.NextAttemptTime(); args.deadline = std::max(next_attempt_deadline_, min_deadline); args.channel_args = args_; - SetConnectivityStateLocked(GRPC_CHANNEL_CONNECTING, "connecting"); - grpc_connectivity_state_set(&state_and_health_tracker_, - GRPC_CHANNEL_CONNECTING, "connecting"); + SetConnectivityStateLocked(GRPC_CHANNEL_CONNECTING); grpc_connector_connect(connector_, &args, &connecting_result_, &on_connecting_finished_); } @@ -955,12 +1042,7 @@ void Subchannel::OnConnectingFinished(void* arg, grpc_error* error) { GRPC_SUBCHANNEL_WEAK_UNREF(c, "connecting"); } else { gpr_log(GPR_INFO, "Connect failed: %s", grpc_error_string(error)); - c->SetConnectivityStateLocked(GRPC_CHANNEL_TRANSIENT_FAILURE, - "connect_failed"); - grpc_connectivity_state_set(&c->state_and_health_tracker_, - GRPC_CHANNEL_TRANSIENT_FAILURE, - "connect_failed"); - c->MaybeStartConnectingLocked(); + c->SetConnectivityStateLocked(GRPC_CHANNEL_TRANSIENT_FAILURE); GRPC_SUBCHANNEL_WEAK_UNREF(c, "connecting"); } } @@ -1013,8 +1095,9 @@ bool Subchannel::PublishTransportLocked() { gpr_log(GPR_INFO, "New connected subchannel at %p for subchannel %p", connected_subchannel_.get(), this); // Instantiate state watcher. Will clean itself up. - connected_subchannel_watcher_ = - MakeOrphanable(this); + New(this); + // Report initial state. + SetConnectivityStateLocked(GRPC_CHANNEL_READY); return true; } @@ -1031,7 +1114,7 @@ void Subchannel::Disconnect() { grpc_connector_shutdown(connector_, GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Subchannel disconnected")); connected_subchannel_.reset(); - connected_subchannel_watcher_.reset(); + health_watcher_map_.ShutdownLocked(); } gpr_atm Subchannel::RefMutate( diff --git a/src/core/ext/filters/client_channel/subchannel.h b/src/core/ext/filters/client_channel/subchannel.h index 9c2e57d3e05..e0741bb28fa 100644 --- a/src/core/ext/filters/client_channel/subchannel.h +++ b/src/core/ext/filters/client_channel/subchannel.h @@ -26,7 +26,8 @@ #include "src/core/ext/filters/client_channel/subchannel_pool_interface.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_stack.h" -#include "src/core/lib/gpr/arena.h" +#include "src/core/lib/gprpp/arena.h" +#include "src/core/lib/gprpp/map.h" #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/sync.h" @@ -75,9 +76,9 @@ class ConnectedSubchannel : public RefCounted { grpc_slice path; gpr_timespec start_time; grpc_millis deadline; - gpr_arena* arena; + Arena* arena; grpc_call_context_element* context; - grpc_call_combiner* call_combiner; + CallCombiner* call_combiner; size_t parent_data_size; }; @@ -175,7 +176,38 @@ class SubchannelCall { // A subchannel that knows how to connect to exactly one target address. It // provides a target for load balancing. class Subchannel { + private: + class ConnectivityStateWatcherList; // Forward declaration. + public: + class ConnectivityStateWatcher { + public: + virtual ~ConnectivityStateWatcher() = default; + + // Will be invoked whenever the subchannel's connectivity state + // changes. There will be only one invocation of this method on a + // given watcher instance at any given time. + // + // When the state changes to READY, connected_subchannel will + // contain a ref to the connected subchannel. When it changes from + // READY to some other state, the implementation must release its + // ref to the connected subchannel. + virtual void OnConnectivityStateChange( + grpc_connectivity_state new_state, + RefCountedPtr connected_subchannel) // NOLINT + GRPC_ABSTRACT; + + virtual grpc_pollset_set* interested_parties() GRPC_ABSTRACT; + + GRPC_ABSTRACT_BASE_CLASS + + private: + // For access to next_. + friend class Subchannel::ConnectivityStateWatcherList; + + ConnectivityStateWatcher* next_ = nullptr; + }; + // The ctor and dtor are not intended to use directly. Subchannel(SubchannelKey* key, grpc_connector* connector, const grpc_channel_args* args); @@ -201,20 +233,36 @@ class Subchannel { // Caller doesn't take ownership. const char* GetTargetAddress(); - // Gets the connected subchannel - or nullptr if not connected (which may - // happen before it initially connects or during transient failures). - RefCountedPtr connected_subchannel(); - channelz::SubchannelNode* channelz_node(); - // Polls the current connectivity state of the subchannel. - grpc_connectivity_state CheckConnectivity(bool inhibit_health_checking); - - // When the connectivity state of the subchannel changes from \a *state, - // invokes \a notify and updates \a *state with the new state. - void NotifyOnStateChange(grpc_pollset_set* interested_parties, - grpc_connectivity_state* state, grpc_closure* notify, - bool inhibit_health_checking); + // Returns the current connectivity state of the subchannel. + // If health_check_service_name is non-null, the returned connectivity + // state will be based on the state reported by the backend for that + // service name. + // If the return value is GRPC_CHANNEL_READY, also sets *connected_subchannel. + grpc_connectivity_state CheckConnectivityState( + const char* health_check_service_name, + RefCountedPtr* connected_subchannel); + + // Starts watching the subchannel's connectivity state. + // The first callback to the watcher will be delivered when the + // subchannel's connectivity state becomes a value other than + // initial_state, which may happen immediately. + // Subsequent callbacks will be delivered as the subchannel's state + // changes. + // The watcher will be destroyed either when the subchannel is + // destroyed or when CancelConnectivityStateWatch() is called. + void WatchConnectivityState(grpc_connectivity_state initial_state, + UniquePtr health_check_service_name, + UniquePtr watcher); + + // Cancels a connectivity state watch. + // If the watcher has already been destroyed, this is a no-op. + void CancelConnectivityStateWatch(const char* health_check_service_name, + ConnectivityStateWatcher* watcher); + + // Attempt to connect to the backend. Has no effect if already connected. + void AttemptToConnect(); // Resets the connection backoff of the subchannel. // TODO(roth): Move connection backoff out of subchannels and up into LB @@ -236,12 +284,62 @@ class Subchannel { grpc_resolved_address* addr); private: - struct ExternalStateWatcher; + // A linked list of ConnectivityStateWatchers that are monitoring the + // subchannel's state. + class ConnectivityStateWatcherList { + public: + ~ConnectivityStateWatcherList() { Clear(); } + + void AddWatcherLocked(UniquePtr watcher); + void RemoveWatcherLocked(ConnectivityStateWatcher* watcher); + + // Notifies all watchers in the list about a change to state. + void NotifyLocked(Subchannel* subchannel, grpc_connectivity_state state); + + void Clear(); + + bool empty() const { return head_ == nullptr; } + + private: + ConnectivityStateWatcher* head_ = nullptr; + }; + + // A map that tracks ConnectivityStateWatchers using a particular health + // check service name. + // + // There is one entry in the map for each health check service name. + // Entries exist only as long as there are watchers using the + // corresponding service name. + // + // A health check client is maintained only while the subchannel is in + // state READY. + class HealthWatcherMap { + public: + void AddWatcherLocked(Subchannel* subchannel, + grpc_connectivity_state initial_state, + UniquePtr health_check_service_name, + UniquePtr watcher); + void RemoveWatcherLocked(const char* health_check_service_name, + ConnectivityStateWatcher* watcher); + + // Notifies the watcher when the subchannel's state changes. + void NotifyLocked(grpc_connectivity_state state); + + grpc_connectivity_state CheckConnectivityStateLocked( + Subchannel* subchannel, const char* health_check_service_name); + + void ShutdownLocked(); + + private: + class HealthWatcher; + + Map, StringLess> map_; + }; + class ConnectedSubchannelStateWatcher; // Sets the subchannel's connectivity state to \a state. - void SetConnectivityStateLocked(grpc_connectivity_state state, - const char* reason); + void SetConnectivityStateLocked(grpc_connectivity_state state); // Methods for connection. void MaybeStartConnectingLocked(); @@ -279,15 +377,15 @@ class Subchannel { grpc_closure on_connecting_finished_; // Active connection, or null. RefCountedPtr connected_subchannel_; - OrphanablePtr connected_subchannel_watcher_; bool connecting_ = false; bool disconnected_ = false; // Connectivity state tracking. - grpc_connectivity_state_tracker state_tracker_; - grpc_connectivity_state_tracker state_and_health_tracker_; - UniquePtr health_check_service_name_; - ExternalStateWatcher* external_state_watcher_list_ = nullptr; + grpc_connectivity_state state_ = GRPC_CHANNEL_IDLE; + // The list of watchers without a health check service name. + ConnectivityStateWatcherList watcher_list_; + // The map of watchers with health check service names. + HealthWatcherMap health_watcher_map_; // Backoff state. BackOff backoff_; diff --git a/src/core/ext/filters/deadline/deadline_filter.cc b/src/core/ext/filters/deadline/deadline_filter.cc index e54f29ea3a7..20a2953e5ff 100644 --- a/src/core/ext/filters/deadline/deadline_filter.cc +++ b/src/core/ext/filters/deadline/deadline_filter.cc @@ -68,8 +68,7 @@ static void timer_callback(void* arg, grpc_error* error) { error = grpc_error_set_int( GRPC_ERROR_CREATE_FROM_STATIC_STRING("Deadline Exceeded"), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_DEADLINE_EXCEEDED); - grpc_call_combiner_cancel(deadline_state->call_combiner, - GRPC_ERROR_REF(error)); + deadline_state->call_combiner->Cancel(GRPC_ERROR_REF(error)); GRPC_CLOSURE_INIT(&deadline_state->timer_callback, send_cancel_op_in_call_combiner, elem, grpc_schedule_on_exec_ctx); @@ -183,7 +182,7 @@ static void start_timer_after_init(void* arg, grpc_error* error) { grpc_deadline_state::grpc_deadline_state(grpc_call_element* elem, grpc_call_stack* call_stack, - grpc_call_combiner* call_combiner, + grpc_core::CallCombiner* call_combiner, grpc_millis deadline) : call_stack(call_stack), call_combiner(call_combiner) { // Deadline will always be infinite on servers, so the timer will only be diff --git a/src/core/ext/filters/deadline/deadline_filter.h b/src/core/ext/filters/deadline/deadline_filter.h index e37032999c6..7c4e9aaed0e 100644 --- a/src/core/ext/filters/deadline/deadline_filter.h +++ b/src/core/ext/filters/deadline/deadline_filter.h @@ -32,12 +32,13 @@ enum grpc_deadline_timer_state { // Must be the first field in the filter's call_data. struct grpc_deadline_state { grpc_deadline_state(grpc_call_element* elem, grpc_call_stack* call_stack, - grpc_call_combiner* call_combiner, grpc_millis deadline); + grpc_core::CallCombiner* call_combiner, + grpc_millis deadline); ~grpc_deadline_state(); // We take a reference to the call stack for the timer callback. grpc_call_stack* call_stack; - grpc_call_combiner* call_combiner; + grpc_core::CallCombiner* call_combiner; grpc_deadline_timer_state timer_state = GRPC_DEADLINE_STATE_INITIAL; grpc_timer timer; grpc_closure timer_callback; diff --git a/src/core/ext/filters/http/client/http_client_filter.cc b/src/core/ext/filters/http/client/http_client_filter.cc index 6200e7ddc4c..4ef6c1f610e 100644 --- a/src/core/ext/filters/http/client/http_client_filter.cc +++ b/src/core/ext/filters/http/client/http_client_filter.cc @@ -62,7 +62,7 @@ struct call_data { ~call_data() { GRPC_ERROR_UNREF(recv_initial_metadata_error); } - grpc_call_combiner* call_combiner; + grpc_core::CallCombiner* call_combiner; // State for handling send_initial_metadata ops. grpc_linked_mdelem method; grpc_linked_mdelem scheme; diff --git a/src/core/ext/filters/http/client_authority_filter.cc b/src/core/ext/filters/http/client_authority_filter.cc index 125059c93a9..85b30bc13ca 100644 --- a/src/core/ext/filters/http/client_authority_filter.cc +++ b/src/core/ext/filters/http/client_authority_filter.cc @@ -40,7 +40,7 @@ namespace { struct call_data { grpc_linked_mdelem authority_storage; - grpc_call_combiner* call_combiner; + grpc_core::CallCombiner* call_combiner; }; struct channel_data { diff --git a/src/core/ext/filters/http/message_compress/message_compress_filter.cc b/src/core/ext/filters/http/message_compress/message_compress_filter.cc index 1527ea440c4..d2b1f6794cd 100644 --- a/src/core/ext/filters/http/message_compress/message_compress_filter.cc +++ b/src/core/ext/filters/http/message_compress/message_compress_filter.cc @@ -72,7 +72,7 @@ struct call_data { GRPC_ERROR_UNREF(cancel_error); } - grpc_call_combiner* call_combiner; + grpc_core::CallCombiner* call_combiner; grpc_linked_mdelem compression_algorithm_storage; grpc_linked_mdelem stream_compression_algorithm_storage; grpc_linked_mdelem accept_encoding_storage; @@ -249,7 +249,7 @@ static void finish_send_message(grpc_call_element* elem) { bool did_compress = grpc_msg_compress(calld->message_compression_algorithm, &calld->slices, &tmp); if (did_compress) { - if (grpc_compression_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_compression_trace)) { const char* algo_name; const size_t before_size = calld->slices.length; const size_t after_size = tmp.length; @@ -265,7 +265,7 @@ static void finish_send_message(grpc_call_element* elem) { grpc_slice_buffer_swap(&calld->slices, &tmp); send_flags |= GRPC_WRITE_INTERNAL_COMPRESS; } else { - if (grpc_compression_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_compression_trace)) { const char* algo_name; GPR_ASSERT(grpc_message_compression_algorithm_name( calld->message_compression_algorithm, &algo_name)); diff --git a/src/core/ext/filters/http/server/http_server_filter.cc b/src/core/ext/filters/http/server/http_server_filter.cc index 443a356452a..028d268c7b3 100644 --- a/src/core/ext/filters/http/server/http_server_filter.cc +++ b/src/core/ext/filters/http/server/http_server_filter.cc @@ -61,7 +61,7 @@ struct call_data { } } - grpc_call_combiner* call_combiner; + grpc_core::CallCombiner* call_combiner; // Outgoing headers to add to send_initial_metadata. grpc_linked_mdelem status; diff --git a/src/core/ext/filters/message_size/message_size_filter.cc b/src/core/ext/filters/message_size/message_size_filter.cc index 4d120c0eb76..8e93d11c9c0 100644 --- a/src/core/ext/filters/message_size/message_size_filter.cc +++ b/src/core/ext/filters/message_size/message_size_filter.cc @@ -32,75 +32,78 @@ #include "src/core/lib/gpr/string.h" #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" +#include "src/core/lib/surface/call.h" #include "src/core/lib/surface/channel_init.h" -typedef struct { - int max_send_size; - int max_recv_size; -} message_size_limits; +static void recv_message_ready(void* user_data, grpc_error* error); +static void recv_trailing_metadata_ready(void* user_data, grpc_error* error); namespace grpc_core { -namespace { - -class MessageSizeLimits : public RefCounted { - public: - static RefCountedPtr CreateFromJson(const grpc_json* json); - - const message_size_limits& limits() const { return limits_; } - private: - // So New() can call our private ctor. - template - friend T* grpc_core::New(Args&&... args); - - MessageSizeLimits(int max_send_size, int max_recv_size) { - limits_.max_send_size = max_send_size; - limits_.max_recv_size = max_recv_size; - } - - message_size_limits limits_; -}; +namespace { +size_t g_message_size_parser_index; +} // namespace -RefCountedPtr MessageSizeLimits::CreateFromJson( - const grpc_json* json) { +UniquePtr MessageSizeParser::ParsePerMethodParams( + const grpc_json* json, grpc_error** error) { + GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE); int max_request_message_bytes = -1; int max_response_message_bytes = -1; + InlinedVector error_list; for (grpc_json* field = json->child; field != nullptr; field = field->next) { if (field->key == nullptr) continue; if (strcmp(field->key, "maxRequestMessageBytes") == 0) { - if (max_request_message_bytes >= 0) return nullptr; // Duplicate. + if (max_request_message_bytes >= 0) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:maxRequestMessageBytes error:Duplicate entry")); + } // Duplicate, continue parsing. if (field->type != GRPC_JSON_STRING && field->type != GRPC_JSON_NUMBER) { - return nullptr; + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:maxRequestMessageBytes error:should be of type number")); + } else { + max_request_message_bytes = gpr_parse_nonnegative_int(field->value); + if (max_request_message_bytes == -1) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:maxRequestMessageBytes error:should be non-negative")); + } } - max_request_message_bytes = gpr_parse_nonnegative_int(field->value); - if (max_request_message_bytes == -1) return nullptr; } else if (strcmp(field->key, "maxResponseMessageBytes") == 0) { - if (max_response_message_bytes >= 0) return nullptr; // Duplicate. + if (max_response_message_bytes >= 0) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:maxResponseMessageBytes error:Duplicate entry")); + } // Duplicate, continue parsing if (field->type != GRPC_JSON_STRING && field->type != GRPC_JSON_NUMBER) { - return nullptr; + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:maxResponseMessageBytes error:should be of type number")); + } else { + max_response_message_bytes = gpr_parse_nonnegative_int(field->value); + if (max_response_message_bytes == -1) { + error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "field:maxResponseMessageBytes error:should be non-negative")); + } } - max_response_message_bytes = gpr_parse_nonnegative_int(field->value); - if (max_response_message_bytes == -1) return nullptr; } } - return MakeRefCounted(max_request_message_bytes, - max_response_message_bytes); + if (!error_list.empty()) { + *error = GRPC_ERROR_CREATE_FROM_VECTOR("Message size parser", &error_list); + return nullptr; + } + return UniquePtr(New( + max_request_message_bytes, max_response_message_bytes)); } -} // namespace -} // namespace grpc_core +void MessageSizeParser::Register() { + g_message_size_parser_index = ServiceConfig::RegisterParser( + UniquePtr(New())); +} -static void recv_message_ready(void* user_data, grpc_error* error); -static void recv_trailing_metadata_ready(void* user_data, grpc_error* error); +size_t MessageSizeParser::ParserIndex() { return g_message_size_parser_index; } +} // namespace grpc_core namespace { - struct channel_data { - message_size_limits limits; - // Maps path names to refcounted_message_size_limits structs. - grpc_core::RefCountedPtr>> - method_limit_table; + grpc_core::MessageSizeParsedConfig::message_size_limits limits; + grpc_core::RefCountedPtr svc_cfg; }; struct call_data { @@ -116,29 +119,42 @@ struct call_data { // Note: Per-method config is only available on the client, so we // apply the max request size to the send limit and the max response // size to the receive limit. - if (chand.method_limit_table != nullptr) { - grpc_core::RefCountedPtr limits = - grpc_core::ServiceConfig::MethodConfigTableLookup( - *chand.method_limit_table, args.path); - if (limits != nullptr) { - if (limits->limits().max_send_size >= 0 && - (limits->limits().max_send_size < this->limits.max_send_size || - this->limits.max_send_size < 0)) { - this->limits.max_send_size = limits->limits().max_send_size; - } - if (limits->limits().max_recv_size >= 0 && - (limits->limits().max_recv_size < this->limits.max_recv_size || - this->limits.max_recv_size < 0)) { - this->limits.max_recv_size = limits->limits().max_recv_size; - } + const grpc_core::MessageSizeParsedConfig* limits = nullptr; + grpc_core::ServiceConfig::CallData* svc_cfg_call_data = nullptr; + if (args.context != nullptr) { + svc_cfg_call_data = static_cast( + args.context[GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA].value); + } + if (svc_cfg_call_data != nullptr) { + limits = static_cast( + svc_cfg_call_data->GetMethodParsedConfig( + grpc_core::MessageSizeParser::ParserIndex())); + } else if (chand.svc_cfg != nullptr) { + const auto* objs_vector = + chand.svc_cfg->GetMethodParsedConfigVector(args.path); + if (objs_vector != nullptr) { + limits = static_cast( + (*objs_vector)[grpc_core::MessageSizeParser::ParserIndex()].get()); + } + } + if (limits != nullptr) { + if (limits->limits().max_send_size >= 0 && + (limits->limits().max_send_size < this->limits.max_send_size || + this->limits.max_send_size < 0)) { + this->limits.max_send_size = limits->limits().max_send_size; + } + if (limits->limits().max_recv_size >= 0 && + (limits->limits().max_recv_size < this->limits.max_recv_size || + this->limits.max_recv_size < 0)) { + this->limits.max_recv_size = limits->limits().max_recv_size; } } } ~call_data() { GRPC_ERROR_UNREF(error); } - grpc_call_combiner* call_combiner; - message_size_limits limits; + grpc_core::CallCombiner* call_combiner; + grpc_core::MessageSizeParsedConfig::message_size_limits limits; // Receive closures are chained: we inject this closure as the // recv_message_ready up-call on transport_stream_op, and remember to // call our next_recv_message_ready member after handling it. @@ -284,9 +300,9 @@ static int default_size(const grpc_channel_args* args, return without_minimal_stack; } -message_size_limits get_message_size_limits( +grpc_core::MessageSizeParsedConfig::message_size_limits get_message_size_limits( const grpc_channel_args* channel_args) { - message_size_limits lim; + grpc_core::MessageSizeParsedConfig::message_size_limits lim; lim.max_send_size = default_size(channel_args, GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH); lim.max_recv_size = @@ -313,21 +329,27 @@ static grpc_error* init_channel_elem(grpc_channel_element* elem, grpc_channel_element_args* args) { GPR_ASSERT(!args->is_last); channel_data* chand = static_cast(elem->channel_data); + new (chand) channel_data(); chand->limits = get_message_size_limits(args->channel_args); - // Get method config table from channel args. + // TODO(yashykt): We only need to read GRPC_ARG_SERVICE_CONFIG in the case of + // direct channels. (Service config is otherwise stored in the call_context by + // client_channel filter.) If we ever need a second filter that also needs to + // parse GRPC_ARG_SERVICE_CONFIG, we should refactor this code and add a + // separate filter that reads GRPC_ARG_SERVICE_CONFIG and saves the parsed + // config in the call_context. const grpc_arg* channel_arg = grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVICE_CONFIG); const char* service_config_str = grpc_channel_arg_get_string(channel_arg); if (service_config_str != nullptr) { grpc_error* service_config_error = GRPC_ERROR_NONE; - grpc_core::RefCountedPtr service_config = - grpc_core::ServiceConfig::Create(service_config_str, - &service_config_error); - GRPC_ERROR_UNREF(service_config_error); - if (service_config != nullptr) { - chand->method_limit_table = service_config->CreateMethodConfigTable( - grpc_core::MessageSizeLimits::CreateFromJson); + auto svc_cfg = grpc_core::ServiceConfig::Create(service_config_str, + &service_config_error); + if (service_config_error == GRPC_ERROR_NONE) { + chand->svc_cfg = std::move(svc_cfg); + } else { + gpr_log(GPR_ERROR, "%s", grpc_error_string(service_config_error)); } + GRPC_ERROR_UNREF(service_config_error); } return GRPC_ERROR_NONE; } @@ -335,7 +357,7 @@ static grpc_error* init_channel_elem(grpc_channel_element* elem, // Destructor for channel_data. static void destroy_channel_elem(grpc_channel_element* elem) { channel_data* chand = static_cast(elem->channel_data); - chand->method_limit_table.reset(); + chand->~channel_data(); } const grpc_channel_filter grpc_message_size_filter = { @@ -351,18 +373,34 @@ const grpc_channel_filter grpc_message_size_filter = { grpc_channel_next_get_info, "message_size"}; +// Used for GRPC_CLIENT_SUBCHANNEL +static bool maybe_add_message_size_filter_subchannel( + grpc_channel_stack_builder* builder, void* arg) { + const grpc_channel_args* channel_args = + grpc_channel_stack_builder_get_channel_arguments(builder); + if (grpc_channel_args_want_minimal_stack(channel_args)) { + return true; + } + return grpc_channel_stack_builder_prepend_filter( + builder, &grpc_message_size_filter, nullptr, nullptr); +} + +// Used for GRPC_CLIENT_DIRECT_CHANNEL and GRPC_SERVER_CHANNEL. Adds the filter +// only if message size limits or service config is specified. static bool maybe_add_message_size_filter(grpc_channel_stack_builder* builder, void* arg) { const grpc_channel_args* channel_args = grpc_channel_stack_builder_get_channel_arguments(builder); bool enable = false; - message_size_limits lim = get_message_size_limits(channel_args); + grpc_core::MessageSizeParsedConfig::message_size_limits lim = + get_message_size_limits(channel_args); if (lim.max_send_size != -1 || lim.max_recv_size != -1) { enable = true; } const grpc_arg* a = grpc_channel_args_find(channel_args, GRPC_ARG_SERVICE_CONFIG); - if (a != nullptr) { + const char* svc_cfg_str = grpc_channel_arg_get_string(a); + if (svc_cfg_str != nullptr) { enable = true; } if (enable) { @@ -374,15 +412,16 @@ static bool maybe_add_message_size_filter(grpc_channel_stack_builder* builder, } void grpc_message_size_filter_init(void) { - grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, - GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, - maybe_add_message_size_filter, nullptr); + grpc_channel_init_register_stage( + GRPC_CLIENT_SUBCHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, + maybe_add_message_size_filter_subchannel, nullptr); grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, maybe_add_message_size_filter, nullptr); grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, maybe_add_message_size_filter, nullptr); + grpc_core::MessageSizeParser::Register(); } void grpc_message_size_filter_shutdown(void) {} diff --git a/src/core/ext/filters/message_size/message_size_filter.h b/src/core/ext/filters/message_size/message_size_filter.h index f66636e5832..1dde55f40b1 100644 --- a/src/core/ext/filters/message_size/message_size_filter.h +++ b/src/core/ext/filters/message_size/message_size_filter.h @@ -19,8 +19,41 @@ #include +#include "src/core/ext/filters/client_channel/service_config.h" #include "src/core/lib/channel/channel_stack.h" extern const grpc_channel_filter grpc_message_size_filter; +namespace grpc_core { + +class MessageSizeParsedConfig : public ServiceConfig::ParsedConfig { + public: + struct message_size_limits { + int max_send_size; + int max_recv_size; + }; + + MessageSizeParsedConfig(int max_send_size, int max_recv_size) { + limits_.max_send_size = max_send_size; + limits_.max_recv_size = max_recv_size; + } + + const message_size_limits& limits() const { return limits_; } + + private: + message_size_limits limits_; +}; + +class MessageSizeParser : public ServiceConfig::Parser { + public: + UniquePtr ParsePerMethodParams( + const grpc_json* json, grpc_error** error) override; + + static void Register(); + + static size_t ParserIndex(); +}; + +} // namespace grpc_core + #endif /* GRPC_CORE_EXT_FILTERS_MESSAGE_SIZE_MESSAGE_SIZE_FILTER_H */ diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.cc b/src/core/ext/transport/chttp2/server/chttp2_server.cc index 040ea2044b1..8285ee76445 100644 --- a/src/core/ext/transport/chttp2/server/chttp2_server.cc +++ b/src/core/ext/transport/chttp2/server/chttp2_server.cc @@ -20,12 +20,12 @@ #include "src/core/ext/transport/chttp2/server/chttp2_server.h" -#include - #include #include #include +#include +#include #include #include #include @@ -289,6 +289,50 @@ static void server_destroy_listener(grpc_server* server, void* arg, grpc_tcp_server_unref(tcp_server); } +static grpc_error* chttp2_server_add_acceptor(grpc_server* server, + const char* name, + grpc_channel_args* args) { + grpc_tcp_server* tcp_server = nullptr; + grpc_error* err = GRPC_ERROR_NONE; + server_state* state = nullptr; + const grpc_arg* arg = nullptr; + grpc_core::TcpServerFdHandler** arg_val = nullptr; + state = static_cast(gpr_zalloc(sizeof(*state))); + GRPC_CLOSURE_INIT(&state->tcp_server_shutdown_complete, + tcp_server_shutdown_complete, state, + grpc_schedule_on_exec_ctx); + err = grpc_tcp_server_create(&state->tcp_server_shutdown_complete, args, + &tcp_server); + if (err != GRPC_ERROR_NONE) { + goto error; + } + state->server = server; + state->tcp_server = tcp_server; + state->args = args; + state->shutdown = true; + gpr_mu_init(&state->mu); + // TODO(yangg) channelz + arg = grpc_channel_args_find(args, name); + GPR_ASSERT(arg->type == GRPC_ARG_POINTER); + arg_val = static_cast(arg->value.pointer.p); + *arg_val = grpc_tcp_server_create_fd_handler(tcp_server); + + grpc_server_add_listener(server, state, server_start_listener, + server_destroy_listener, /* socket_uuid */ 0); + return err; + +/* Error path: cleanup and return */ +error: + GPR_ASSERT(err != GRPC_ERROR_NONE); + if (tcp_server) { + grpc_tcp_server_unref(tcp_server); + } else { + grpc_channel_args_destroy(args); + gpr_free(state); + } + return err; +} + grpc_error* grpc_chttp2_server_add_port(grpc_server* server, const char* addr, grpc_channel_args* args, int* port_num) { @@ -306,6 +350,10 @@ grpc_error* grpc_chttp2_server_add_port(grpc_server* server, const char* addr, *port_num = -1; + if (strncmp(addr, "external:", 9) == 0) { + return chttp2_server_add_acceptor(server, addr, args); + } + /* resolve address */ err = grpc_blocking_resolve_address(addr, "https", &resolved); if (err != GRPC_ERROR_NONE) { diff --git a/src/core/ext/transport/chttp2/transport/chttp2_plugin.cc b/src/core/ext/transport/chttp2/transport/chttp2_plugin.cc index 531ea73e9e6..ac13d73d3b5 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_plugin.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_plugin.cc @@ -20,16 +20,18 @@ #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include "src/core/lib/debug/trace.h" -#include "src/core/lib/gpr/env.h" +#include "src/core/lib/gprpp/global_config.h" #include "src/core/lib/transport/metadata.h" +GPR_GLOBAL_CONFIG_DEFINE_BOOL( + grpc_experimental_disable_flow_control, false, + "If set, flow control will be effectively disabled. Max out all values and " + "assume the remote peer does the same. Thus we can ignore any flow control " + "bookkeeping, error checking, and decision making"); + void grpc_chttp2_plugin_init(void) { - g_flow_control_enabled = true; - char* env_variable = gpr_getenv("GRPC_EXPERIMENTAL_DISABLE_FLOW_CONTROL"); - if (env_variable != nullptr) { - g_flow_control_enabled = false; - gpr_free(env_variable); - } + g_flow_control_enabled = + !GPR_GLOBAL_CONFIG_GET(grpc_experimental_disable_flow_control); } void grpc_chttp2_plugin_shutdown(void) {} diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc index 5f850df7b5a..48c3d002bbd 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc @@ -655,11 +655,12 @@ grpc_chttp2_stream::Reffer::Reffer(grpc_chttp2_stream* s) { grpc_chttp2_stream::grpc_chttp2_stream(grpc_chttp2_transport* t, grpc_stream_refcount* refcount, const void* server_data, - gpr_arena* arena) + grpc_core::Arena* arena) : t(t), refcount(refcount), reffer(this), - metadata_buffer{{arena}, {arena}} { + metadata_buffer{grpc_chttp2_incoming_metadata_buffer(arena), + grpc_chttp2_incoming_metadata_buffer(arena)} { if (server_data) { id = static_cast((uintptr_t)server_data); *t->accepting_stream = this; @@ -678,8 +679,6 @@ grpc_chttp2_stream::grpc_chttp2_stream(grpc_chttp2_transport* t, grpc_slice_buffer_init(&frame_storage); grpc_slice_buffer_init(&unprocessed_incoming_frames_buffer); grpc_slice_buffer_init(&flow_controlled_buffer); - grpc_slice_buffer_init(&compressed_data_buffer); - grpc_slice_buffer_init(&decompressed_data_buffer); GRPC_CLOSURE_INIT(&complete_fetch_locked, ::complete_fetch_locked, this, grpc_combiner_scheduler(t->combiner)); @@ -703,8 +702,13 @@ grpc_chttp2_stream::~grpc_chttp2_stream() { grpc_slice_buffer_destroy_internal(&unprocessed_incoming_frames_buffer); grpc_slice_buffer_destroy_internal(&frame_storage); - grpc_slice_buffer_destroy_internal(&compressed_data_buffer); - grpc_slice_buffer_destroy_internal(&decompressed_data_buffer); + if (stream_compression_method != GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS) { + grpc_slice_buffer_destroy_internal(&compressed_data_buffer); + } + if (stream_decompression_method != + GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS) { + grpc_slice_buffer_destroy_internal(&decompressed_data_buffer); + } grpc_chttp2_list_remove_stalled_by_transport(t, this); grpc_chttp2_list_remove_stalled_by_stream(t, this); @@ -740,7 +744,7 @@ grpc_chttp2_stream::~grpc_chttp2_stream() { static int init_stream(grpc_transport* gt, grpc_stream* gs, grpc_stream_refcount* refcount, const void* server_data, - gpr_arena* arena) { + grpc_core::Arena* arena) { GPR_TIMER_SCOPE("init_stream", 0); grpc_chttp2_transport* t = reinterpret_cast(gt); new (gs) grpc_chttp2_stream(t, refcount, server_data, arena); @@ -758,12 +762,15 @@ static void destroy_stream(grpc_transport* gt, grpc_stream* gs, GPR_TIMER_SCOPE("destroy_stream", 0); grpc_chttp2_transport* t = reinterpret_cast(gt); grpc_chttp2_stream* s = reinterpret_cast(gs); - - if (s->stream_compression_ctx != nullptr) { + if (s->stream_compression_method != + GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS && + s->stream_compression_ctx != nullptr) { grpc_stream_compression_context_destroy(s->stream_compression_ctx); s->stream_compression_ctx = nullptr; } - if (s->stream_decompression_ctx != nullptr) { + if (s->stream_decompression_method != + GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS && + s->stream_decompression_ctx != nullptr) { grpc_stream_compression_context_destroy(s->stream_decompression_ctx); s->stream_decompression_ctx = nullptr; } @@ -1242,7 +1249,7 @@ void grpc_chttp2_complete_closure_step(grpc_chttp2_transport* t, return; } closure->next_data.scratch -= CLOSURE_BARRIER_FIRST_REF_BIT; - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { const char* errstr = grpc_error_string(error); gpr_log( GPR_INFO, @@ -1394,7 +1401,7 @@ static void perform_stream_op_locked(void* stream_op, s->context = op->payload->context; s->traced = op->is_traced; - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { char* str = grpc_transport_stream_op_batch_string(op); gpr_log(GPR_INFO, "perform_stream_op_locked: %s; on_complete = %p", str, op->on_complete); @@ -1441,7 +1448,12 @@ static void perform_stream_op_locked(void* stream_op, true, &s->stream_compression_method) == 0) { s->stream_compression_method = GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS; } - + if (s->stream_compression_method != + GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS) { + s->uncompressed_data_size = 0; + s->stream_compression_ctx = nullptr; + grpc_slice_buffer_init(&s->compressed_data_buffer); + } s->send_initial_metadata_finished = add_closure_barrier(on_complete); s->send_initial_metadata = op_payload->send_initial_metadata.send_initial_metadata; @@ -1693,7 +1705,7 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs, } } - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { char* str = grpc_transport_stream_op_batch_string(op); gpr_log(GPR_INFO, "perform_stream_op[s=%p]: %s", s, str); gpr_free(str); @@ -1708,7 +1720,7 @@ static void perform_stream_op(grpc_transport* gt, grpc_stream* gs, } static void cancel_pings(grpc_chttp2_transport* t, grpc_error* error) { - /* callback remaining pings: they're not allowed to call into the transpot, + /* callback remaining pings: they're not allowed to call into the transport, and maybe they hold resources that need to be freed */ grpc_chttp2_ping_queue* pq = &t->ping_queue; GPR_ASSERT(error != GRPC_ERROR_NONE); @@ -1860,7 +1872,7 @@ static void perform_transport_op_locked(void* stream_op, static void perform_transport_op(grpc_transport* gt, grpc_transport_op* op) { grpc_chttp2_transport* t = reinterpret_cast(gt); - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { char* msg = grpc_transport_op_string(op); gpr_log(GPR_INFO, "perform_transport_op[t=%p]: %s", t, msg); gpr_free(msg); @@ -1997,27 +2009,39 @@ void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_chttp2_transport* t, !s->seen_error && s->recv_trailing_metadata_finished != nullptr) { /* Maybe some SYNC_FLUSH data is left in frame_storage. Consume them and * maybe decompress the next 5 bytes in the stream. */ - bool end_of_context; - if (!s->stream_decompression_ctx) { - s->stream_decompression_ctx = grpc_stream_compression_context_create( - s->stream_decompression_method); - } - if (!grpc_stream_decompress( - s->stream_decompression_ctx, &s->frame_storage, - &s->unprocessed_incoming_frames_buffer, nullptr, - GRPC_HEADER_SIZE_IN_BYTES, &end_of_context)) { - grpc_slice_buffer_reset_and_unref_internal(&s->frame_storage); - grpc_slice_buffer_reset_and_unref_internal( - &s->unprocessed_incoming_frames_buffer); - s->seen_error = true; - } else { + if (s->stream_decompression_method == + GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS) { + grpc_slice_buffer_move_first(&s->frame_storage, + GRPC_HEADER_SIZE_IN_BYTES, + &s->unprocessed_incoming_frames_buffer); if (s->unprocessed_incoming_frames_buffer.length > 0) { s->unprocessed_incoming_frames_decompressed = true; pending_data = true; } - if (end_of_context) { - grpc_stream_compression_context_destroy(s->stream_decompression_ctx); - s->stream_decompression_ctx = nullptr; + } else { + bool end_of_context; + if (!s->stream_decompression_ctx) { + s->stream_decompression_ctx = grpc_stream_compression_context_create( + s->stream_decompression_method); + } + if (!grpc_stream_decompress( + s->stream_decompression_ctx, &s->frame_storage, + &s->unprocessed_incoming_frames_buffer, nullptr, + GRPC_HEADER_SIZE_IN_BYTES, &end_of_context)) { + grpc_slice_buffer_reset_and_unref_internal(&s->frame_storage); + grpc_slice_buffer_reset_and_unref_internal( + &s->unprocessed_incoming_frames_buffer); + s->seen_error = true; + } else { + if (s->unprocessed_incoming_frames_buffer.length > 0) { + s->unprocessed_incoming_frames_decompressed = true; + pending_data = true; + } + if (end_of_context) { + grpc_stream_compression_context_destroy( + s->stream_decompression_ctx); + s->stream_decompression_ctx = nullptr; + } } } } @@ -2238,7 +2262,7 @@ void grpc_chttp2_mark_stream_closed(grpc_chttp2_transport* t, if (closed_read) { for (int i = 0; i < 2; i++) { if (s->published_metadata[i] == GRPC_METADATA_NOT_PUBLISHED) { - s->published_metadata[i] = GPRC_METADATA_PUBLISHED_AT_CLOSE; + s->published_metadata[i] = GRPC_METADATA_PUBLISHED_AT_CLOSE; } } grpc_chttp2_maybe_complete_recv_initial_metadata(t, s); @@ -2595,7 +2619,7 @@ static void schedule_bdp_ping_locked(grpc_chttp2_transport* t) { static void start_bdp_ping_locked(void* tp, grpc_error* error) { grpc_chttp2_transport* t = static_cast(tp); - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { gpr_log(GPR_INFO, "%s: Start BDP ping err=%s", t->peer_string, grpc_error_string(error)); } @@ -2611,7 +2635,7 @@ static void start_bdp_ping_locked(void* tp, grpc_error* error) { static void finish_bdp_ping_locked(void* tp, grpc_error* error) { grpc_chttp2_transport* t = static_cast(tp); - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { gpr_log(GPR_INFO, "%s: Complete BDP ping err=%s", t->peer_string, grpc_error_string(error)); } @@ -2743,7 +2767,7 @@ static void start_keepalive_ping_locked(void* arg, grpc_error* error) { if (t->channelz_socket != nullptr) { t->channelz_socket->RecordKeepaliveSent(); } - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { gpr_log(GPR_INFO, "%s: Start keepalive ping", t->peer_string); } GRPC_CHTTP2_REF_TRANSPORT(t, "keepalive watchdog"); @@ -2756,7 +2780,7 @@ static void finish_keepalive_ping_locked(void* arg, grpc_error* error) { grpc_chttp2_transport* t = static_cast(arg); if (t->keepalive_state == GRPC_CHTTP2_KEEPALIVE_STATE_PINGING) { if (error == GRPC_ERROR_NONE) { - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { gpr_log(GPR_INFO, "%s: Finish keepalive ping", t->peer_string); } t->keepalive_state = GRPC_CHTTP2_KEEPALIVE_STATE_WAITING; @@ -2940,6 +2964,8 @@ bool Chttp2IncomingByteStream::Next(size_t max_size_hint, } void Chttp2IncomingByteStream::MaybeCreateStreamDecompressionCtx() { + GPR_DEBUG_ASSERT(stream_->stream_decompression_method != + GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS); if (!stream_->stream_decompression_ctx) { stream_->stream_decompression_ctx = grpc_stream_compression_context_create( stream_->stream_decompression_method); @@ -2950,7 +2976,9 @@ grpc_error* Chttp2IncomingByteStream::Pull(grpc_slice* slice) { GPR_TIMER_SCOPE("incoming_byte_stream_pull", 0); grpc_error* error; if (stream_->unprocessed_incoming_frames_buffer.length > 0) { - if (!stream_->unprocessed_incoming_frames_decompressed) { + if (!stream_->unprocessed_incoming_frames_decompressed && + stream_->stream_decompression_method != + GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS) { bool end_of_context; MaybeCreateStreamDecompressionCtx(); if (!grpc_stream_decompress(stream_->stream_decompression_ctx, @@ -3062,7 +3090,7 @@ static void benign_reclaimer_locked(void* arg, grpc_error* error) { grpc_chttp2_stream_map_size(&t->stream_map) == 0) { /* Channel with no active streams: send a goaway to try and make it * disconnect cleanly */ - if (grpc_resource_quota_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_resource_quota_trace)) { gpr_log(GPR_INFO, "HTTP2: %s - send goaway to free memory", t->peer_string); } @@ -3070,7 +3098,8 @@ static void benign_reclaimer_locked(void* arg, grpc_error* error) { grpc_error_set_int( GRPC_ERROR_CREATE_FROM_STATIC_STRING("Buffers full"), GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM)); - } else if (error == GRPC_ERROR_NONE && grpc_resource_quota_trace.enabled()) { + } else if (error == GRPC_ERROR_NONE && + GRPC_TRACE_FLAG_ENABLED(grpc_resource_quota_trace)) { gpr_log(GPR_INFO, "HTTP2: %s - skip benign reclamation, there are still %" PRIdPTR " streams", @@ -3091,7 +3120,7 @@ static void destructive_reclaimer_locked(void* arg, grpc_error* error) { if (error == GRPC_ERROR_NONE && n > 0) { grpc_chttp2_stream* s = static_cast( grpc_chttp2_stream_map_rand(&t->stream_map)); - if (grpc_resource_quota_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_resource_quota_trace)) { gpr_log(GPR_INFO, "HTTP2: %s - abandon stream id %d", t->peer_string, s->id); } diff --git a/src/core/ext/transport/chttp2/transport/flow_control.h b/src/core/ext/transport/chttp2/transport/flow_control.h index 120fefc8b79..49e206fca3d 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.h +++ b/src/core/ext/transport/chttp2/transport/flow_control.h @@ -127,7 +127,7 @@ class FlowControlTrace { StreamFlowControl* sfc); void Finish(); - const bool enabled_ = grpc_flowctl_trace.enabled(); + const bool enabled_ = GRPC_TRACE_FLAG_ENABLED(grpc_flowctl_trace); TransportFlowControl* tfc_; StreamFlowControl* sfc_; diff --git a/src/core/ext/transport/chttp2/transport/frame_data.cc b/src/core/ext/transport/chttp2/transport/frame_data.cc index 6080a4bd1c4..3734c0150b7 100644 --- a/src/core/ext/transport/chttp2/transport/frame_data.cc +++ b/src/core/ext/transport/chttp2/transport/frame_data.cc @@ -104,23 +104,22 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames( uint8_t* end = nullptr; uint8_t* cur = nullptr; - grpc_slice slice = grpc_slice_buffer_take_first(slices); - - beg = GRPC_SLICE_START_PTR(slice); - end = GRPC_SLICE_END_PTR(slice); + grpc_slice* slice = grpc_slice_buffer_peek_first(slices); + beg = GRPC_SLICE_START_PTR(*slice); + end = GRPC_SLICE_END_PTR(*slice); cur = beg; uint32_t message_flags; char* msg; if (cur == end) { - grpc_slice_unref_internal(slice); + grpc_slice_buffer_remove_first(slices); continue; } switch (p->state) { case GRPC_CHTTP2_DATA_ERROR: p->state = GRPC_CHTTP2_DATA_ERROR; - grpc_slice_unref_internal(slice); + grpc_slice_buffer_remove_first(slices); return GRPC_ERROR_REF(p->error); case GRPC_CHTTP2_DATA_FH_0: s->stats.incoming.framing_bytes++; @@ -138,19 +137,19 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames( p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID, static_cast(s->id)); gpr_free(msg); - msg = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII); + msg = grpc_dump_slice(*slice, GPR_DUMP_HEX | GPR_DUMP_ASCII); p->error = grpc_error_set_str(p->error, GRPC_ERROR_STR_RAW_BYTES, grpc_slice_from_copied_string(msg)); gpr_free(msg); p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_OFFSET, cur - beg); p->state = GRPC_CHTTP2_DATA_ERROR; - grpc_slice_unref_internal(slice); + grpc_slice_buffer_remove_first(slices); return GRPC_ERROR_REF(p->error); } if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_1; - grpc_slice_unref_internal(slice); + grpc_slice_buffer_remove_first(slices); continue; } /* fallthrough */ @@ -159,7 +158,7 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames( p->frame_size = (static_cast(*cur)) << 24; if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_2; - grpc_slice_unref_internal(slice); + grpc_slice_buffer_remove_first(slices); continue; } /* fallthrough */ @@ -168,7 +167,7 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames( p->frame_size |= (static_cast(*cur)) << 16; if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_3; - grpc_slice_unref_internal(slice); + grpc_slice_buffer_remove_first(slices); continue; } /* fallthrough */ @@ -177,7 +176,7 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames( p->frame_size |= (static_cast(*cur)) << 8; if (++cur == end) { p->state = GRPC_CHTTP2_DATA_FH_4; - grpc_slice_unref_internal(slice); + grpc_slice_buffer_remove_first(slices); continue; } /* fallthrough */ @@ -204,19 +203,18 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames( p->state = GRPC_CHTTP2_DATA_FH_0; } s->pending_byte_stream = true; - if (cur != end) { - grpc_slice_buffer_undo_take_first( - slices, grpc_slice_sub(slice, static_cast(cur - beg), - static_cast(end - beg))); + grpc_slice_buffer_sub_first(slices, static_cast(cur - beg), + static_cast(end - beg)); + } else { + grpc_slice_buffer_remove_first(slices); } - grpc_slice_unref_internal(slice); return GRPC_ERROR_NONE; case GRPC_CHTTP2_DATA_FRAME: { GPR_ASSERT(p->parsing_frame != nullptr); GPR_ASSERT(slice_out != nullptr); if (cur == end) { - grpc_slice_unref_internal(slice); + grpc_slice_buffer_remove_first(slices); continue; } uint32_t remaining = static_cast(end - cur); @@ -224,32 +222,32 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames( s->stats.incoming.data_bytes += remaining; if (GRPC_ERROR_NONE != (error = p->parsing_frame->Push( - grpc_slice_sub(slice, static_cast(cur - beg), + grpc_slice_sub(*slice, static_cast(cur - beg), static_cast(end - beg)), slice_out))) { - grpc_slice_unref_internal(slice); + grpc_slice_buffer_remove_first(slices); return error; } if (GRPC_ERROR_NONE != (error = p->parsing_frame->Finished(GRPC_ERROR_NONE, true))) { - grpc_slice_unref_internal(slice); + grpc_slice_buffer_remove_first(slices); return error; } p->parsing_frame = nullptr; p->state = GRPC_CHTTP2_DATA_FH_0; - grpc_slice_unref_internal(slice); + grpc_slice_buffer_remove_first(slices); return GRPC_ERROR_NONE; } else if (remaining < p->frame_size) { s->stats.incoming.data_bytes += remaining; if (GRPC_ERROR_NONE != (error = p->parsing_frame->Push( - grpc_slice_sub(slice, static_cast(cur - beg), + grpc_slice_sub(*slice, static_cast(cur - beg), static_cast(end - beg)), slice_out))) { return error; } p->frame_size -= remaining; - grpc_slice_unref_internal(slice); + grpc_slice_buffer_remove_first(slices); return GRPC_ERROR_NONE; } else { GPR_ASSERT(remaining > p->frame_size); @@ -257,30 +255,27 @@ grpc_error* grpc_deframe_unprocessed_incoming_frames( if (GRPC_ERROR_NONE != p->parsing_frame->Push( grpc_slice_sub( - slice, static_cast(cur - beg), + *slice, static_cast(cur - beg), static_cast(cur + p->frame_size - beg)), slice_out)) { - grpc_slice_unref_internal(slice); + grpc_slice_buffer_remove_first(slices); return error; } if (GRPC_ERROR_NONE != (error = p->parsing_frame->Finished(GRPC_ERROR_NONE, true))) { - grpc_slice_unref_internal(slice); + grpc_slice_buffer_remove_first(slices); return error; } p->parsing_frame = nullptr; p->state = GRPC_CHTTP2_DATA_FH_0; cur += p->frame_size; - grpc_slice_buffer_undo_take_first( - slices, grpc_slice_sub(slice, static_cast(cur - beg), - static_cast(end - beg))); - grpc_slice_unref_internal(slice); + grpc_slice_buffer_sub_first(slices, static_cast(cur - beg), + static_cast(end - beg)); return GRPC_ERROR_NONE; } } } } - return GRPC_ERROR_NONE; } diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.cc b/src/core/ext/transport/chttp2/transport/frame_settings.cc index ed1554e2fef..3f84679ec31 100644 --- a/src/core/ext/transport/chttp2/transport/frame_settings.cc +++ b/src/core/ext/transport/chttp2/transport/frame_settings.cc @@ -217,19 +217,20 @@ grpc_error* grpc_chttp2_settings_parser_parse(void* p, grpc_chttp2_transport* t, parser->incoming_settings[id] != parser->value) { t->initial_window_update += static_cast(parser->value) - parser->incoming_settings[id]; - if (grpc_http_trace.enabled() || grpc_flowctl_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace) || + GRPC_TRACE_FLAG_ENABLED(grpc_flowctl_trace)) { gpr_log(GPR_INFO, "%p[%s] adding %d for initial_window change", t, t->is_client ? "cli" : "svr", static_cast(t->initial_window_update)); } } parser->incoming_settings[id] = parser->value; - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { gpr_log(GPR_INFO, "CHTTP2:%s:%s: got setting %s = %d", t->is_client ? "CLI" : "SVR", t->peer_string, sp->name, parser->value); } - } else if (grpc_http_trace.enabled()) { + } else if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)", parser->id, parser->value); } diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc index 1ae81fe37ff..d2607e97707 100644 --- a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc +++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc @@ -461,7 +461,7 @@ static void hpack_enc(grpc_chttp2_hpack_compressor* c, grpc_mdelem elem, "Reserved header (colon-prefixed) happening after regular ones."); } - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { char* k = grpc_slice_to_c_string(GRPC_MDKEY(elem)); char* v = nullptr; if (grpc_is_binary_header(GRPC_MDKEY(elem))) { @@ -660,7 +660,7 @@ void grpc_chttp2_hpack_compressor_set_max_table_size( } } c->advertise_table_size_change = 1; - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { gpr_log(GPR_INFO, "set max table size from encoder to %d", max_table_size); } } diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.cc b/src/core/ext/transport/chttp2/transport/hpack_parser.cc index 5bcdb4e2326..6e422127511 100644 --- a/src/core/ext/transport/chttp2/transport/hpack_parser.cc +++ b/src/core/ext/transport/chttp2/transport/hpack_parser.cc @@ -624,7 +624,7 @@ static const uint8_t inverse_base64[256] = { /* emission helpers */ static grpc_error* on_hdr(grpc_chttp2_hpack_parser* p, grpc_mdelem md, int add_to_table) { - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { char* k = grpc_slice_to_c_string(GRPC_MDKEY(md)); char* v = nullptr; if (grpc_is_binary_header(GRPC_MDKEY(md))) { @@ -994,7 +994,7 @@ static grpc_error* parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser* p, /* finish parsing a max table size change */ static grpc_error* finish_max_tbl_size(grpc_chttp2_hpack_parser* p, const uint8_t* cur, const uint8_t* end) { - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index); } grpc_error* err = @@ -1616,6 +1616,12 @@ static void parse_stream_compression_md(grpc_chttp2_transport* t, s->stream_decompression_method = GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS; } + + if (s->stream_decompression_method != + GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS) { + s->stream_decompression_ctx = nullptr; + grpc_slice_buffer_init(&s->decompressed_data_buffer); + } } grpc_error* grpc_chttp2_header_parser_parse(void* hpack_parser, diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.cc b/src/core/ext/transport/chttp2/transport/hpack_table.cc index fcfb01872bf..16aeb49df4d 100644 --- a/src/core/ext/transport/chttp2/transport/hpack_table.cc +++ b/src/core/ext/transport/chttp2/transport/hpack_table.cc @@ -247,7 +247,7 @@ void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl* tbl, if (tbl->max_bytes == max_bytes) { return; } - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { gpr_log(GPR_INFO, "Update hpack parser max size to %d", max_bytes); } while (tbl->mem_used > max_bytes) { @@ -270,7 +270,7 @@ grpc_error* grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl* tbl, gpr_free(msg); return err; } - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { gpr_log(GPR_INFO, "Update hpack parser table size to %d", bytes); } while (tbl->mem_used > bytes) { diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.cc b/src/core/ext/transport/chttp2/transport/incoming_metadata.cc index 1e04be79f7b..02623c978d7 100644 --- a/src/core/ext/transport/chttp2/transport/incoming_metadata.cc +++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.cc @@ -36,7 +36,7 @@ grpc_error* grpc_chttp2_incoming_metadata_buffer_add( buffer->count++; } else { storage = static_cast( - gpr_arena_alloc(buffer->arena, sizeof(grpc_linked_mdelem))); + buffer->arena->Alloc(sizeof(grpc_linked_mdelem))); } return grpc_metadata_batch_add_tail(&buffer->batch, storage, elem); } diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.h b/src/core/ext/transport/chttp2/transport/incoming_metadata.h index 4a9a59288f4..b63caa1ae25 100644 --- a/src/core/ext/transport/chttp2/transport/incoming_metadata.h +++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.h @@ -24,7 +24,8 @@ #include "src/core/lib/transport/transport.h" struct grpc_chttp2_incoming_metadata_buffer { - grpc_chttp2_incoming_metadata_buffer(gpr_arena* arena) : arena(arena) { + explicit grpc_chttp2_incoming_metadata_buffer(grpc_core::Arena* arena) + : arena(arena) { grpc_metadata_batch_init(&batch); batch.deadline = GRPC_MILLIS_INF_FUTURE; } @@ -34,7 +35,7 @@ struct grpc_chttp2_incoming_metadata_buffer { static constexpr size_t kPreallocatedMDElem = 10; - gpr_arena* arena; + grpc_core::Arena* arena; size_t size = 0; // total size of metadata. size_t count = 0; // minimum of count of metadata and kPreallocatedMDElem. // These preallocated mdelems are used while count < kPreallocatedMDElem. diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index e4fd5928f2c..4ab46f9808b 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -225,20 +225,20 @@ class Chttp2IncomingByteStream : public ByteStream { // TODO(roth): When I converted this class to C++, I wanted to make it // inherit from RefCounted or InternallyRefCounted instead of continuing // to use its own custom ref-counting code. However, that would require - // using multiple inheritence, which sucks in general. And to make matters + // using multiple inheritance, which sucks in general. And to make matters // worse, it causes problems with our New<> and Delete<> wrappers. // Specifically, unless RefCounted is first in the list of parent classes, // it will see a different value of the address of the object than the one // we actually allocated, in which case gpr_free() will be called on a // different address than the one we got from gpr_malloc(), thus causing a // crash. Given the fragility of depending on that, as well as a desire to - // avoid multiple inheritence in general, I've decided to leave this + // avoid multiple inheritance in general, I've decided to leave this // alone for now. We can revisit this once we're able to link against // libc++, at which point we can eliminate New<> and Delete<> and // switch to std::shared_ptr<>. void Ref() { refs_.Ref(); } void Unref() { - if (refs_.Unref()) { + if (GPR_UNLIKELY(refs_.Unref())) { grpc_core::Delete(this); } } @@ -499,12 +499,12 @@ typedef enum { GRPC_METADATA_NOT_PUBLISHED, GRPC_METADATA_SYNTHESIZED_FROM_FAKE, GRPC_METADATA_PUBLISHED_FROM_WIRE, - GPRC_METADATA_PUBLISHED_AT_CLOSE + GRPC_METADATA_PUBLISHED_AT_CLOSE } grpc_published_metadata_method; struct grpc_chttp2_stream { grpc_chttp2_stream(grpc_chttp2_transport* t, grpc_stream_refcount* refcount, - const void* server_data, gpr_arena* arena); + const void* server_data, grpc_core::Arena* arena); ~grpc_chttp2_stream(); void* context; @@ -583,10 +583,6 @@ struct grpc_chttp2_stream { grpc_slice_buffer frame_storage; /* protected by t combiner */ - /* Accessed only by transport thread when stream->pending_byte_stream == false - * Accessed only by application thread when stream->pending_byte_stream == - * true */ - grpc_slice_buffer unprocessed_incoming_frames_buffer; grpc_closure* on_next = nullptr; /* protected by t combiner */ bool pending_byte_stream = false; /* protected by t combiner */ // cached length of buffer to be used by the transport thread in cases where @@ -594,6 +590,10 @@ struct grpc_chttp2_stream { // application threads are allowed to modify // unprocessed_incoming_frames_buffer size_t unprocessed_incoming_frames_buffer_cached_length = 0; + /* Accessed only by transport thread when stream->pending_byte_stream == false + * Accessed only by application thread when stream->pending_byte_stream == + * true */ + grpc_slice_buffer unprocessed_incoming_frames_buffer; grpc_closure reset_byte_stream; grpc_error* byte_stream_error = GRPC_ERROR_NONE; /* protected by t combiner */ bool received_last_frame = false; /* protected by t combiner */ @@ -633,19 +633,8 @@ struct grpc_chttp2_stream { GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS; /* Stream decompression method to be used. */ grpc_stream_compression_method stream_decompression_method = - GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS; - /** Stream compression decompress context */ - grpc_stream_compression_context* stream_decompression_ctx = nullptr; - /** Stream compression compress context */ - grpc_stream_compression_context* stream_compression_ctx = nullptr; + GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS; - /** Buffer storing data that is compressed but not sent */ - grpc_slice_buffer compressed_data_buffer; - /** Amount of uncompressed bytes sent out when compressed_data_buffer is - * emptied */ - size_t uncompressed_data_size = 0; - /** Temporary buffer storing decompressed data */ - grpc_slice_buffer decompressed_data_buffer; /** Whether bytes stored in unprocessed_incoming_byte_stream is decompressed */ bool unprocessed_incoming_frames_decompressed = false; @@ -655,6 +644,22 @@ struct grpc_chttp2_stream { size_t decompressed_header_bytes = 0; /** Byte counter for number of bytes written */ size_t byte_counter = 0; + + /** Amount of uncompressed bytes sent out when compressed_data_buffer is + * emptied */ + size_t uncompressed_data_size; + /** Stream compression compress context */ + grpc_stream_compression_context* stream_compression_ctx; + /** Buffer storing data that is compressed but not sent */ + grpc_slice_buffer compressed_data_buffer; + + /** Stream compression decompress context */ + grpc_stream_compression_context* stream_decompression_ctx; + /** Temporary buffer storing decompressed data. + * Initialized, used, and destroyed only when stream uses (non-identity) + * compression. + */ + grpc_slice_buffer decompressed_data_buffer; }; /** Transport writing call flow: @@ -766,11 +771,12 @@ void grpc_chttp2_complete_closure_step(grpc_chttp2_transport* t, // extern grpc_core::TraceFlag grpc_http_trace; // extern grpc_core::TraceFlag grpc_flowctl_trace; -#define GRPC_CHTTP2_IF_TRACING(stmt) \ - if (!(grpc_http_trace.enabled())) \ - ; \ - else \ - stmt +#define GRPC_CHTTP2_IF_TRACING(stmt) \ + do { \ + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { \ + (stmt); \ + } \ + } while (0) void grpc_chttp2_fake_status(grpc_chttp2_transport* t, grpc_chttp2_stream* stream, grpc_error* error); diff --git a/src/core/ext/transport/chttp2/transport/parsing.cc b/src/core/ext/transport/chttp2/transport/parsing.cc index 84b2275ebc4..1aa6d971684 100644 --- a/src/core/ext/transport/chttp2/transport/parsing.cc +++ b/src/core/ext/transport/chttp2/transport/parsing.cc @@ -28,6 +28,7 @@ #include "src/core/lib/profiling/timers.h" #include "src/core/lib/slice/slice_string_helpers.h" +#include "src/core/lib/slice/slice_utils.h" #include "src/core/lib/transport/http2_errors.h" #include "src/core/lib/transport/static_metadata.h" #include "src/core/lib/transport/status_conversion.h" @@ -304,7 +305,7 @@ static grpc_error* init_frame_parser(grpc_chttp2_transport* t) { case GRPC_CHTTP2_FRAME_GOAWAY: return init_goaway_parser(t); default: - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { gpr_log(GPR_ERROR, "Unknown frame type %02x", t->incoming_frame_type); } return init_skip_frame_parser(t, 0); @@ -400,7 +401,7 @@ static void on_initial_header(void* tp, grpc_mdelem md) { grpc_chttp2_stream* s = t->incoming_stream; GPR_ASSERT(s != nullptr); - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { char* key = grpc_slice_to_c_string(GRPC_MDKEY(md)); char* value = grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX | GPR_DUMP_ASCII); @@ -410,53 +411,42 @@ static void on_initial_header(void* tp, grpc_mdelem md) { gpr_free(value); } - if (GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC) { - // We don't use grpc_mdelem_eq here to avoid executing additional - // instructions. The reasoning is if the payload is not equal, we already - // know that the metadata elements are not equal because the md is - // confirmed to be static. If we had used grpc_mdelem_eq here, then if the - // payloads are not equal, grpc_mdelem_eq executes more instructions to - // determine if they're equal or not. - if (md.payload == GRPC_MDELEM_GRPC_STATUS_1.payload || - md.payload == GRPC_MDELEM_GRPC_STATUS_2.payload) { - s->seen_error = true; - } - } else { - if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) && - !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) { - /* TODO(ctiller): check for a status like " 0" */ - s->seen_error = true; - } - - if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_TIMEOUT)) { - grpc_millis* cached_timeout = static_cast( - grpc_mdelem_get_user_data(md, free_timeout)); - grpc_millis timeout; - if (cached_timeout != nullptr) { - timeout = *cached_timeout; - } else { - if (GPR_UNLIKELY( - !grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) { - char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md)); - gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val); - gpr_free(val); - timeout = GRPC_MILLIS_INF_FUTURE; - } - if (GRPC_MDELEM_IS_INTERNED(md)) { - /* store the result */ - cached_timeout = - static_cast(gpr_malloc(sizeof(grpc_millis))); - *cached_timeout = timeout; - grpc_mdelem_set_user_data(md, free_timeout, cached_timeout); - } + // If md.payload == GRPC_MDELEM_GRPC_STATUS_1 or GRPC_MDELEM_GRPC_STATUS_2, + // then we have seen an error. In fact, if it is a GRPC_STATUS and it's + // not equal to GRPC_MDELEM_GRPC_STATUS_0, then we have seen an error. + if (grpc_slice_eq_static_interned(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) && + !grpc_mdelem_static_value_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) { + /* TODO(ctiller): check for a status like " 0" */ + s->seen_error = true; + } else if (grpc_slice_eq_static_interned(GRPC_MDKEY(md), + GRPC_MDSTR_GRPC_TIMEOUT)) { + grpc_millis* cached_timeout = + static_cast(grpc_mdelem_get_user_data(md, free_timeout)); + grpc_millis timeout; + if (cached_timeout != nullptr) { + timeout = *cached_timeout; + } else { + if (GPR_UNLIKELY( + !grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) { + char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md)); + gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val); + gpr_free(val); + timeout = GRPC_MILLIS_INF_FUTURE; } - if (timeout != GRPC_MILLIS_INF_FUTURE) { - grpc_chttp2_incoming_metadata_buffer_set_deadline( - &s->metadata_buffer[0], grpc_core::ExecCtx::Get()->Now() + timeout); + if (GRPC_MDELEM_IS_INTERNED(md)) { + /* store the result */ + cached_timeout = + static_cast(gpr_malloc(sizeof(grpc_millis))); + *cached_timeout = timeout; + grpc_mdelem_set_user_data(md, free_timeout, cached_timeout); } - GRPC_MDELEM_UNREF(md); - return; } + if (timeout != GRPC_MILLIS_INF_FUTURE) { + grpc_chttp2_incoming_metadata_buffer_set_deadline( + &s->metadata_buffer[0], grpc_core::ExecCtx::Get()->Now() + timeout); + } + GRPC_MDELEM_UNREF(md); + return; } const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md); @@ -496,7 +486,7 @@ static void on_trailing_header(void* tp, grpc_mdelem md) { grpc_chttp2_stream* s = t->incoming_stream; GPR_ASSERT(s != nullptr); - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { char* key = grpc_slice_to_c_string(GRPC_MDKEY(md)); char* value = grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX | GPR_DUMP_ASCII); @@ -506,19 +496,11 @@ static void on_trailing_header(void* tp, grpc_mdelem md) { gpr_free(value); } - if (GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC) { - // We don't use grpc_mdelem_eq here to avoid executing additional - // instructions. The reasoning is if the payload is not equal, we already - // know that the metadata elements are not equal because the md is - // confirmed to be static. If we had used grpc_mdelem_eq here, then if the - // payloads are not equal, grpc_mdelem_eq executes more instructions to - // determine if they're equal or not. - if (md.payload == GRPC_MDELEM_GRPC_STATUS_1.payload || - md.payload == GRPC_MDELEM_GRPC_STATUS_2.payload) { - s->seen_error = true; - } - } else if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) && - !grpc_mdelem_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) { + // If md.payload == GRPC_MDELEM_GRPC_STATUS_1 or GRPC_MDELEM_GRPC_STATUS_2, + // then we have seen an error. In fact, if it is a GRPC_STATUS and it's + // not equal to GRPC_MDELEM_GRPC_STATUS_0, then we have seen an error. + if (grpc_slice_eq_static_interned(GRPC_MDKEY(md), GRPC_MDSTR_GRPC_STATUS) && + !grpc_mdelem_static_value_eq(md, GRPC_MDELEM_GRPC_STATUS_0)) { /* TODO(ctiller): check for a status like " 0" */ s->seen_error = true; } @@ -761,7 +743,7 @@ static grpc_error* parse_frame_slice(grpc_chttp2_transport* t, if (GPR_LIKELY(err == GRPC_ERROR_NONE)) { return err; } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, &unused)) { - if (grpc_http_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) { const char* msg = grpc_error_string(err); gpr_log(GPR_ERROR, "%s", msg); } diff --git a/src/core/ext/transport/chttp2/transport/stream_lists.cc b/src/core/ext/transport/chttp2/transport/stream_lists.cc index 6626170a7e4..db79899dedc 100644 --- a/src/core/ext/transport/chttp2/transport/stream_lists.cc +++ b/src/core/ext/transport/chttp2/transport/stream_lists.cc @@ -67,7 +67,7 @@ static bool stream_list_pop(grpc_chttp2_transport* t, s->included[id] = 0; } *stream = s; - if (s && grpc_trace_http2_stream_state.enabled()) { + if (s && GRPC_TRACE_FLAG_ENABLED(grpc_trace_http2_stream_state)) { gpr_log(GPR_INFO, "%p[%d][%s]: pop from %s", t, s->id, t->is_client ? "cli" : "svr", stream_list_id_string(id)); } @@ -89,7 +89,7 @@ static void stream_list_remove(grpc_chttp2_transport* t, grpc_chttp2_stream* s, } else { t->lists[id].tail = s->links[id].prev; } - if (grpc_trace_http2_stream_state.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_http2_stream_state)) { gpr_log(GPR_INFO, "%p[%d][%s]: remove from %s", t, s->id, t->is_client ? "cli" : "svr", stream_list_id_string(id)); } @@ -121,7 +121,7 @@ static void stream_list_add_tail(grpc_chttp2_transport* t, } t->lists[id].tail = s; s->included[id] = 1; - if (grpc_trace_http2_stream_state.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_http2_stream_state)) { gpr_log(GPR_INFO, "%p[%d][%s]: add to %s", t, s->id, t->is_client ? "cli" : "svr", stream_list_id_string(id)); } diff --git a/src/core/ext/transport/chttp2/transport/writing.cc b/src/core/ext/transport/chttp2/transport/writing.cc index 3d1db0aa144..f3cb390dc7a 100644 --- a/src/core/ext/transport/chttp2/transport/writing.cc +++ b/src/core/ext/transport/chttp2/transport/writing.cc @@ -25,6 +25,7 @@ #include +#include "src/core/lib/compression/stream_compression.h" #include "src/core/lib/debug/stats.h" #include "src/core/lib/profiling/timers.h" #include "src/core/lib/slice/slice_internal.h" @@ -52,7 +53,8 @@ static void maybe_initiate_ping(grpc_chttp2_transport* t) { } if (!grpc_closure_list_empty(pq->lists[GRPC_CHTTP2_PCL_INFLIGHT])) { /* ping already in-flight: wait */ - if (grpc_http_trace.enabled() || grpc_bdp_estimator_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace) || + GRPC_TRACE_FLAG_ENABLED(grpc_bdp_estimator_trace)) { gpr_log(GPR_INFO, "%s: Ping delayed [%p]: already pinging", t->is_client ? "CLIENT" : "SERVER", t->peer_string); } @@ -61,7 +63,8 @@ static void maybe_initiate_ping(grpc_chttp2_transport* t) { if (t->ping_state.pings_before_data_required == 0 && t->ping_policy.max_pings_without_data != 0) { /* need to receive something of substance before sending a ping again */ - if (grpc_http_trace.enabled() || grpc_bdp_estimator_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace) || + GRPC_TRACE_FLAG_ENABLED(grpc_bdp_estimator_trace)) { gpr_log(GPR_INFO, "%s: Ping delayed [%p]: too many recent pings: %d/%d", t->is_client ? "CLIENT" : "SERVER", t->peer_string, t->ping_state.pings_before_data_required, @@ -81,7 +84,8 @@ static void maybe_initiate_ping(grpc_chttp2_transport* t) { if (next_allowed_ping > now) { /* not enough elapsed time between successive pings */ - if (grpc_http_trace.enabled() || grpc_bdp_estimator_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace) || + GRPC_TRACE_FLAG_ENABLED(grpc_bdp_estimator_trace)) { gpr_log(GPR_INFO, "%s: Ping delayed [%p]: not enough time elapsed since last ping. " " Last ping %f: Next ping %f: Now %f", @@ -107,7 +111,8 @@ static void maybe_initiate_ping(grpc_chttp2_transport* t) { grpc_chttp2_ping_create(false, pq->inflight_id)); GRPC_STATS_INC_HTTP2_PINGS_SENT(); t->ping_state.last_ping_sent_time = now; - if (grpc_http_trace.enabled() || grpc_bdp_estimator_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace) || + GRPC_TRACE_FLAG_ENABLED(grpc_bdp_estimator_trace)) { gpr_log(GPR_INFO, "%s: Ping sent [%s]: %d/%d", t->is_client ? "CLIENT" : "SERVER", t->peer_string, t->ping_state.pings_before_data_required, @@ -140,7 +145,7 @@ static bool update_list(grpc_chttp2_transport* t, grpc_chttp2_stream* s, static void report_stall(grpc_chttp2_transport* t, grpc_chttp2_stream* s, const char* staller) { - if (grpc_flowctl_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_flowctl_trace)) { gpr_log( GPR_DEBUG, "%s:%p stream %d moved to stalled list by %s. This is FULLY expected " @@ -150,7 +155,11 @@ static void report_stall(grpc_chttp2_transport* t, grpc_chttp2_stream* s, ":flowed=%" PRId64 ":peer_initwin=%d:t_win=%" PRId64 ":s_win=%d:s_delta=%" PRId64 "]", t->peer_string, t, s->id, staller, s->flow_controlled_buffer.length, - s->compressed_data_buffer.length, s->flow_controlled_bytes_flowed, + s->stream_compression_method == + GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS + ? 0 + : s->compressed_data_buffer.length, + s->flow_controlled_bytes_flowed, t->settings[GRPC_ACKED_SETTINGS] [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE], t->flow_control->remote_window(), @@ -325,7 +334,23 @@ class DataSendContext { bool AnyOutgoing() const { return max_outgoing() > 0; } + void FlushUncompressedBytes() { + uint32_t send_bytes = static_cast GPR_MIN( + max_outgoing(), s_->flow_controlled_buffer.length); + is_last_frame_ = send_bytes == s_->flow_controlled_buffer.length && + s_->fetching_send_message == nullptr && + s_->send_trailing_metadata != nullptr && + grpc_metadata_batch_is_empty(s_->send_trailing_metadata); + grpc_chttp2_encode_data(s_->id, &s_->flow_controlled_buffer, send_bytes, + is_last_frame_, &s_->stats.outgoing, &t_->outbuf); + s_->flow_control->SentData(send_bytes); + s_->sending_bytes += send_bytes; + } + void FlushCompressedBytes() { + GPR_DEBUG_ASSERT(s_->stream_compression_method != + GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS); + uint32_t send_bytes = static_cast GPR_MIN( max_outgoing(), s_->compressed_data_buffer.length); bool is_last_data_frame = @@ -360,6 +385,9 @@ class DataSendContext { } void CompressMoreBytes() { + GPR_DEBUG_ASSERT(s_->stream_compression_method != + GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS); + if (s_->stream_compression_ctx == nullptr) { s_->stream_compression_ctx = grpc_stream_compression_context_create(s_->stream_compression_method); @@ -417,7 +445,7 @@ class StreamWriteContext { // https://github.com/grpc/proposal/blob/master/A6-client-retries.md#when-retries-are-valid if (!t_->is_client && s_->fetching_send_message == nullptr && s_->flow_controlled_buffer.length == 0 && - s_->compressed_data_buffer.length == 0 && + compressed_data_buffer_len() == 0 && s_->send_trailing_metadata != nullptr && is_default_initial_metadata(s_->send_initial_metadata)) { ConvertInitialMetadataToTrailingMetadata(); @@ -446,6 +474,13 @@ class StreamWriteContext { "send_initial_metadata_finished"); } + bool compressed_data_buffer_len() { + return s_->stream_compression_method == + GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS + ? 0 + : s_->compressed_data_buffer.length; + } + void FlushWindowUpdates() { /* send any window updates */ const uint32_t stream_announce = s_->flow_control->MaybeSendUpdate(); @@ -462,7 +497,7 @@ class StreamWriteContext { if (!s_->sent_initial_metadata) return; if (s_->flow_controlled_buffer.length == 0 && - s_->compressed_data_buffer.length == 0) { + compressed_data_buffer_len() == 0) { return; // early out: nothing to do } @@ -479,13 +514,21 @@ class StreamWriteContext { return; // early out: nothing to do } - while ((s_->flow_controlled_buffer.length > 0 || - s_->compressed_data_buffer.length > 0) && - data_send_context.max_outgoing() > 0) { - if (s_->compressed_data_buffer.length > 0) { - data_send_context.FlushCompressedBytes(); - } else { - data_send_context.CompressMoreBytes(); + if (s_->stream_compression_method == + GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS) { + while (s_->flow_controlled_buffer.length > 0 && + data_send_context.max_outgoing() > 0) { + data_send_context.FlushUncompressedBytes(); + } + } else { + while ((s_->flow_controlled_buffer.length > 0 || + s_->compressed_data_buffer.length > 0) && + data_send_context.max_outgoing() > 0) { + if (s_->compressed_data_buffer.length > 0) { + data_send_context.FlushCompressedBytes(); + } else { + data_send_context.CompressMoreBytes(); + } } } write_context_->ResetPingClock(); @@ -495,7 +538,7 @@ class StreamWriteContext { data_send_context.CallCallbacks(); stream_became_writable_ = true; if (s_->flow_controlled_buffer.length > 0 || - s_->compressed_data_buffer.length > 0) { + compressed_data_buffer_len() > 0) { GRPC_CHTTP2_STREAM_REF(s_, "chttp2_writing:fork"); grpc_chttp2_list_add_writable_stream(t_, s_); } @@ -508,7 +551,7 @@ class StreamWriteContext { if (s_->send_trailing_metadata == nullptr) return; if (s_->fetching_send_message != nullptr) return; if (s_->flow_controlled_buffer.length != 0) return; - if (s_->compressed_data_buffer.length != 0) return; + if (compressed_data_buffer_len() != 0) return; GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_INFO, "sending trailing_metadata")); if (grpc_metadata_batch_is_empty(s_->send_trailing_metadata)) { diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.cc b/src/core/ext/transport/cronet/transport/cronet_transport.cc index 76a32dc4049..413de807638 100644 --- a/src/core/ext/transport/cronet/transport/cronet_transport.cc +++ b/src/core/ext/transport/cronet/transport/cronet_transport.cc @@ -29,6 +29,7 @@ #include "src/core/ext/transport/chttp2/transport/bin_encoder.h" #include "src/core/ext/transport/chttp2/transport/incoming_metadata.h" #include "src/core/ext/transport/cronet/transport/cronet_transport.h" +#include "src/core/lib/debug/trace.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gprpp/manual_constructor.h" @@ -45,14 +46,12 @@ #define GRPC_HEADER_SIZE_IN_BYTES 5 #define GRPC_FLUSH_READ_SIZE 4096 -#define CRONET_LOG(...) \ - do { \ - if (grpc_cronet_trace) gpr_log(__VA_ARGS__); \ +grpc_core::TraceFlag grpc_cronet_trace(false, "cronet"); +#define CRONET_LOG(...) \ + do { \ + if (grpc_cronet_trace.enabled()) gpr_log(__VA_ARGS__); \ } while (0) -/* TODO (makdharma): Hook up into the wider tracing mechanism */ -int grpc_cronet_trace = 0; - enum e_op_result { ACTION_TAKEN_WITH_CALLBACK, ACTION_TAKEN_NO_CALLBACK, @@ -111,7 +110,7 @@ typedef struct grpc_cronet_transport grpc_cronet_transport; /* TODO (makdharma): reorder structure for memory efficiency per http://www.catb.org/esr/structure-packing/#_structure_reordering: */ struct read_state { - read_state(gpr_arena* arena) + read_state(grpc_core::Arena* arena) : trailing_metadata(arena), initial_metadata(arena) { grpc_slice_buffer_init(&read_slice_buffer); } @@ -145,7 +144,7 @@ struct write_state { /* track state of one stream op */ struct op_state { - op_state(gpr_arena* arena) : rs(arena) {} + op_state(grpc_core::Arena* arena) : rs(arena) {} bool state_op_done[OP_NUM_OPS] = {}; bool state_callback_received[OP_NUM_OPS] = {}; @@ -187,10 +186,10 @@ struct op_storage { struct stream_obj { stream_obj(grpc_transport* gt, grpc_stream* gs, - grpc_stream_refcount* refcount, gpr_arena* arena); + grpc_stream_refcount* refcount, grpc_core::Arena* arena); ~stream_obj(); - gpr_arena* arena; + grpc_core::Arena* arena; struct op_and_state* oas = nullptr; grpc_transport_stream_op_batch* curr_op = nullptr; grpc_cronet_transport* curr_ct; @@ -754,15 +753,16 @@ static void convert_metadata_to_cronet_headers( } else { value = grpc_slice_to_c_string(GRPC_MDVALUE(mdelem)); } - if (grpc_slice_eq(GRPC_MDKEY(mdelem), GRPC_MDSTR_SCHEME) || - grpc_slice_eq(GRPC_MDKEY(mdelem), GRPC_MDSTR_AUTHORITY)) { + if (grpc_slice_eq_static_interned(GRPC_MDKEY(mdelem), GRPC_MDSTR_SCHEME) || + grpc_slice_eq_static_interned(GRPC_MDKEY(mdelem), + GRPC_MDSTR_AUTHORITY)) { /* Cronet populates these fields on its own */ gpr_free(key); gpr_free(value); continue; } - if (grpc_slice_eq(GRPC_MDKEY(mdelem), GRPC_MDSTR_METHOD)) { - if (grpc_slice_eq(GRPC_MDVALUE(mdelem), GRPC_MDSTR_PUT)) { + if (grpc_slice_eq_static_interned(GRPC_MDKEY(mdelem), GRPC_MDSTR_METHOD)) { + if (grpc_slice_eq_static_interned(GRPC_MDVALUE(mdelem), GRPC_MDSTR_PUT)) { *method = "PUT"; } else { /* POST method in default*/ @@ -772,7 +772,7 @@ static void convert_metadata_to_cronet_headers( gpr_free(value); continue; } - if (grpc_slice_eq(GRPC_MDKEY(mdelem), GRPC_MDSTR_PATH)) { + if (grpc_slice_eq_static_interned(GRPC_MDKEY(mdelem), GRPC_MDSTR_PATH)) { /* Create URL by appending :path value to the hostname */ gpr_asprintf(pp_url, "https://%s%s", host, value); gpr_free(key); @@ -804,7 +804,8 @@ static void parse_grpc_header(const uint8_t* data, int* length, static bool header_has_authority(grpc_linked_mdelem* head) { while (head != nullptr) { - if (grpc_slice_eq(GRPC_MDKEY(head->md), GRPC_MDSTR_AUTHORITY)) { + if (grpc_slice_eq_static_interned(GRPC_MDKEY(head->md), + GRPC_MDSTR_AUTHORITY)) { return true; } head = head->next; @@ -1369,7 +1370,8 @@ static enum e_op_result execute_stream_op(struct op_and_state* oas) { */ inline stream_obj::stream_obj(grpc_transport* gt, grpc_stream* gs, - grpc_stream_refcount* refcount, gpr_arena* arena) + grpc_stream_refcount* refcount, + grpc_core::Arena* arena) : arena(arena), curr_ct(reinterpret_cast(gt)), curr_gs(gs), @@ -1388,7 +1390,7 @@ inline stream_obj::~stream_obj() { static int init_stream(grpc_transport* gt, grpc_stream* gs, grpc_stream_refcount* refcount, const void* server_data, - gpr_arena* arena) { + grpc_core::Arena* arena) { new (gs) stream_obj(gt, gs, refcount, arena); return 0; } diff --git a/src/core/ext/transport/inproc/inproc_transport.cc b/src/core/ext/transport/inproc/inproc_transport.cc index 7ded133bebf..8da89851a69 100644 --- a/src/core/ext/transport/inproc/inproc_transport.cc +++ b/src/core/ext/transport/inproc/inproc_transport.cc @@ -35,9 +35,11 @@ #include "src/core/lib/transport/error_utils.h" #include "src/core/lib/transport/transport_impl.h" -#define INPROC_LOG(...) \ - do { \ - if (grpc_inproc_trace.enabled()) gpr_log(__VA_ARGS__); \ +#define INPROC_LOG(...) \ + do { \ + if (GRPC_TRACE_FLAG_ENABLED(grpc_inproc_trace)) { \ + gpr_log(__VA_ARGS__); \ + } \ } while (0) namespace { @@ -120,7 +122,7 @@ struct inproc_transport { struct inproc_stream { inproc_stream(inproc_transport* t, grpc_stream_refcount* refcount, - const void* server_data, gpr_arena* arena) + const void* server_data, grpc_core::Arena* arena) : t(t), refs(refcount), arena(arena) { // Ref this stream right now for ctor and list. ref("inproc_init_stream:init"); @@ -250,7 +252,7 @@ struct inproc_stream { grpc_stream_refcount* refs; grpc_closure* closure_at_destroy = nullptr; - gpr_arena* arena; + grpc_core::Arena* arena; grpc_transport_stream_op_batch* send_message_op = nullptr; grpc_transport_stream_op_batch* send_trailing_md_op = nullptr; @@ -296,7 +298,7 @@ grpc_error* fill_in_metadata(inproc_stream* s, const grpc_metadata_batch* metadata, uint32_t flags, grpc_metadata_batch* out_md, uint32_t* outflags, bool* markfilled) { - if (grpc_inproc_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_inproc_trace)) { log_metadata(metadata, s->t->is_client, outflags != nullptr); } @@ -309,8 +311,8 @@ grpc_error* fill_in_metadata(inproc_stream* s, grpc_error* error = GRPC_ERROR_NONE; for (grpc_linked_mdelem* elem = metadata->list.head; (elem != nullptr) && (error == GRPC_ERROR_NONE); elem = elem->next) { - grpc_linked_mdelem* nelem = static_cast( - gpr_arena_alloc(s->arena, sizeof(*nelem))); + grpc_linked_mdelem* nelem = + static_cast(s->arena->Alloc(sizeof(*nelem))); nelem->md = grpc_mdelem_from_slices(grpc_slice_intern(GRPC_MDKEY(elem->md)), grpc_slice_intern(GRPC_MDVALUE(elem->md))); @@ -322,7 +324,7 @@ grpc_error* fill_in_metadata(inproc_stream* s, int init_stream(grpc_transport* gt, grpc_stream* gs, grpc_stream_refcount* refcount, const void* server_data, - gpr_arena* arena) { + grpc_core::Arena* arena) { INPROC_LOG(GPR_INFO, "init_stream %p %p %p", gt, gs, server_data); inproc_transport* t = reinterpret_cast(gt); new (gs) inproc_stream(t, refcount, server_data, arena); @@ -436,13 +438,13 @@ void fail_helper_locked(inproc_stream* s, grpc_error* error) { // since it expects that as well as no error yet grpc_metadata_batch fake_md; grpc_metadata_batch_init(&fake_md); - grpc_linked_mdelem* path_md = static_cast( - gpr_arena_alloc(s->arena, sizeof(*path_md))); + grpc_linked_mdelem* path_md = + static_cast(s->arena->Alloc(sizeof(*path_md))); path_md->md = grpc_mdelem_from_slices(g_fake_path_key, g_fake_path_value); GPR_ASSERT(grpc_metadata_batch_link_tail(&fake_md, path_md) == GRPC_ERROR_NONE); - grpc_linked_mdelem* auth_md = static_cast( - gpr_arena_alloc(s->arena, sizeof(*auth_md))); + grpc_linked_mdelem* auth_md = + static_cast(s->arena->Alloc(sizeof(*auth_md))); auth_md->md = grpc_mdelem_from_slices(g_fake_auth_key, g_fake_auth_value); GPR_ASSERT(grpc_metadata_batch_link_tail(&fake_md, auth_md) == GRPC_ERROR_NONE); @@ -907,7 +909,7 @@ void perform_stream_op(grpc_transport* gt, grpc_stream* gs, gpr_mu* mu = &s->t->mu->mu; // save aside in case s gets closed gpr_mu_lock(mu); - if (grpc_inproc_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_inproc_trace)) { if (op->send_initial_metadata) { log_metadata(op->payload->send_initial_metadata.send_initial_metadata, s->t->is_client, true); diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h index 580e1e55100..a7c28d059f3 100644 --- a/src/core/lib/channel/channel_stack.h +++ b/src/core/lib/channel/channel_stack.h @@ -42,7 +42,7 @@ #include #include "src/core/lib/debug/trace.h" -#include "src/core/lib/gpr/arena.h" +#include "src/core/lib/gprpp/arena.h" #include "src/core/lib/iomgr/call_combiner.h" #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/transport/transport.h" @@ -69,8 +69,8 @@ typedef struct { const grpc_slice& path; gpr_timespec start_time; grpc_millis deadline; - gpr_arena* arena; - grpc_call_combiner* call_combiner; + grpc_core::Arena* arena; + grpc_core::CallCombiner* call_combiner; } grpc_call_element_args; typedef struct { @@ -274,7 +274,11 @@ void grpc_call_log_op(const char* file, int line, gpr_log_severity severity, extern grpc_core::TraceFlag grpc_trace_channel; -#define GRPC_CALL_LOG_OP(sev, elem, op) \ - if (grpc_trace_channel.enabled()) grpc_call_log_op(sev, elem, op) +#define GRPC_CALL_LOG_OP(sev, elem, op) \ + do { \ + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_channel)) { \ + grpc_call_log_op(sev, elem, op); \ + } \ + } while (0) #endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_STACK_H */ diff --git a/src/core/lib/channel/connected_channel.cc b/src/core/lib/channel/connected_channel.cc index e2ea334dedf..bd30c3663a2 100644 --- a/src/core/lib/channel/connected_channel.cc +++ b/src/core/lib/channel/connected_channel.cc @@ -41,12 +41,12 @@ typedef struct connected_channel_channel_data { typedef struct { grpc_closure closure; grpc_closure* original_closure; - grpc_call_combiner* call_combiner; + grpc_core::CallCombiner* call_combiner; const char* reason; } callback_state; typedef struct connected_channel_call_data { - grpc_call_combiner* call_combiner; + grpc_core::CallCombiner* call_combiner; // Closures used for returning results on the call combiner. callback_state on_complete[6]; // Max number of pending batches. callback_state recv_initial_metadata_ready; diff --git a/src/core/lib/channel/context.h b/src/core/lib/channel/context.h index 81b84f1ca05..e8a024547f6 100644 --- a/src/core/lib/channel/context.h +++ b/src/core/lib/channel/context.h @@ -35,6 +35,9 @@ typedef enum { /// Reserved for traffic_class_context. GRPC_CONTEXT_TRAFFIC, + /// Holds a pointer to ServiceConfig::CallData associated with this call. + GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA, + GRPC_CONTEXT_COUNT } grpc_context_index; diff --git a/src/core/lib/channel/handshaker.cc b/src/core/lib/channel/handshaker.cc index 6bb05cee24e..ad0bc875fd2 100644 --- a/src/core/lib/channel/handshaker.cc +++ b/src/core/lib/channel/handshaker.cc @@ -20,6 +20,7 @@ #include +#include #include #include #include @@ -94,7 +95,7 @@ void HandshakeManager::ShutdownAllPending(grpc_error* why) { } void HandshakeManager::Add(RefCountedPtr handshaker) { - if (grpc_handshaker_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_handshaker_trace)) { gpr_log( GPR_INFO, "handshake_manager %p: adding handshaker %s [%p] at index %" PRIuPTR, @@ -125,7 +126,7 @@ void HandshakeManager::Shutdown(grpc_error* why) { // on_handshake_done callback. // Returns true if we've scheduled the on_handshake_done callback. bool HandshakeManager::CallNextHandshakerLocked(grpc_error* error) { - if (grpc_handshaker_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_handshaker_trace)) { char* args_str = HandshakerArgsString(&args_); gpr_log(GPR_INFO, "handshake_manager %p: error=%s shutdown=%d index=%" PRIuPTR @@ -159,7 +160,7 @@ bool HandshakeManager::CallNextHandshakerLocked(grpc_error* error) { args_.read_buffer = nullptr; } } - if (grpc_handshaker_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_handshaker_trace)) { gpr_log(GPR_INFO, "handshake_manager %p: handshaking complete -- scheduling " "on_handshake_done with error=%s", @@ -172,7 +173,7 @@ bool HandshakeManager::CallNextHandshakerLocked(grpc_error* error) { is_shutdown_ = true; } else { auto handshaker = handshakers_[index_]; - if (grpc_handshaker_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_handshaker_trace)) { gpr_log( GPR_INFO, "handshake_manager %p: calling handshaker %s [%p] at index %" PRIuPTR, @@ -226,6 +227,11 @@ void HandshakeManager::DoHandshake(grpc_endpoint* endpoint, args_.read_buffer = static_cast(gpr_malloc(sizeof(*args_.read_buffer))); grpc_slice_buffer_init(args_.read_buffer); + if (acceptor != nullptr && acceptor->external_connection && + acceptor->pending_data != nullptr) { + grpc_slice_buffer_swap(args_.read_buffer, + &(acceptor->pending_data->data.raw.slice_buffer)); + } // Initialize state needed for calling handshakers. acceptor_ = acceptor; GRPC_CLOSURE_INIT(&call_next_handshaker_, diff --git a/src/core/lib/compression/compression.cc b/src/core/lib/compression/compression.cc index 9139fa04ee5..a3a069d9266 100644 --- a/src/core/lib/compression/compression.cc +++ b/src/core/lib/compression/compression.cc @@ -26,6 +26,7 @@ #include "src/core/lib/compression/algorithm_metadata.h" #include "src/core/lib/compression/compression_internal.h" #include "src/core/lib/gpr/useful.h" +#include "src/core/lib/slice/slice_utils.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/transport/static_metadata.h" @@ -42,16 +43,17 @@ int grpc_compression_algorithm_is_stream(grpc_compression_algorithm algorithm) { int grpc_compression_algorithm_parse(grpc_slice name, grpc_compression_algorithm* algorithm) { - if (grpc_slice_eq(name, GRPC_MDSTR_IDENTITY)) { + if (grpc_slice_eq_static_interned(name, GRPC_MDSTR_IDENTITY)) { *algorithm = GRPC_COMPRESS_NONE; return 1; - } else if (grpc_slice_eq(name, GRPC_MDSTR_DEFLATE)) { + } else if (grpc_slice_eq_static_interned(name, GRPC_MDSTR_DEFLATE)) { *algorithm = GRPC_COMPRESS_DEFLATE; return 1; - } else if (grpc_slice_eq(name, GRPC_MDSTR_GZIP)) { + } else if (grpc_slice_eq_static_interned(name, GRPC_MDSTR_GZIP)) { *algorithm = GRPC_COMPRESS_GZIP; return 1; - } else if (grpc_slice_eq(name, GRPC_MDSTR_STREAM_SLASH_GZIP)) { + } else if (grpc_slice_eq_static_interned(name, + GRPC_MDSTR_STREAM_SLASH_GZIP)) { *algorithm = GRPC_COMPRESS_STREAM_GZIP; return 1; } else { @@ -148,10 +150,13 @@ grpc_slice grpc_compression_algorithm_slice( grpc_compression_algorithm grpc_compression_algorithm_from_slice( const grpc_slice& str) { - if (grpc_slice_eq(str, GRPC_MDSTR_IDENTITY)) return GRPC_COMPRESS_NONE; - if (grpc_slice_eq(str, GRPC_MDSTR_DEFLATE)) return GRPC_COMPRESS_DEFLATE; - if (grpc_slice_eq(str, GRPC_MDSTR_GZIP)) return GRPC_COMPRESS_GZIP; - if (grpc_slice_eq(str, GRPC_MDSTR_STREAM_SLASH_GZIP)) + if (grpc_slice_eq_static_interned(str, GRPC_MDSTR_IDENTITY)) + return GRPC_COMPRESS_NONE; + if (grpc_slice_eq_static_interned(str, GRPC_MDSTR_DEFLATE)) + return GRPC_COMPRESS_DEFLATE; + if (grpc_slice_eq_static_interned(str, GRPC_MDSTR_GZIP)) + return GRPC_COMPRESS_GZIP; + if (grpc_slice_eq_static_interned(str, GRPC_MDSTR_STREAM_SLASH_GZIP)) return GRPC_COMPRESS_STREAM_GZIP; return GRPC_COMPRESS_ALGORITHMS_COUNT; } diff --git a/src/core/lib/compression/compression_internal.cc b/src/core/lib/compression/compression_internal.cc index 65a36de4290..e0d73ef6d83 100644 --- a/src/core/lib/compression/compression_internal.cc +++ b/src/core/lib/compression/compression_internal.cc @@ -26,6 +26,7 @@ #include "src/core/lib/compression/algorithm_metadata.h" #include "src/core/lib/compression/compression_internal.h" #include "src/core/lib/gpr/useful.h" +#include "src/core/lib/slice/slice_utils.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/transport/static_metadata.h" @@ -33,18 +34,21 @@ grpc_message_compression_algorithm grpc_message_compression_algorithm_from_slice(const grpc_slice& str) { - if (grpc_slice_eq(str, GRPC_MDSTR_IDENTITY)) + if (grpc_slice_eq_static_interned(str, GRPC_MDSTR_IDENTITY)) return GRPC_MESSAGE_COMPRESS_NONE; - if (grpc_slice_eq(str, GRPC_MDSTR_DEFLATE)) + if (grpc_slice_eq_static_interned(str, GRPC_MDSTR_DEFLATE)) return GRPC_MESSAGE_COMPRESS_DEFLATE; - if (grpc_slice_eq(str, GRPC_MDSTR_GZIP)) return GRPC_MESSAGE_COMPRESS_GZIP; + if (grpc_slice_eq_static_interned(str, GRPC_MDSTR_GZIP)) + return GRPC_MESSAGE_COMPRESS_GZIP; return GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT; } grpc_stream_compression_algorithm grpc_stream_compression_algorithm_from_slice( const grpc_slice& str) { - if (grpc_slice_eq(str, GRPC_MDSTR_IDENTITY)) return GRPC_STREAM_COMPRESS_NONE; - if (grpc_slice_eq(str, GRPC_MDSTR_GZIP)) return GRPC_STREAM_COMPRESS_GZIP; + if (grpc_slice_eq_static_interned(str, GRPC_MDSTR_IDENTITY)) + return GRPC_STREAM_COMPRESS_NONE; + if (grpc_slice_eq_static_interned(str, GRPC_MDSTR_GZIP)) + return GRPC_STREAM_COMPRESS_GZIP; return GRPC_STREAM_COMPRESS_ALGORITHMS_COUNT; } @@ -244,13 +248,13 @@ grpc_message_compression_algorithm grpc_message_compression_algorithm_for_level( int grpc_message_compression_algorithm_parse( grpc_slice value, grpc_message_compression_algorithm* algorithm) { - if (grpc_slice_eq(value, GRPC_MDSTR_IDENTITY)) { + if (grpc_slice_eq_static_interned(value, GRPC_MDSTR_IDENTITY)) { *algorithm = GRPC_MESSAGE_COMPRESS_NONE; return 1; - } else if (grpc_slice_eq(value, GRPC_MDSTR_DEFLATE)) { + } else if (grpc_slice_eq_static_interned(value, GRPC_MDSTR_DEFLATE)) { *algorithm = GRPC_MESSAGE_COMPRESS_DEFLATE; return 1; - } else if (grpc_slice_eq(value, GRPC_MDSTR_GZIP)) { + } else if (grpc_slice_eq_static_interned(value, GRPC_MDSTR_GZIP)) { *algorithm = GRPC_MESSAGE_COMPRESS_GZIP; return 1; } else { @@ -263,10 +267,10 @@ int grpc_message_compression_algorithm_parse( int grpc_stream_compression_algorithm_parse( grpc_slice value, grpc_stream_compression_algorithm* algorithm) { - if (grpc_slice_eq(value, GRPC_MDSTR_IDENTITY)) { + if (grpc_slice_eq_static_interned(value, GRPC_MDSTR_IDENTITY)) { *algorithm = GRPC_STREAM_COMPRESS_NONE; return 1; - } else if (grpc_slice_eq(value, GRPC_MDSTR_GZIP)) { + } else if (grpc_slice_eq_static_interned(value, GRPC_MDSTR_GZIP)) { *algorithm = GRPC_STREAM_COMPRESS_GZIP; return 1; } else { diff --git a/src/core/lib/compression/compression_internal.h b/src/core/lib/compression/compression_internal.h index da007368b01..73947a2c34d 100644 --- a/src/core/lib/compression/compression_internal.h +++ b/src/core/lib/compression/compression_internal.h @@ -35,7 +35,7 @@ typedef enum { GRPC_MESSAGE_COMPRESS_ALGORITHMS_COUNT } grpc_message_compression_algorithm; -/** Stream compresssion algorithms supported by gRPC */ +/** Stream compression algorithms supported by gRPC */ typedef enum { GRPC_STREAM_COMPRESS_NONE = 0, GRPC_STREAM_COMPRESS_GZIP, diff --git a/src/core/lib/compression/stream_compression.cc b/src/core/lib/compression/stream_compression.cc index 46cb3daf4cc..e0857988643 100644 --- a/src/core/lib/compression/stream_compression.cc +++ b/src/core/lib/compression/stream_compression.cc @@ -22,6 +22,7 @@ #include "src/core/lib/compression/stream_compression.h" #include "src/core/lib/compression/stream_compression_gzip.h" +#include "src/core/lib/slice/slice_utils.h" extern const grpc_stream_compression_vtable grpc_stream_compression_identity_vtable; @@ -65,11 +66,11 @@ void grpc_stream_compression_context_destroy( int grpc_stream_compression_method_parse( grpc_slice value, bool is_compress, grpc_stream_compression_method* method) { - if (grpc_slice_eq(value, GRPC_MDSTR_IDENTITY)) { + if (grpc_slice_eq_static_interned(value, GRPC_MDSTR_IDENTITY)) { *method = is_compress ? GRPC_STREAM_COMPRESSION_IDENTITY_COMPRESS : GRPC_STREAM_COMPRESSION_IDENTITY_DECOMPRESS; return 1; - } else if (grpc_slice_eq(value, GRPC_MDSTR_GZIP)) { + } else if (grpc_slice_eq_static_interned(value, GRPC_MDSTR_GZIP)) { *method = is_compress ? GRPC_STREAM_COMPRESSION_GZIP_COMPRESS : GRPC_STREAM_COMPRESSION_GZIP_DECOMPRESS; return 1; diff --git a/src/core/lib/compression/stream_compression.h b/src/core/lib/compression/stream_compression.h index c80f2f8692b..7328c3ec0f2 100644 --- a/src/core/lib/compression/stream_compression.h +++ b/src/core/lib/compression/stream_compression.h @@ -68,7 +68,7 @@ struct grpc_stream_compression_vtable { * at the end of compression. Emits at most \a max_output_size compressed bytes * into \a out. If all the bytes in input buffer \a in are depleted and \a flush * is not GRPC_STREAM_COMPRESSION_FLUSH_NONE, the corresponding flush method is - * executed. The total number of bytes emitted is outputed in \a output_size. + * executed. The total number of bytes emitted is outputted in \a output_size. * * A SYNC flush indicates that the entire messages in \a in can be decompressed * from \a out. A FINISH flush implies a SYNC flush, and that any further @@ -85,7 +85,7 @@ bool grpc_stream_compress(grpc_stream_compression_context* ctx, * Decompress bytes provided in \a in with a given context. Emits at most \a * max_output_size decompressed bytes into \a out. If decompression process * reached the end of a gzip stream, \a end_of_context is set to true; otherwise - * it is set to false. The total number of bytes emitted is outputed in \a + * it is set to false. The total number of bytes emitted is outputted in \a * output_size. */ bool grpc_stream_decompress(grpc_stream_compression_context* ctx, diff --git a/src/core/lib/compression/stream_compression_gzip.cc b/src/core/lib/compression/stream_compression_gzip.cc index bffdb1fd17d..452b22b7628 100644 --- a/src/core/lib/compression/stream_compression_gzip.cc +++ b/src/core/lib/compression/stream_compression_gzip.cc @@ -53,25 +53,25 @@ static bool gzip_flate(grpc_stream_compression_context_gzip* ctx, ctx->zs.avail_out = static_cast(slice_size); ctx->zs.next_out = GRPC_SLICE_START_PTR(slice_out); while (ctx->zs.avail_out > 0 && in->length > 0 && !eoc) { - grpc_slice slice = grpc_slice_buffer_take_first(in); - ctx->zs.avail_in = static_cast GRPC_SLICE_LENGTH(slice); - ctx->zs.next_in = GRPC_SLICE_START_PTR(slice); + grpc_slice* slice = grpc_slice_buffer_peek_first(in); + ctx->zs.avail_in = static_cast GRPC_SLICE_LENGTH(*slice); + ctx->zs.next_in = GRPC_SLICE_START_PTR(*slice); r = ctx->flate(&ctx->zs, Z_NO_FLUSH); if (r < 0 && r != Z_BUF_ERROR) { gpr_log(GPR_ERROR, "zlib error (%d)", r); grpc_slice_unref_internal(slice_out); - grpc_slice_unref_internal(slice); + grpc_slice_buffer_remove_first(in); return false; } else if (r == Z_STREAM_END && ctx->flate == inflate) { eoc = true; } if (ctx->zs.avail_in > 0) { - grpc_slice_buffer_undo_take_first( - in, - grpc_slice_sub(slice, GRPC_SLICE_LENGTH(slice) - ctx->zs.avail_in, - GRPC_SLICE_LENGTH(slice))); + grpc_slice_buffer_sub_first( + in, GRPC_SLICE_LENGTH(*slice) - ctx->zs.avail_in, + GRPC_SLICE_LENGTH(*slice)); + } else { + grpc_slice_buffer_remove_first(in); } - grpc_slice_unref_internal(slice); } if (flush != 0 && ctx->zs.avail_out > 0 && !eoc) { GPR_ASSERT(in->length == 0); diff --git a/src/core/lib/debug/trace.cc b/src/core/lib/debug/trace.cc index cafdb15c699..84c0a3805d3 100644 --- a/src/core/lib/debug/trace.cc +++ b/src/core/lib/debug/trace.cc @@ -26,7 +26,11 @@ #include #include #include -#include "src/core/lib/gpr/env.h" + +GPR_GLOBAL_CONFIG_DEFINE_STRING( + grpc_trace, "", + "A comma separated list of tracers that provide additional insight into " + "how gRPC C core is processing requests via debug logs."); int grpc_tracer_set_enabled(const char* name, int enabled); @@ -133,12 +137,14 @@ static void parse(const char* s) { gpr_free(strings); } -void grpc_tracer_init(const char* env_var) { - char* e = gpr_getenv(env_var); - if (e != nullptr) { - parse(e); - gpr_free(e); - } +void grpc_tracer_init(const char* env_var_name) { + (void)env_var_name; // suppress unused variable error + grpc_tracer_init(); +} + +void grpc_tracer_init() { + grpc_core::UniquePtr value = GPR_GLOBAL_CONFIG_GET(grpc_trace); + parse(value.get()); } void grpc_tracer_shutdown(void) {} diff --git a/src/core/lib/debug/trace.h b/src/core/lib/debug/trace.h index 6108fb239bd..6a4a8031ec4 100644 --- a/src/core/lib/debug/trace.h +++ b/src/core/lib/debug/trace.h @@ -24,7 +24,15 @@ #include #include +#include "src/core/lib/gprpp/global_config.h" + +GPR_GLOBAL_CONFIG_DECLARE_STRING(grpc_trace); + +// TODO(veblush): Remove this deprecated function once codes depending on this +// function are updated in the internal repo. void grpc_tracer_init(const char* env_var_name); + +void grpc_tracer_init(); void grpc_tracer_shutdown(void); #if defined(__has_feature) @@ -65,6 +73,8 @@ class TraceFlag { // wrapped language (wr don't want to force recompilation to get tracing). // Internally, however, for performance reasons, we compile them out by // default, since internal build systems make recompiling trivial. +// +// Prefer GRPC_TRACE_FLAG_ENABLED() macro instead of using enabled() directly. #define GRPC_USE_TRACERS // tracers on by default in OSS #if defined(GRPC_USE_TRACERS) || !defined(NDEBUG) bool enabled() { @@ -99,6 +109,8 @@ class TraceFlag { #endif }; +#define GRPC_TRACE_FLAG_ENABLED(f) GPR_UNLIKELY((f).enabled()) + #ifndef NDEBUG typedef TraceFlag DebugOnlyTraceFlag; #else diff --git a/src/core/lib/gpr/arena.cc b/src/core/lib/gpr/arena.cc deleted file mode 100644 index ede5cc48050..00000000000 --- a/src/core/lib/gpr/arena.cc +++ /dev/null @@ -1,152 +0,0 @@ -/* - * - * Copyright 2017 gRPC authors. - * - * 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 - -#include "src/core/lib/gpr/arena.h" - -#include -#include - -#include -#include -#include -#include - -#include "src/core/lib/gpr/alloc.h" -#include "src/core/lib/gprpp/memory.h" - -static void* gpr_arena_malloc(size_t size) { - return gpr_malloc_aligned(size, GPR_MAX_ALIGNMENT); -} - -// Uncomment this to use a simple arena that simply allocates the -// requested amount of memory for each call to gpr_arena_alloc(). This -// effectively eliminates the efficiency gain of using an arena, but it -// may be useful for debugging purposes. -//#define SIMPLE_ARENA_FOR_DEBUGGING -#ifdef SIMPLE_ARENA_FOR_DEBUGGING - -struct gpr_arena { - gpr_arena() { gpr_mu_init(&mu); } - ~gpr_arena() { - gpr_mu_destroy(&mu); - for (size_t i = 0; i < num_ptrs; ++i) { - gpr_free_aligned(ptrs[i]); - } - gpr_free(ptrs); - } - - gpr_mu mu; - void** ptrs = nullptr; - size_t num_ptrs = 0; -}; - -gpr_arena* gpr_arena_create(size_t ignored_initial_size) { - return grpc_core::New(); -} - -size_t gpr_arena_destroy(gpr_arena* arena) { - grpc_core::Delete(arena); - return 1; // Value doesn't matter, since it won't be used. -} - -void* gpr_arena_alloc(gpr_arena* arena, size_t size) { - gpr_mu_lock(&arena->mu); - arena->ptrs = - (void**)gpr_realloc(arena->ptrs, sizeof(void*) * (arena->num_ptrs + 1)); - void* retval = arena->ptrs[arena->num_ptrs++] = gpr_arena_malloc(size); - gpr_mu_unlock(&arena->mu); - return retval; -} - -#else // SIMPLE_ARENA_FOR_DEBUGGING - -// TODO(roth): We currently assume that all callers need alignment of 16 -// bytes, which may be wrong in some cases. As part of converting the -// arena API to C++, we should consider replacing gpr_arena_alloc() with a -// template that takes the type of the value being allocated, which -// would allow us to use the alignment actually needed by the caller. - -typedef struct zone { - zone* next = nullptr; -} zone; - -struct gpr_arena { - gpr_arena(size_t initial_size) - : initial_zone_size(initial_size), last_zone(&initial_zone) { - gpr_mu_init(&arena_growth_mutex); - } - ~gpr_arena() { - gpr_mu_destroy(&arena_growth_mutex); - zone* z = initial_zone.next; - while (z) { - zone* next_z = z->next; - z->~zone(); - gpr_free_aligned(z); - z = next_z; - } - } - - // Keep track of the total used size. We use this in our call sizing - // historesis. - gpr_atm total_used = 0; - size_t initial_zone_size; - zone initial_zone; - zone* last_zone; - gpr_mu arena_growth_mutex; -}; - -gpr_arena* gpr_arena_create(size_t initial_size) { - initial_size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(initial_size); - return new (gpr_arena_malloc( - GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena)) + initial_size)) - gpr_arena(initial_size); -} - -size_t gpr_arena_destroy(gpr_arena* arena) { - const gpr_atm size = gpr_atm_no_barrier_load(&arena->total_used); - arena->~gpr_arena(); - gpr_free_aligned(arena); - return static_cast(size); -} - -void* gpr_arena_alloc(gpr_arena* arena, size_t size) { - size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(size); - size_t begin = gpr_atm_no_barrier_fetch_add(&arena->total_used, size); - if (begin + size <= arena->initial_zone_size) { - return reinterpret_cast(arena) + - GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena)) + begin; - } else { - // If the allocation isn't able to end in the initial zone, create a new - // zone for this allocation, and any unused space in the initial zone is - // wasted. This overflowing and wasting is uncommon because of our arena - // sizing historesis (that is, most calls should have a large enough initial - // zone and will not need to grow the arena). - gpr_mu_lock(&arena->arena_growth_mutex); - zone* z = new (gpr_arena_malloc( - GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone)) + size)) zone(); - arena->last_zone->next = z; - arena->last_zone = z; - gpr_mu_unlock(&arena->arena_growth_mutex); - return reinterpret_cast(z) + - GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone)); - } -} - -#endif // SIMPLE_ARENA_FOR_DEBUGGING diff --git a/src/core/lib/gpr/arena.h b/src/core/lib/gpr/arena.h index 6d2a073dd58..4d70695149c 100644 --- a/src/core/lib/gpr/arena.h +++ b/src/core/lib/gpr/arena.h @@ -21,21 +21,27 @@ // the arena as a whole is freed // Tracks the total memory allocated against it, so that future arenas can // pre-allocate the right amount of memory +// This transitional API is deprecated and will be removed soon in favour of +// src/core/lib/gprpp/arena.h . #ifndef GRPC_CORE_LIB_GPR_ARENA_H #define GRPC_CORE_LIB_GPR_ARENA_H #include -#include - -typedef struct gpr_arena gpr_arena; +#include "src/core/lib/gprpp/arena.h" +// TODO(arjunroy) : Remove deprecated gpr_arena API once all callers are gone. +typedef class grpc_core::Arena gpr_arena; // Create an arena, with \a initial_size bytes in the first allocated buffer -gpr_arena* gpr_arena_create(size_t initial_size); -// Allocate \a size bytes from the arena -void* gpr_arena_alloc(gpr_arena* arena, size_t size); +inline gpr_arena* gpr_arena_create(size_t initial_size) { + return grpc_core::Arena::Create(initial_size); +} // Destroy an arena, returning the total number of bytes allocated -size_t gpr_arena_destroy(gpr_arena* arena); +inline size_t gpr_arena_destroy(gpr_arena* arena) { return arena->Destroy(); } +// Allocate \a size bytes from the arena +inline void* gpr_arena_alloc(gpr_arena* arena, size_t size) { + return arena->Alloc(size); +} #endif /* GRPC_CORE_LIB_GPR_ARENA_H */ diff --git a/src/core/lib/gpr/env.h b/src/core/lib/gpr/env.h index aec8a3166b1..f5016c6fa06 100644 --- a/src/core/lib/gpr/env.h +++ b/src/core/lib/gpr/env.h @@ -26,7 +26,7 @@ /* Env utility functions */ /* Gets the environment variable value with the specified name. - Returns a newly allocated string. It is the responsability of the caller to + Returns a newly allocated string. It is the responsibility of the caller to gpr_free the return value if not NULL (which means that the environment variable exists). */ char* gpr_getenv(const char* name); @@ -34,10 +34,7 @@ char* gpr_getenv(const char* name); /* Sets the environment with the specified name to the specified value. */ void gpr_setenv(const char* name, const char* value); -/* This is a version of gpr_getenv that does not produce any output if it has to - use an insecure version of the function. It is ONLY to be used to solve the - problem in which we need to check an env variable to configure the verbosity - level of logging. So DO NOT USE THIS. */ -const char* gpr_getenv_silent(const char* name, char** dst); +/* Deletes the variable name from the environment. */ +void gpr_unsetenv(const char* name); #endif /* GRPC_CORE_LIB_GPR_ENV_H */ diff --git a/src/core/lib/gpr/env_linux.cc b/src/core/lib/gpr/env_linux.cc index fadc42f22f1..3a3aa541672 100644 --- a/src/core/lib/gpr/env_linux.cc +++ b/src/core/lib/gpr/env_linux.cc @@ -38,7 +38,7 @@ #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/useful.h" -const char* gpr_getenv_silent(const char* name, char** dst) { +static const char* gpr_getenv_silent(const char* name, char** dst) { const char* insecure_func_used = nullptr; char* result = nullptr; #if defined(GPR_BACKWARDS_COMPATIBILITY_MODE) @@ -79,4 +79,9 @@ void gpr_setenv(const char* name, const char* value) { GPR_ASSERT(res == 0); } +void gpr_unsetenv(const char* name) { + int res = unsetenv(name); + GPR_ASSERT(res == 0); +} + #endif /* GPR_LINUX_ENV */ diff --git a/src/core/lib/gpr/env_posix.cc b/src/core/lib/gpr/env_posix.cc index 599f85aa72b..30ddc50f682 100644 --- a/src/core/lib/gpr/env_posix.cc +++ b/src/core/lib/gpr/env_posix.cc @@ -44,4 +44,9 @@ void gpr_setenv(const char* name, const char* value) { GPR_ASSERT(res == 0); } +void gpr_unsetenv(const char* name) { + int res = unsetenv(name); + GPR_ASSERT(res == 0); +} + #endif /* GPR_POSIX_ENV */ diff --git a/src/core/lib/gpr/env_windows.cc b/src/core/lib/gpr/env_windows.cc index cf8ed60d8f6..76c45fb87a7 100644 --- a/src/core/lib/gpr/env_windows.cc +++ b/src/core/lib/gpr/env_windows.cc @@ -30,11 +30,6 @@ #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/string_windows.h" -const char* gpr_getenv_silent(const char* name, char** dst) { - *dst = gpr_getenv(name); - return NULL; -} - char* gpr_getenv(const char* name) { char* result = NULL; DWORD size; @@ -69,4 +64,11 @@ void gpr_setenv(const char* name, const char* value) { GPR_ASSERT(res); } +void gpr_unsetenv(const char* name) { + LPTSTR tname = gpr_char_to_tchar(name); + BOOL res = SetEnvironmentVariable(tname, NULL); + gpr_free(tname); + GPR_ASSERT(res); +} + #endif /* GPR_WINDOWS_ENV */ diff --git a/src/core/lib/gpr/log.cc b/src/core/lib/gpr/log.cc index 01ef112fb31..8a229b2adf1 100644 --- a/src/core/lib/gpr/log.cc +++ b/src/core/lib/gpr/log.cc @@ -22,12 +22,15 @@ #include #include -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/gprpp/global_config.h" #include #include +GPR_GLOBAL_CONFIG_DEFINE_STRING(grpc_verbosity, "ERROR", + "Default gRPC logging verbosity") + void gpr_default_log(gpr_log_func_args* args); static gpr_atm g_log_func = (gpr_atm)gpr_default_log; static gpr_atm g_min_severity_to_print = GPR_LOG_VERBOSITY_UNSET; @@ -72,29 +75,22 @@ void gpr_set_log_verbosity(gpr_log_severity min_severity_to_print) { } void gpr_log_verbosity_init() { - char* verbosity = nullptr; - const char* insecure_getenv = gpr_getenv_silent("GRPC_VERBOSITY", &verbosity); + grpc_core::UniquePtr verbosity = GPR_GLOBAL_CONFIG_GET(grpc_verbosity); gpr_atm min_severity_to_print = GPR_LOG_SEVERITY_ERROR; - if (verbosity != nullptr) { - if (gpr_stricmp(verbosity, "DEBUG") == 0) { + if (strlen(verbosity.get()) > 0) { + if (gpr_stricmp(verbosity.get(), "DEBUG") == 0) { min_severity_to_print = static_cast(GPR_LOG_SEVERITY_DEBUG); - } else if (gpr_stricmp(verbosity, "INFO") == 0) { + } else if (gpr_stricmp(verbosity.get(), "INFO") == 0) { min_severity_to_print = static_cast(GPR_LOG_SEVERITY_INFO); - } else if (gpr_stricmp(verbosity, "ERROR") == 0) { + } else if (gpr_stricmp(verbosity.get(), "ERROR") == 0) { min_severity_to_print = static_cast(GPR_LOG_SEVERITY_ERROR); } - gpr_free(verbosity); } if ((gpr_atm_no_barrier_load(&g_min_severity_to_print)) == GPR_LOG_VERBOSITY_UNSET) { gpr_atm_no_barrier_store(&g_min_severity_to_print, min_severity_to_print); } - - if (insecure_getenv != nullptr) { - gpr_log(GPR_DEBUG, "Warning: insecure environment read function '%s' used", - insecure_getenv); - } } void gpr_set_log_function(gpr_log_func f) { diff --git a/src/core/lib/gpr/string.cc b/src/core/lib/gpr/string.cc index 0a76fc1f54a..31d5fdee5be 100644 --- a/src/core/lib/gpr/string.cc +++ b/src/core/lib/gpr/string.cc @@ -332,16 +332,22 @@ void* gpr_memrchr(const void* s, int c, size_t n) { return nullptr; } -bool gpr_is_true(const char* s) { - size_t i; +bool gpr_parse_bool_value(const char* s, bool* dst) { + const char* kTrue[] = {"1", "t", "true", "y", "yes"}; + const char* kFalse[] = {"0", "f", "false", "n", "no"}; + static_assert(sizeof(kTrue) == sizeof(kFalse), "true_false_equal"); + if (s == nullptr) { return false; } - static const char* truthy[] = {"yes", "true", "1"}; - for (i = 0; i < GPR_ARRAY_SIZE(truthy); i++) { - if (0 == gpr_stricmp(s, truthy[i])) { + for (size_t i = 0; i < GPR_ARRAY_SIZE(kTrue); ++i) { + if (gpr_stricmp(s, kTrue[i]) == 0) { + *dst = true; + return true; + } else if (gpr_stricmp(s, kFalse[i]) == 0) { + *dst = false; return true; } } - return false; + return false; // didn't match a legal input } diff --git a/src/core/lib/gpr/string.h b/src/core/lib/gpr/string.h index ce51fe46321..c5efcec3bb1 100644 --- a/src/core/lib/gpr/string.h +++ b/src/core/lib/gpr/string.h @@ -113,7 +113,9 @@ int gpr_stricmp(const char* a, const char* b); void* gpr_memrchr(const void* s, int c, size_t n); -/** Return true if lower(s) equals "true", "yes" or "1", otherwise false. */ -bool gpr_is_true(const char* s); +/* Try to parse given string into a boolean value. + When parsed successfully, dst will have the value and returns true. + Otherwise, it returns false. */ +bool gpr_parse_bool_value(const char* value, bool* dst); #endif /* GRPC_CORE_LIB_GPR_STRING_H */ diff --git a/src/core/lib/gprpp/arena.cc b/src/core/lib/gprpp/arena.cc new file mode 100644 index 00000000000..5c344db4e35 --- /dev/null +++ b/src/core/lib/gprpp/arena.cc @@ -0,0 +1,103 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * 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 + +#include "src/core/lib/gprpp/arena.h" + +#include +#include + +#include +#include +#include +#include + +#include "src/core/lib/gpr/alloc.h" +#include "src/core/lib/gprpp/memory.h" + +namespace { + +void* ArenaStorage(size_t initial_size) { + static constexpr size_t base_size = + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_core::Arena)); + initial_size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(initial_size); + size_t alloc_size = base_size + initial_size; + static constexpr size_t alignment = + (GPR_CACHELINE_SIZE > GPR_MAX_ALIGNMENT && + GPR_CACHELINE_SIZE % GPR_MAX_ALIGNMENT == 0) + ? GPR_CACHELINE_SIZE + : GPR_MAX_ALIGNMENT; + return gpr_malloc_aligned(alloc_size, alignment); +} + +} // namespace + +namespace grpc_core { + +Arena::~Arena() { + Zone* z = last_zone_; + while (z) { + Zone* prev_z = z->prev; + z->~Zone(); + gpr_free_aligned(z); + z = prev_z; + } +} + +Arena* Arena::Create(size_t initial_size) { + return new (ArenaStorage(initial_size)) Arena(initial_size); +} + +Pair Arena::CreateWithAlloc(size_t initial_size, + size_t alloc_size) { + static constexpr size_t base_size = + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(Arena)); + auto* new_arena = + new (ArenaStorage(initial_size)) Arena(initial_size, alloc_size); + void* first_alloc = reinterpret_cast(new_arena) + base_size; + return MakePair(new_arena, first_alloc); +} + +size_t Arena::Destroy() { + size_t size = total_used_.Load(MemoryOrder::RELAXED); + this->~Arena(); + gpr_free_aligned(this); + return size; +} + +void* Arena::AllocZone(size_t size) { + // If the allocation isn't able to end in the initial zone, create a new + // zone for this allocation, and any unused space in the initial zone is + // wasted. This overflowing and wasting is uncommon because of our arena + // sizing hysteresis (that is, most calls should have a large enough initial + // zone and will not need to grow the arena). + static constexpr size_t zone_base_size = + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(Zone)); + size_t alloc_size = zone_base_size + size; + Zone* z = new (gpr_malloc_aligned(alloc_size, GPR_MAX_ALIGNMENT)) Zone(); + { + gpr_spinlock_lock(&arena_growth_spinlock_); + z->prev = last_zone_; + last_zone_ = z; + gpr_spinlock_unlock(&arena_growth_spinlock_); + } + return reinterpret_cast(z) + zone_base_size; +} + +} // namespace grpc_core diff --git a/src/core/lib/gprpp/arena.h b/src/core/lib/gprpp/arena.h new file mode 100644 index 00000000000..b1b0c4a85cb --- /dev/null +++ b/src/core/lib/gprpp/arena.h @@ -0,0 +1,121 @@ +/* + * + * Copyright 2017 gRPC authors. + * + * 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. + * + */ + +// \file Arena based allocator +// Allows very fast allocation of memory, but that memory cannot be freed until +// the arena as a whole is freed +// Tracks the total memory allocated against it, so that future arenas can +// pre-allocate the right amount of memory + +#ifndef GRPC_CORE_LIB_GPRPP_ARENA_H +#define GRPC_CORE_LIB_GPRPP_ARENA_H + +#include + +#include +#include + +#include +#include + +#include "src/core/lib/gpr/alloc.h" +#include "src/core/lib/gpr/spinlock.h" +#include "src/core/lib/gprpp/atomic.h" +#include "src/core/lib/gprpp/pair.h" + +#include + +namespace grpc_core { + +class Arena { + public: + // Create an arena, with \a initial_size bytes in the first allocated buffer. + static Arena* Create(size_t initial_size); + + // Create an arena, with \a initial_size bytes in the first allocated buffer, + // and return both a void pointer to the returned arena and a void* with the + // first allocation. + static Pair CreateWithAlloc(size_t initial_size, + size_t alloc_size); + + // Destroy an arena, returning the total number of bytes allocated. + size_t Destroy(); + // Allocate \a size bytes from the arena. + void* Alloc(size_t size) { + static constexpr size_t base_size = + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(Arena)); + size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(size); + size_t begin = total_used_.FetchAdd(size, MemoryOrder::RELAXED); + if (begin + size <= initial_zone_size_) { + return reinterpret_cast(this) + base_size + begin; + } else { + return AllocZone(size); + } + } + + // TODO(roth): We currently assume that all callers need alignment of 16 + // bytes, which may be wrong in some cases. When we have time, we should + // change this to instead use the alignment of the type being allocated by + // this method. + template + T* New(Args&&... args) { + T* t = static_cast(Alloc(sizeof(T))); + new (t) T(std::forward(args)...); + return t; + } + + private: + struct Zone { + Zone* prev; + }; + + // Initialize an arena. + // Parameters: + // initial_size: The initial size of the whole arena in bytes. These bytes + // are contained within 'zone 0'. If the arena user ends up requiring more + // memory than the arena contains in zone 0, subsequent zones are allocated + // on demand and maintained in a tail-linked list. + // + // initial_alloc: Optionally, construct the arena as though a call to + // Alloc() had already been made for initial_alloc bytes. This provides a + // quick optimization (avoiding an atomic fetch-add) for the common case + // where we wish to create an arena and then perform an immediate + // allocation. + explicit Arena(size_t initial_size, size_t initial_alloc = 0) + : total_used_(initial_alloc), initial_zone_size_(initial_size) {} + + ~Arena(); + + void* AllocZone(size_t size); + + // Keep track of the total used size. We use this in our call sizing + // hysteresis. + Atomic total_used_; + size_t initial_zone_size_; + gpr_spinlock arena_growth_spinlock_ = GPR_SPINLOCK_STATIC_INITIALIZER; + // If the initial arena allocation wasn't enough, we allocate additional zones + // in a reverse linked list. Each additional zone consists of (1) a pointer to + // the zone added before this zone (null if this is the first additional zone) + // and (2) the allocated memory. The arena itself maintains a pointer to the + // last zone; the zone list is reverse-walked during arena destruction only. + Zone* last_zone_ = nullptr; +}; + +} // namespace grpc_core + +#endif /* GRPC_CORE_LIB_GPRPP_ARENA_H */ diff --git a/src/core/lib/gprpp/fork.cc b/src/core/lib/gprpp/fork.cc index c4b1cbc2233..37552692373 100644 --- a/src/core/lib/gprpp/fork.cc +++ b/src/core/lib/gprpp/fork.cc @@ -26,8 +26,8 @@ #include #include -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/useful.h" +#include "src/core/lib/gprpp/global_config.h" #include "src/core/lib/gprpp/memory.h" /* @@ -35,6 +35,16 @@ * AROUND VERY SPECIFIC USE CASES. */ +#ifdef GRPC_ENABLE_FORK_SUPPORT +#define GRPC_ENABLE_FORK_SUPPORT_DEFAULT true +#else +#define GRPC_ENABLE_FORK_SUPPORT_DEFAULT false +#endif // GRPC_ENABLE_FORK_SUPPORT + +GPR_GLOBAL_CONFIG_DEFINE_BOOL(grpc_enable_fork_support, + GRPC_ENABLE_FORK_SUPPORT_DEFAULT, + "Enable folk support"); + namespace grpc_core { namespace internal { // The exec_ctx_count has 2 modes, blocked and unblocked. @@ -158,34 +168,7 @@ class ThreadState { void Fork::GlobalInit() { if (!override_enabled_) { -#ifdef GRPC_ENABLE_FORK_SUPPORT - support_enabled_ = true; -#endif - bool env_var_set = false; - char* env = gpr_getenv("GRPC_ENABLE_FORK_SUPPORT"); - if (env != nullptr) { - static const char* truthy[] = {"yes", "Yes", "YES", "true", - "True", "TRUE", "1"}; - static const char* falsey[] = {"no", "No", "NO", "false", - "False", "FALSE", "0"}; - for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) { - if (0 == strcmp(env, truthy[i])) { - support_enabled_ = true; - env_var_set = true; - break; - } - } - if (!env_var_set) { - for (size_t i = 0; i < GPR_ARRAY_SIZE(falsey); i++) { - if (0 == strcmp(env, falsey[i])) { - support_enabled_ = false; - env_var_set = true; - break; - } - } - } - gpr_free(env); - } + support_enabled_ = GPR_GLOBAL_CONFIG_GET(grpc_enable_fork_support); } if (support_enabled_) { exec_ctx_state_ = grpc_core::New(); @@ -260,7 +243,7 @@ void Fork::AwaitThreads() { internal::ExecCtxState* Fork::exec_ctx_state_ = nullptr; internal::ThreadState* Fork::thread_state_ = nullptr; -bool Fork::support_enabled_ = false; +std::atomic Fork::support_enabled_; bool Fork::override_enabled_ = false; Fork::child_postfork_func Fork::reset_child_polling_engine_ = nullptr; } // namespace grpc_core diff --git a/src/core/lib/gprpp/fork.h b/src/core/lib/gprpp/fork.h index 5a7404f0d91..73f2fa56aa7 100644 --- a/src/core/lib/gprpp/fork.h +++ b/src/core/lib/gprpp/fork.h @@ -19,6 +19,10 @@ #ifndef GRPC_CORE_LIB_GPRPP_FORK_H #define GRPC_CORE_LIB_GPRPP_FORK_H +#include + +#include + /* * NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK * AROUND VERY SPECIFIC USE CASES. @@ -78,7 +82,7 @@ class Fork { private: static internal::ExecCtxState* exec_ctx_state_; static internal::ThreadState* thread_state_; - static bool support_enabled_; + static std::atomic support_enabled_; static bool override_enabled_; static child_postfork_func reset_child_polling_engine_; }; diff --git a/src/core/lib/gprpp/global_config.h b/src/core/lib/gprpp/global_config.h new file mode 100644 index 00000000000..a1bbf07564c --- /dev/null +++ b/src/core/lib/gprpp/global_config.h @@ -0,0 +1,87 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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_LIB_GPRPP_GLOBAL_CONFIG_H +#define GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_H + +#include + +#include + +// -------------------------------------------------------------------- +// How to use global configuration variables: +// +// Defining config variables of a specified type: +// GPR_GLOBAL_CONFIG_DEFINE_*TYPE*(name, default_value, help); +// +// Supported TYPEs: BOOL, INT32, STRING +// +// It's recommended to use lowercase letters for 'name' like +// regular variables. The builtin configuration system uses +// environment variable and the name is converted to uppercase +// when looking up the value. For example, +// GPR_GLOBAL_CONFIG_DEFINE(grpc_latency) looks up the value with the +// name, "GRPC_LATENCY". +// +// The variable initially has the specified 'default_value' +// which must be an expression convertible to 'Type'. +// 'default_value' may be evaluated 0 or more times, +// and at an unspecified time; keep it +// simple and usually free of side-effects. +// +// GPR_GLOBAL_CONFIG_DEFINE_*TYPE* should not be called in a C++ header. +// It should be called at the top-level (outside any namespaces) +// in a .cc file. +// +// Getting the variables: +// GPR_GLOBAL_CONFIG_GET(name) +// +// If error happens during getting variables, error messages will +// be logged and default value will be returned. +// +// Setting the variables with new value: +// GPR_GLOBAL_CONFIG_SET(name, new_value) +// +// Declaring config variables for other modules to access: +// GPR_GLOBAL_CONFIG_DECLARE_*TYPE*(name) + +// -------------------------------------------------------------------- +// How to customize the global configuration system: +// +// How to read and write configuration value can be customized. +// Builtin system uses environment variables but it can be extended to +// support command-line flag, file, etc. +// +// To customize it, following macros should be redefined. +// +// GPR_GLOBAL_CONFIG_DEFINE_BOOL +// GPR_GLOBAL_CONFIG_DEFINE_INT32 +// GPR_GLOBAL_CONFIG_DEFINE_STRING +// +// These macros should define functions for getting and setting variable. +// For example, GPR_GLOBAL_CONFIG_DEFINE_BOOL(test, ...) would define two +// functions. +// +// bool gpr_global_config_get_test(); +// void gpr_global_config_set_test(bool value); + +#include "src/core/lib/gprpp/global_config_env.h" + +#include "src/core/lib/gprpp/global_config_custom.h" + +#endif /* GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_H */ diff --git a/src/core/lib/gprpp/global_config_custom.h b/src/core/lib/gprpp/global_config_custom.h new file mode 100644 index 00000000000..175677e07c7 --- /dev/null +++ b/src/core/lib/gprpp/global_config_custom.h @@ -0,0 +1,29 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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_LIB_GPRPP_GLOBAL_CONFIG_CUSTOM_H +#define GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_CUSTOM_H + +// This is a placeholder for custom global configuration implementation. +// To use the custom one, please define following macros here. +// +// GPR_GLOBAL_CONFIG_DEFINE_BOOL +// GPR_GLOBAL_CONFIG_DEFINE_INT32 +// GPR_GLOBAL_CONFIG_DEFINE_STRING + +#endif /* GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_CUSTOM_H */ diff --git a/src/core/lib/gprpp/global_config_env.cc b/src/core/lib/gprpp/global_config_env.cc new file mode 100644 index 00000000000..fb14805d01b --- /dev/null +++ b/src/core/lib/gprpp/global_config_env.cc @@ -0,0 +1,135 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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 + +#include "src/core/lib/gprpp/global_config_env.h" + +#include +#include +#include + +#include "src/core/lib/gpr/env.h" +#include "src/core/lib/gpr/string.h" + +#include +#include + +namespace grpc_core { + +namespace { + +void DefaultGlobalConfigEnvErrorFunction(const char* error_message) { + gpr_log(GPR_ERROR, "%s", error_message); +} + +GlobalConfigEnvErrorFunctionType g_global_config_env_error_func = + DefaultGlobalConfigEnvErrorFunction; + +void LogParsingError(const char* name, const char* value) { + char* error_message; + gpr_asprintf(&error_message, + "Illegal value '%s' specified for environment variable '%s'", + value, name); + (*g_global_config_env_error_func)(error_message); + gpr_free(error_message); +} + +} // namespace + +void SetGlobalConfigEnvErrorFunction(GlobalConfigEnvErrorFunctionType func) { + g_global_config_env_error_func = func; +} + +UniquePtr GlobalConfigEnv::GetValue() { + return UniquePtr(gpr_getenv(GetName())); +} + +void GlobalConfigEnv::SetValue(const char* value) { + gpr_setenv(GetName(), value); +} + +void GlobalConfigEnv::Unset() { gpr_unsetenv(GetName()); } + +char* GlobalConfigEnv::GetName() { + // This makes sure that name_ is in a canonical form having uppercase + // letters. This is okay to be called serveral times. + for (char* c = name_; *c != 0; ++c) { + *c = toupper(*c); + } + return name_; +} +static_assert(std::is_trivially_destructible::value, + "GlobalConfigEnvBool needs to be trivially destructible."); + +bool GlobalConfigEnvBool::Get() { + UniquePtr str = GetValue(); + if (str == nullptr) { + return default_value_; + } + // parsing given value string. + bool result = false; + if (!gpr_parse_bool_value(str.get(), &result)) { + LogParsingError(GetName(), str.get()); + result = default_value_; + } + return result; +} + +void GlobalConfigEnvBool::Set(bool value) { + SetValue(value ? "true" : "false"); +} + +static_assert(std::is_trivially_destructible::value, + "GlobalConfigEnvInt32 needs to be trivially destructible."); + +int32_t GlobalConfigEnvInt32::Get() { + UniquePtr str = GetValue(); + if (str == nullptr) { + return default_value_; + } + // parsing given value string. + char* end = str.get(); + long result = strtol(str.get(), &end, 10); + if (*end != 0) { + LogParsingError(GetName(), str.get()); + result = default_value_; + } + return static_cast(result); +} + +void GlobalConfigEnvInt32::Set(int32_t value) { + char buffer[GPR_LTOA_MIN_BUFSIZE]; + gpr_ltoa(value, buffer); + SetValue(buffer); +} + +static_assert(std::is_trivially_destructible::value, + "GlobalConfigEnvString needs to be trivially destructible."); + +UniquePtr GlobalConfigEnvString::Get() { + UniquePtr str = GetValue(); + if (str == nullptr) { + return UniquePtr(gpr_strdup(default_value_)); + } + return str; +} + +void GlobalConfigEnvString::Set(const char* value) { SetValue(value); } + +} // namespace grpc_core diff --git a/src/core/lib/gprpp/global_config_env.h b/src/core/lib/gprpp/global_config_env.h new file mode 100644 index 00000000000..3d3038895d3 --- /dev/null +++ b/src/core/lib/gprpp/global_config_env.h @@ -0,0 +1,131 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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_LIB_GPRPP_GLOBAL_CONFIG_ENV_H +#define GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_ENV_H + +#include + +#include "src/core/lib/gprpp/global_config_generic.h" +#include "src/core/lib/gprpp/memory.h" + +namespace grpc_core { + +typedef void (*GlobalConfigEnvErrorFunctionType)(const char* error_message); + +/* + * Set global_config_env_error_function which is called when config system + * encounters errors such as parsing error. What the default function does + * is logging error message. + */ +void SetGlobalConfigEnvErrorFunction(GlobalConfigEnvErrorFunctionType func); + +// Base class for all classes to access environment variables. +class GlobalConfigEnv { + protected: + // `name` should be writable and alive after constructor is called. + constexpr explicit GlobalConfigEnv(char* name) : name_(name) {} + + public: + // Returns the value of `name` variable. + UniquePtr GetValue(); + + // Sets the value of `name` variable. + void SetValue(const char* value); + + // Unsets `name` variable. + void Unset(); + + protected: + char* GetName(); + + private: + char* name_; +}; + +class GlobalConfigEnvBool : public GlobalConfigEnv { + public: + constexpr GlobalConfigEnvBool(char* name, bool default_value) + : GlobalConfigEnv(name), default_value_(default_value) {} + + bool Get(); + void Set(bool value); + + private: + bool default_value_; +}; + +class GlobalConfigEnvInt32 : public GlobalConfigEnv { + public: + constexpr GlobalConfigEnvInt32(char* name, int32_t default_value) + : GlobalConfigEnv(name), default_value_(default_value) {} + + int32_t Get(); + void Set(int32_t value); + + private: + int32_t default_value_; +}; + +class GlobalConfigEnvString : public GlobalConfigEnv { + public: + constexpr GlobalConfigEnvString(char* name, const char* default_value) + : GlobalConfigEnv(name), default_value_(default_value) {} + + UniquePtr Get(); + void Set(const char* value); + + private: + const char* default_value_; +}; + +} // namespace grpc_core + +// Macros for defining global config instances using environment variables. +// This defines a GlobalConfig*Type* instance with arguments for +// mutable variable name and default value. +// Mutable name (g_env_str_##name) is here for having an array +// for the canonical name without dynamic allocation. +// `help` argument is ignored for this implementation. + +#define GPR_GLOBAL_CONFIG_DEFINE_BOOL(name, default_value, help) \ + static char g_env_str_##name[] = #name; \ + static ::grpc_core::GlobalConfigEnvBool g_env_##name(g_env_str_##name, \ + default_value); \ + bool gpr_global_config_get_##name() { return g_env_##name.Get(); } \ + void gpr_global_config_set_##name(bool value) { g_env_##name.Set(value); } + +#define GPR_GLOBAL_CONFIG_DEFINE_INT32(name, default_value, help) \ + static char g_env_str_##name[] = #name; \ + static ::grpc_core::GlobalConfigEnvInt32 g_env_##name(g_env_str_##name, \ + default_value); \ + int32_t gpr_global_config_get_##name() { return g_env_##name.Get(); } \ + void gpr_global_config_set_##name(int32_t value) { g_env_##name.Set(value); } + +#define GPR_GLOBAL_CONFIG_DEFINE_STRING(name, default_value, help) \ + static char g_env_str_##name[] = #name; \ + static ::grpc_core::GlobalConfigEnvString g_env_##name(g_env_str_##name, \ + default_value); \ + ::grpc_core::UniquePtr gpr_global_config_get_##name() { \ + return g_env_##name.Get(); \ + } \ + void gpr_global_config_set_##name(const char* value) { \ + g_env_##name.Set(value); \ + } + +#endif /* GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_ENV_H */ diff --git a/src/core/lib/gprpp/global_config_generic.h b/src/core/lib/gprpp/global_config_generic.h new file mode 100644 index 00000000000..d3e3e2a2dbe --- /dev/null +++ b/src/core/lib/gprpp/global_config_generic.h @@ -0,0 +1,44 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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_LIB_GPRPP_GLOBAL_CONFIG_GENERIC_H +#define GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_GENERIC_H + +#include + +#include "src/core/lib/gprpp/memory.h" + +#include + +#define GPR_GLOBAL_CONFIG_GET(name) gpr_global_config_get_##name() + +#define GPR_GLOBAL_CONFIG_SET(name, value) gpr_global_config_set_##name(value) + +#define GPR_GLOBAL_CONFIG_DECLARE_BOOL(name) \ + extern bool gpr_global_config_get_##name(); \ + extern void gpr_global_config_set_##name(bool value) + +#define GPR_GLOBAL_CONFIG_DECLARE_INT32(name) \ + extern int32_t gpr_global_config_get_##name(); \ + extern void gpr_global_config_set_##name(int32_t value) + +#define GPR_GLOBAL_CONFIG_DECLARE_STRING(name) \ + extern grpc_core::UniquePtr gpr_global_config_get_##name(); \ + extern void gpr_global_config_set_##name(const char* value) + +#endif /* GRPC_CORE_LIB_GPRPP_GLOBAL_CONFIG_GENERIC_H */ diff --git a/src/core/lib/gprpp/optional.h b/src/core/lib/gprpp/optional.h index a8e3ce1505e..ab5f86393b6 100644 --- a/src/core/lib/gprpp/optional.h +++ b/src/core/lib/gprpp/optional.h @@ -26,6 +26,7 @@ namespace grpc_core { template class Optional { public: + Optional() : value_() {} void set(const T& val) { value_ = val; set_ = true; diff --git a/src/core/lib/gprpp/orphanable.h b/src/core/lib/gprpp/orphanable.h index dda5026cbca..2e467e49060 100644 --- a/src/core/lib/gprpp/orphanable.h +++ b/src/core/lib/gprpp/orphanable.h @@ -110,12 +110,12 @@ class InternallyRefCounted : public Orphanable { } void Unref() { - if (refs_.Unref()) { + if (GPR_UNLIKELY(refs_.Unref())) { Delete(static_cast(this)); } } void Unref(const DebugLocation& location, const char* reason) { - if (refs_.Unref(location, reason)) { + if (GPR_UNLIKELY(refs_.Unref(location, reason))) { Delete(static_cast(this)); } } diff --git a/src/core/lib/gprpp/ref_counted.h b/src/core/lib/gprpp/ref_counted.h index 87b342e0093..4de50985dcf 100644 --- a/src/core/lib/gprpp/ref_counted.h +++ b/src/core/lib/gprpp/ref_counted.h @@ -180,7 +180,7 @@ class RefCount { // So, use NonPolymorphicRefCount only when both of the following conditions // are guaranteed to hold: // (a) Child is a concrete leaf class in RefCounted, and -// (b) you are gauranteed to call Unref only on concrete leaf classes and not +// (b) you are guaranteed to call Unref only on concrete leaf classes and not // their parents. // // The following example is illegal, because calling Unref() will not call @@ -211,12 +211,12 @@ class RefCounted : public Impl { // private, since it will only be used by RefCountedPtr<>, which is a // friend of this class. void Unref() { - if (refs_.Unref()) { + if (GPR_UNLIKELY(refs_.Unref())) { Delete(static_cast(this)); } } void Unref(const DebugLocation& location, const char* reason) { - if (refs_.Unref(location, reason)) { + if (GPR_UNLIKELY(refs_.Unref(location, reason))) { Delete(static_cast(this)); } } diff --git a/src/core/lib/http/parser.cc b/src/core/lib/http/parser.cc index 7ca1cc9db5f..58608da982c 100644 --- a/src/core/lib/http/parser.cc +++ b/src/core/lib/http/parser.cc @@ -300,7 +300,7 @@ static grpc_error* addbyte(grpc_http_parser* parser, uint8_t byte, case GRPC_HTTP_FIRST_LINE: case GRPC_HTTP_HEADERS: if (parser->cur_line_length >= GRPC_HTTP_PARSER_MAX_HEADER_LENGTH) { - if (grpc_http1_trace.enabled()) + if (GRPC_TRACE_FLAG_ENABLED(grpc_http1_trace)) gpr_log(GPR_ERROR, "HTTP header max line length (%d) exceeded", GRPC_HTTP_PARSER_MAX_HEADER_LENGTH); return GRPC_ERROR_CREATE_FROM_STATIC_STRING( diff --git a/src/core/lib/iomgr/call_combiner.cc b/src/core/lib/iomgr/call_combiner.cc index 6b5759a036f..6a4e85de4df 100644 --- a/src/core/lib/iomgr/call_combiner.cc +++ b/src/core/lib/iomgr/call_combiner.cc @@ -26,23 +26,43 @@ #include "src/core/lib/debug/stats.h" #include "src/core/lib/profiling/timers.h" -grpc_core::TraceFlag grpc_call_combiner_trace(false, "call_combiner"); +namespace grpc_core { -static grpc_error* decode_cancel_state_error(gpr_atm cancel_state) { +TraceFlag grpc_call_combiner_trace(false, "call_combiner"); + +namespace { + +grpc_error* DecodeCancelStateError(gpr_atm cancel_state) { if (cancel_state & 1) { return (grpc_error*)(cancel_state & ~static_cast(1)); } return GRPC_ERROR_NONE; } -static gpr_atm encode_cancel_state_error(grpc_error* error) { +gpr_atm EncodeCancelStateError(grpc_error* error) { return static_cast(1) | (gpr_atm)error; } +} // namespace + +CallCombiner::CallCombiner() { + gpr_atm_no_barrier_store(&cancel_state_, 0); + gpr_atm_no_barrier_store(&size_, 0); + gpr_mpscq_init(&queue_); +#ifdef GRPC_TSAN_ENABLED + GRPC_CLOSURE_INIT(&tsan_closure_, TsanClosure, this, + grpc_schedule_on_exec_ctx); +#endif +} + +CallCombiner::~CallCombiner() { + gpr_mpscq_destroy(&queue_); + GRPC_ERROR_UNREF(DecodeCancelStateError(cancel_state_)); +} + #ifdef GRPC_TSAN_ENABLED -static void tsan_closure(void* user_data, grpc_error* error) { - grpc_call_combiner* call_combiner = - static_cast(user_data); +void CallCombiner::TsanClosure(void* arg, grpc_error* error) { + CallCombiner* self = static_cast(arg); // We ref-count the lock, and check if it's already taken. // If it was taken, we should do nothing. Otherwise, we will mark it as // locked. Note that if two different threads try to do this, only one of @@ -51,18 +71,18 @@ static void tsan_closure(void* user_data, grpc_error* error) { // TSAN will correctly produce an error. // // TODO(soheil): This only covers the callbacks scheduled by - // grpc_call_combiner_(start|finish). If in the future, a - // callback gets scheduled using other mechanisms, we will need - // to add APIs to externally lock call combiners. - grpc_core::RefCountedPtr lock = - call_combiner->tsan_lock; + // CallCombiner::Start() and CallCombiner::Stop(). + // If in the future, a callback gets scheduled using other + // mechanisms, we will need to add APIs to externally lock + // call combiners. + RefCountedPtr lock = self->tsan_lock_; bool prev = false; if (lock->taken.compare_exchange_strong(prev, true)) { TSAN_ANNOTATE_RWLOCK_ACQUIRED(&lock->taken, true); } else { lock.reset(); } - GRPC_CLOSURE_RUN(call_combiner->original_closure, GRPC_ERROR_REF(error)); + GRPC_CLOSURE_RUN(self->original_closure_, GRPC_ERROR_REF(error)); if (lock != nullptr) { TSAN_ANNOTATE_RWLOCK_RELEASED(&lock->taken, true); bool prev = true; @@ -71,34 +91,17 @@ static void tsan_closure(void* user_data, grpc_error* error) { } #endif -static void call_combiner_sched_closure(grpc_call_combiner* call_combiner, - grpc_closure* closure, - grpc_error* error) { +void CallCombiner::ScheduleClosure(grpc_closure* closure, grpc_error* error) { #ifdef GRPC_TSAN_ENABLED - call_combiner->original_closure = closure; - GRPC_CLOSURE_SCHED(&call_combiner->tsan_closure, error); + original_closure_ = closure; + GRPC_CLOSURE_SCHED(&tsan_closure_, error); #else GRPC_CLOSURE_SCHED(closure, error); #endif } -void grpc_call_combiner_init(grpc_call_combiner* call_combiner) { - gpr_atm_no_barrier_store(&call_combiner->cancel_state, 0); - gpr_atm_no_barrier_store(&call_combiner->size, 0); - gpr_mpscq_init(&call_combiner->queue); -#ifdef GRPC_TSAN_ENABLED - GRPC_CLOSURE_INIT(&call_combiner->tsan_closure, tsan_closure, call_combiner, - grpc_schedule_on_exec_ctx); -#endif -} - -void grpc_call_combiner_destroy(grpc_call_combiner* call_combiner) { - gpr_mpscq_destroy(&call_combiner->queue); - GRPC_ERROR_UNREF(decode_cancel_state_error(call_combiner->cancel_state)); -} - #ifndef NDEBUG -#define DEBUG_ARGS , const char *file, int line +#define DEBUG_ARGS const char *file, int line, #define DEBUG_FMT_STR "%s:%d: " #define DEBUG_FMT_ARGS , file, line #else @@ -107,123 +110,113 @@ void grpc_call_combiner_destroy(grpc_call_combiner* call_combiner) { #define DEBUG_FMT_ARGS #endif -void grpc_call_combiner_start(grpc_call_combiner* call_combiner, - grpc_closure* closure, - grpc_error* error DEBUG_ARGS, - const char* reason) { - GPR_TIMER_SCOPE("call_combiner_start", 0); - if (grpc_call_combiner_trace.enabled()) { +void CallCombiner::Start(grpc_closure* closure, grpc_error* error, + DEBUG_ARGS const char* reason) { + GPR_TIMER_SCOPE("CallCombiner::Start", 0); + if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) { gpr_log(GPR_INFO, - "==> grpc_call_combiner_start() [%p] closure=%p [" DEBUG_FMT_STR + "==> CallCombiner::Start() [%p] closure=%p [" DEBUG_FMT_STR "%s] error=%s", - call_combiner, closure DEBUG_FMT_ARGS, reason, - grpc_error_string(error)); + this, closure DEBUG_FMT_ARGS, reason, grpc_error_string(error)); } - size_t prev_size = static_cast( - gpr_atm_full_fetch_add(&call_combiner->size, (gpr_atm)1)); - if (grpc_call_combiner_trace.enabled()) { + size_t prev_size = + static_cast(gpr_atm_full_fetch_add(&size_, (gpr_atm)1)); + if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) { gpr_log(GPR_INFO, " size: %" PRIdPTR " -> %" PRIdPTR, prev_size, prev_size + 1); } GRPC_STATS_INC_CALL_COMBINER_LOCKS_SCHEDULED_ITEMS(); if (prev_size == 0) { GRPC_STATS_INC_CALL_COMBINER_LOCKS_INITIATED(); - GPR_TIMER_MARK("call_combiner_initiate", 0); - if (grpc_call_combiner_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) { gpr_log(GPR_INFO, " EXECUTING IMMEDIATELY"); } // Queue was empty, so execute this closure immediately. - call_combiner_sched_closure(call_combiner, closure, error); + ScheduleClosure(closure, error); } else { - if (grpc_call_combiner_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) { gpr_log(GPR_INFO, " QUEUING"); } // Queue was not empty, so add closure to queue. closure->error_data.error = error; - gpr_mpscq_push(&call_combiner->queue, - reinterpret_cast(closure)); + gpr_mpscq_push(&queue_, reinterpret_cast(closure)); } } -void grpc_call_combiner_stop(grpc_call_combiner* call_combiner DEBUG_ARGS, - const char* reason) { - GPR_TIMER_SCOPE("call_combiner_stop", 0); - if (grpc_call_combiner_trace.enabled()) { - gpr_log(GPR_INFO, - "==> grpc_call_combiner_stop() [%p] [" DEBUG_FMT_STR "%s]", - call_combiner DEBUG_FMT_ARGS, reason); +void CallCombiner::Stop(DEBUG_ARGS const char* reason) { + GPR_TIMER_SCOPE("CallCombiner::Stop", 0); + if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) { + gpr_log(GPR_INFO, "==> CallCombiner::Stop() [%p] [" DEBUG_FMT_STR "%s]", + this DEBUG_FMT_ARGS, reason); } - size_t prev_size = static_cast( - gpr_atm_full_fetch_add(&call_combiner->size, (gpr_atm)-1)); - if (grpc_call_combiner_trace.enabled()) { + size_t prev_size = + static_cast(gpr_atm_full_fetch_add(&size_, (gpr_atm)-1)); + if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) { gpr_log(GPR_INFO, " size: %" PRIdPTR " -> %" PRIdPTR, prev_size, prev_size - 1); } GPR_ASSERT(prev_size >= 1); if (prev_size > 1) { while (true) { - if (grpc_call_combiner_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) { gpr_log(GPR_INFO, " checking queue"); } bool empty; grpc_closure* closure = reinterpret_cast( - gpr_mpscq_pop_and_check_end(&call_combiner->queue, &empty)); + gpr_mpscq_pop_and_check_end(&queue_, &empty)); if (closure == nullptr) { // This can happen either due to a race condition within the mpscq - // code or because of a race with grpc_call_combiner_start(). - if (grpc_call_combiner_trace.enabled()) { + // code or because of a race with Start(). + if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) { gpr_log(GPR_INFO, " queue returned no result; checking again"); } continue; } - if (grpc_call_combiner_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) { gpr_log(GPR_INFO, " EXECUTING FROM QUEUE: closure=%p error=%s", closure, grpc_error_string(closure->error_data.error)); } - call_combiner_sched_closure(call_combiner, closure, - closure->error_data.error); + ScheduleClosure(closure, closure->error_data.error); break; } - } else if (grpc_call_combiner_trace.enabled()) { + } else if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) { gpr_log(GPR_INFO, " queue empty"); } } -void grpc_call_combiner_set_notify_on_cancel(grpc_call_combiner* call_combiner, - grpc_closure* closure) { +void CallCombiner::SetNotifyOnCancel(grpc_closure* closure) { GRPC_STATS_INC_CALL_COMBINER_SET_NOTIFY_ON_CANCEL(); while (true) { // Decode original state. - gpr_atm original_state = gpr_atm_acq_load(&call_combiner->cancel_state); - grpc_error* original_error = decode_cancel_state_error(original_state); + gpr_atm original_state = gpr_atm_acq_load(&cancel_state_); + grpc_error* original_error = DecodeCancelStateError(original_state); // If error is set, invoke the cancellation closure immediately. // Otherwise, store the new closure. if (original_error != GRPC_ERROR_NONE) { - if (grpc_call_combiner_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) { gpr_log(GPR_INFO, "call_combiner=%p: scheduling notify_on_cancel callback=%p " "for pre-existing cancellation", - call_combiner, closure); + this, closure); } GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_REF(original_error)); break; } else { - if (gpr_atm_full_cas(&call_combiner->cancel_state, original_state, - (gpr_atm)closure)) { - if (grpc_call_combiner_trace.enabled()) { + if (gpr_atm_full_cas(&cancel_state_, original_state, (gpr_atm)closure)) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) { gpr_log(GPR_INFO, "call_combiner=%p: setting notify_on_cancel=%p", - call_combiner, closure); + this, closure); } // If we replaced an earlier closure, invoke the original // closure with GRPC_ERROR_NONE. This allows callers to clean // up any resources they may be holding for the callback. if (original_state != 0) { closure = (grpc_closure*)original_state; - if (grpc_call_combiner_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) { gpr_log(GPR_INFO, - "call_combiner=%p: scheduling old cancel callback=%p", - call_combiner, closure); + "call_combiner=%p: scheduling old cancel callback=%p", this, + closure); } GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_NONE); } @@ -234,24 +227,23 @@ void grpc_call_combiner_set_notify_on_cancel(grpc_call_combiner* call_combiner, } } -void grpc_call_combiner_cancel(grpc_call_combiner* call_combiner, - grpc_error* error) { +void CallCombiner::Cancel(grpc_error* error) { GRPC_STATS_INC_CALL_COMBINER_CANCELLED(); while (true) { - gpr_atm original_state = gpr_atm_acq_load(&call_combiner->cancel_state); - grpc_error* original_error = decode_cancel_state_error(original_state); + gpr_atm original_state = gpr_atm_acq_load(&cancel_state_); + grpc_error* original_error = DecodeCancelStateError(original_state); if (original_error != GRPC_ERROR_NONE) { GRPC_ERROR_UNREF(error); break; } - if (gpr_atm_full_cas(&call_combiner->cancel_state, original_state, - encode_cancel_state_error(error))) { + if (gpr_atm_full_cas(&cancel_state_, original_state, + EncodeCancelStateError(error))) { if (original_state != 0) { grpc_closure* notify_on_cancel = (grpc_closure*)original_state; - if (grpc_call_combiner_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) { gpr_log(GPR_INFO, "call_combiner=%p: scheduling notify_on_cancel callback=%p", - call_combiner, notify_on_cancel); + this, notify_on_cancel); } GRPC_CLOSURE_SCHED(notify_on_cancel, GRPC_ERROR_REF(error)); } @@ -260,3 +252,5 @@ void grpc_call_combiner_cancel(grpc_call_combiner* call_combiner, // cas failed, try again. } } + +} // namespace grpc_core diff --git a/src/core/lib/iomgr/call_combiner.h b/src/core/lib/iomgr/call_combiner.h index 4ec0044f056..a10b437c15a 100644 --- a/src/core/lib/iomgr/call_combiner.h +++ b/src/core/lib/iomgr/call_combiner.h @@ -41,15 +41,78 @@ // when it is done with the action that was kicked off by the original // callback. -extern grpc_core::TraceFlag grpc_call_combiner_trace; +namespace grpc_core { + +extern TraceFlag grpc_call_combiner_trace; + +class CallCombiner { + public: + CallCombiner(); + ~CallCombiner(); + +#ifndef NDEBUG +#define GRPC_CALL_COMBINER_START(call_combiner, closure, error, reason) \ + (call_combiner)->Start((closure), (error), __FILE__, __LINE__, (reason)) +#define GRPC_CALL_COMBINER_STOP(call_combiner, reason) \ + (call_combiner)->Stop(__FILE__, __LINE__, (reason)) + /// Starts processing \a closure. + void Start(grpc_closure* closure, grpc_error* error, const char* file, + int line, const char* reason); + /// Yields the call combiner to the next closure in the queue, if any. + void Stop(const char* file, int line, const char* reason); +#else +#define GRPC_CALL_COMBINER_START(call_combiner, closure, error, reason) \ + (call_combiner)->Start((closure), (error), (reason)) +#define GRPC_CALL_COMBINER_STOP(call_combiner, reason) \ + (call_combiner)->Stop((reason)) + /// Starts processing \a closure. + void Start(grpc_closure* closure, grpc_error* error, const char* reason); + /// Yields the call combiner to the next closure in the queue, if any. + void Stop(const char* reason); +#endif + + /// Registers \a closure to be invoked when Cancel() is called. + /// + /// Once a closure is registered, it will always be scheduled exactly + /// once; this allows the closure to hold references that will be freed + /// regardless of whether or not the call was cancelled. If a cancellation + /// does occur, the closure will be scheduled with the cancellation error; + /// otherwise, it will be scheduled with GRPC_ERROR_NONE. + /// + /// The closure will be scheduled in the following cases: + /// - If Cancel() was called prior to registering the closure, it will be + /// scheduled immediately with the cancelation error. + /// - If Cancel() is called after registering the closure, the closure will + /// be scheduled with the cancellation error. + /// - If SetNotifyOnCancel() is called again to register a new cancellation + /// closure, the previous cancellation closure will be scheduled with + /// GRPC_ERROR_NONE. + /// + /// If \a closure is NULL, then no closure will be invoked on + /// cancellation; this effectively unregisters the previously set closure. + /// However, most filters will not need to explicitly unregister their + /// callbacks, as this is done automatically when the call is destroyed. + /// Filters that schedule the cancellation closure on ExecCtx do not need + /// to take a ref on the call stack to guarantee closure liveness. This is + /// done by explicitly flushing ExecCtx after the unregistration during + /// call destruction. + void SetNotifyOnCancel(grpc_closure* closure); + + /// Indicates that the call has been cancelled. + void Cancel(grpc_error* error); + + private: + void ScheduleClosure(grpc_closure* closure, grpc_error* error); +#ifdef GRPC_TSAN_ENABLED + static void TsanClosure(void* arg, grpc_error* error); +#endif -struct grpc_call_combiner { - gpr_atm size = 0; // size_t, num closures in queue or currently executing - gpr_mpscq queue; + gpr_atm size_ = 0; // size_t, num closures in queue or currently executing + gpr_mpscq queue_; // Either 0 (if not cancelled and no cancellation closure set), // a grpc_closure* (if the lowest bit is 0), // or a grpc_error* (if the lowest bit is 1). - gpr_atm cancel_state = 0; + gpr_atm cancel_state_ = 0; #ifdef GRPC_TSAN_ENABLED // A fake ref-counted lock that is kept alive after the destruction of // grpc_call_combiner, when we are running the original closure. @@ -58,90 +121,20 @@ struct grpc_call_combiner { // callback is called. However, original_closure is free to trigger // anything on the call combiner (including destruction of grpc_call). // Thus, we need a ref-counted structure that can outlive the call combiner. - struct TsanLock - : public grpc_core::RefCounted { + struct TsanLock : public RefCounted { TsanLock() { TSAN_ANNOTATE_RWLOCK_CREATE(&taken); } ~TsanLock() { TSAN_ANNOTATE_RWLOCK_DESTROY(&taken); } - // To avoid double-locking by the same thread, we should acquire/release // the lock only when taken is false. On each acquire taken must be set to // true. std::atomic taken{false}; }; - grpc_core::RefCountedPtr tsan_lock = - grpc_core::MakeRefCounted(); - grpc_closure tsan_closure; - grpc_closure* original_closure; + RefCountedPtr tsan_lock_ = MakeRefCounted(); + grpc_closure tsan_closure_; + grpc_closure* original_closure_; #endif }; -// Assumes memory was initialized to zero. -void grpc_call_combiner_init(grpc_call_combiner* call_combiner); - -void grpc_call_combiner_destroy(grpc_call_combiner* call_combiner); - -#ifndef NDEBUG -#define GRPC_CALL_COMBINER_START(call_combiner, closure, error, reason) \ - grpc_call_combiner_start((call_combiner), (closure), (error), __FILE__, \ - __LINE__, (reason)) -#define GRPC_CALL_COMBINER_STOP(call_combiner, reason) \ - grpc_call_combiner_stop((call_combiner), __FILE__, __LINE__, (reason)) -/// Starts processing \a closure on \a call_combiner. -void grpc_call_combiner_start(grpc_call_combiner* call_combiner, - grpc_closure* closure, grpc_error* error, - const char* file, int line, const char* reason); -/// Yields the call combiner to the next closure in the queue, if any. -void grpc_call_combiner_stop(grpc_call_combiner* call_combiner, - const char* file, int line, const char* reason); -#else -#define GRPC_CALL_COMBINER_START(call_combiner, closure, error, reason) \ - grpc_call_combiner_start((call_combiner), (closure), (error), (reason)) -#define GRPC_CALL_COMBINER_STOP(call_combiner, reason) \ - grpc_call_combiner_stop((call_combiner), (reason)) -/// Starts processing \a closure on \a call_combiner. -void grpc_call_combiner_start(grpc_call_combiner* call_combiner, - grpc_closure* closure, grpc_error* error, - const char* reason); -/// Yields the call combiner to the next closure in the queue, if any. -void grpc_call_combiner_stop(grpc_call_combiner* call_combiner, - const char* reason); -#endif - -/// Registers \a closure to be invoked by \a call_combiner when -/// grpc_call_combiner_cancel() is called. -/// -/// Once a closure is registered, it will always be scheduled exactly -/// once; this allows the closure to hold references that will be freed -/// regardless of whether or not the call was cancelled. If a cancellation -/// does occur, the closure will be scheduled with the cancellation error; -/// otherwise, it will be scheduled with GRPC_ERROR_NONE. -/// -/// The closure will be scheduled in the following cases: -/// - If grpc_call_combiner_cancel() was called prior to registering the -/// closure, it will be scheduled immediately with the cancelation error. -/// - If grpc_call_combiner_cancel() is called after registering the -/// closure, the closure will be scheduled with the cancellation error. -/// - If grpc_call_combiner_set_notify_on_cancel() is called again to -/// register a new cancellation closure, the previous cancellation -/// closure will be scheduled with GRPC_ERROR_NONE. -/// -/// If \a closure is NULL, then no closure will be invoked on -/// cancellation; this effectively unregisters the previously set closure. -/// However, most filters will not need to explicitly unregister their -/// callbacks, as this is done automatically when the call is destroyed. Filters -/// that schedule the cancellation closure on ExecCtx do not need to take a ref -/// on the call stack to guarantee closure liveness. This is done by explicitly -/// flushing ExecCtx after the unregistration during call destruction. -void grpc_call_combiner_set_notify_on_cancel(grpc_call_combiner* call_combiner, - grpc_closure* closure); - -/// Indicates that the call has been cancelled. -void grpc_call_combiner_cancel(grpc_call_combiner* call_combiner, - grpc_error* error); - -namespace grpc_core { - // Helper for running a list of closures in a call combiner. // // Each callback running in the call combiner will eventually be @@ -166,7 +159,7 @@ class CallCombinerClosureList { // scheduled via GRPC_CLOSURE_SCHED(), which will eventually result in // yielding the call combiner. If the list is empty, then the call // combiner will be yielded immediately. - void RunClosures(grpc_call_combiner* call_combiner) { + void RunClosures(CallCombiner* call_combiner) { if (closures_.empty()) { GRPC_CALL_COMBINER_STOP(call_combiner, "no closures to schedule"); return; @@ -176,7 +169,7 @@ class CallCombinerClosureList { GRPC_CALL_COMBINER_START(call_combiner, closure.closure, closure.error, closure.reason); } - if (grpc_call_combiner_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_call_combiner_trace)) { gpr_log(GPR_INFO, "CallCombinerClosureList executing closure while already " "holding call_combiner %p: closure=%p error=%s reason=%s", @@ -190,7 +183,7 @@ class CallCombinerClosureList { // Runs all closures in the call combiner, but does NOT yield the call // combiner. All closures will be scheduled via GRPC_CALL_COMBINER_START(). - void RunClosuresWithoutYielding(grpc_call_combiner* call_combiner) { + void RunClosuresWithoutYielding(CallCombiner* call_combiner) { for (size_t i = 0; i < closures_.size(); ++i) { auto& closure = closures_[i]; GRPC_CALL_COMBINER_START(call_combiner, closure.closure, closure.error, diff --git a/src/core/lib/iomgr/combiner.h b/src/core/lib/iomgr/combiner.h index 3c947bf9d64..b9274216993 100644 --- a/src/core/lib/iomgr/combiner.h +++ b/src/core/lib/iomgr/combiner.h @@ -31,7 +31,7 @@ // Provides serialized access to some resource. // Each action queued on a combiner is executed serially in a borrowed thread. // The actual thread executing actions may change over time (but there will only -// every be one at a time). +// ever be one at a time). // Initialize the lock, with an optional workqueue to shift load to when // necessary diff --git a/src/core/lib/iomgr/endpoint_pair_windows.cc b/src/core/lib/iomgr/endpoint_pair_windows.cc index 177331d6812..9962809a27b 100644 --- a/src/core/lib/iomgr/endpoint_pair_windows.cc +++ b/src/core/lib/iomgr/endpoint_pair_windows.cc @@ -41,7 +41,7 @@ static void create_sockets(SOCKET sv[2]) { int addr_len = sizeof(addr); lst_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, - WSA_FLAG_OVERLAPPED); + grpc_get_default_wsa_socket_flags()); GPR_ASSERT(lst_sock != INVALID_SOCKET); memset(&addr, 0, sizeof(addr)); @@ -54,7 +54,7 @@ static void create_sockets(SOCKET sv[2]) { SOCKET_ERROR); cli_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, - WSA_FLAG_OVERLAPPED); + grpc_get_default_wsa_socket_flags()); GPR_ASSERT(cli_sock != INVALID_SOCKET); GPR_ASSERT(WSAConnect(cli_sock, (grpc_sockaddr*)&addr, addr_len, NULL, NULL, diff --git a/src/core/lib/iomgr/error.h b/src/core/lib/iomgr/error.h index fcc6f0761b3..7b04888e9ec 100644 --- a/src/core/lib/iomgr/error.h +++ b/src/core/lib/iomgr/error.h @@ -30,6 +30,7 @@ #include #include "src/core/lib/debug/trace.h" +#include "src/core/lib/gprpp/inlined_vector.h" /// Opaque representation of an error. /// See https://github.com/grpc/grpc/blob/master/doc/core/grpc-error.md for a @@ -165,6 +166,9 @@ grpc_error* grpc_error_create(const char* file, int line, grpc_error_create(__FILE__, __LINE__, grpc_slice_from_copied_string(desc), \ errs, count) +#define GRPC_ERROR_CREATE_FROM_VECTOR(desc, error_list) \ + grpc_error_create_from_vector(__FILE__, __LINE__, desc, error_list) + #ifndef NDEBUG grpc_error* grpc_error_do_ref(grpc_error* err, const char* file, int line); void grpc_error_do_unref(grpc_error* err, const char* file, int line); @@ -193,6 +197,25 @@ inline void grpc_error_unref(grpc_error* err) { #define GRPC_ERROR_UNREF(err) grpc_error_unref(err) #endif +// Consumes all the errors in the vector and forms a referencing error from +// them. If the vector is empty, return GRPC_ERROR_NONE. +template +static grpc_error* grpc_error_create_from_vector( + const char* file, int line, const char* desc, + grpc_core::InlinedVector* error_list) { + grpc_error* error = GRPC_ERROR_NONE; + if (error_list->size() != 0) { + error = grpc_error_create(file, line, grpc_slice_from_static_string(desc), + error_list->data(), error_list->size()); + // Remove refs to all errors in error_list. + for (size_t i = 0; i < error_list->size(); i++) { + GRPC_ERROR_UNREF((*error_list)[i]); + } + error_list->clear(); + } + return error; +} + grpc_error* grpc_error_set_int(grpc_error* src, grpc_error_ints which, intptr_t value) GRPC_MUST_USE_RESULT; /// It is an error to pass nullptr as `p`. Caller should allocate a dummy diff --git a/src/core/lib/iomgr/error_internal.h b/src/core/lib/iomgr/error_internal.h index 80273960198..7b0cbd6d98f 100644 --- a/src/core/lib/iomgr/error_internal.h +++ b/src/core/lib/iomgr/error_internal.h @@ -49,7 +49,7 @@ struct grpc_error { uint8_t strs[GRPC_ERROR_STR_MAX]; uint8_t times[GRPC_ERROR_TIME_MAX]; // The child errors are stored in the arena, but are effectively a linked list - // structure, since they are contained withing grpc_linked_error objects. + // structure, since they are contained within grpc_linked_error objects. uint8_t first_err; uint8_t last_err; // The arena is dynamically reallocated with a grow factor of 1.5. diff --git a/src/core/lib/iomgr/ev_epoll1_linux.cc b/src/core/lib/iomgr/ev_epoll1_linux.cc index c2165341964..0c357dd2758 100644 --- a/src/core/lib/iomgr/ev_epoll1_linux.cc +++ b/src/core/lib/iomgr/ev_epoll1_linux.cc @@ -351,7 +351,7 @@ static grpc_fd* fd_create(int fd, const char* name, bool track_err) { grpc_iomgr_register_object(&new_fd->iomgr_object, fd_name); fork_fd_list_add_grpc_fd(new_fd); #ifndef NDEBUG - if (grpc_trace_fd_refcount.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_fd_refcount)) { gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, new_fd, fd_name); } #endif @@ -383,6 +383,13 @@ static void fd_shutdown_internal(grpc_fd* fd, grpc_error* why, if (fd->read_closure->SetShutdown(GRPC_ERROR_REF(why))) { if (!releasing_fd) { shutdown(fd->fd, SHUT_RDWR); + } else { + /* we need a dummy event for earlier linux versions. */ + epoll_event dummy_event; + if (epoll_ctl(g_epoll_set.epfd, EPOLL_CTL_DEL, fd->fd, &dummy_event) != + 0) { + gpr_log(GPR_ERROR, "epoll_ctl failed: %s", strerror(errno)); + } } fd->write_closure->SetShutdown(GRPC_ERROR_REF(why)); fd->error_closure->SetShutdown(GRPC_ERROR_REF(why)); @@ -724,7 +731,7 @@ static grpc_error* do_epoll_wait(grpc_pollset* ps, grpc_millis deadline) { GRPC_STATS_INC_POLL_EVENTS_RETURNED(r); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "ps: %p poll got %d events", ps, r); } @@ -744,7 +751,7 @@ static bool begin_worker(grpc_pollset* pollset, grpc_pollset_worker* worker, worker->schedule_on_end_work = (grpc_closure_list)GRPC_CLOSURE_LIST_INIT; pollset->begin_refs++; - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p BEGIN_STARTS:%p", pollset, worker); } @@ -763,7 +770,7 @@ static bool begin_worker(grpc_pollset* pollset, grpc_pollset_worker* worker, retry_lock_neighborhood: gpr_mu_lock(&neighborhood->mu); gpr_mu_lock(&pollset->mu); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p BEGIN_REORG:%p kick_state=%s is_reassigning=%d", pollset, worker, kick_state_string(worker->state), is_reassigning); @@ -815,7 +822,7 @@ static bool begin_worker(grpc_pollset* pollset, grpc_pollset_worker* worker, worker->initialized_cv = true; gpr_cv_init(&worker->cv); while (worker->state == UNKICKED && !pollset->shutting_down) { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p BEGIN_WAIT:%p kick_state=%s shutdown=%d", pollset, worker, kick_state_string(worker->state), pollset->shutting_down); @@ -832,7 +839,7 @@ static bool begin_worker(grpc_pollset* pollset, grpc_pollset_worker* worker, grpc_core::ExecCtx::Get()->InvalidateNow(); } - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p BEGIN_DONE:%p kick_state=%s shutdown=%d " "kicked_without_poller: %d", @@ -875,7 +882,7 @@ static bool check_neighborhood_for_available_poller( case UNKICKED: if (gpr_atm_no_barrier_cas(&g_active_poller, 0, (gpr_atm)inspect_worker)) { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, " .. choose next poller to be %p", inspect_worker); } @@ -886,7 +893,7 @@ static bool check_neighborhood_for_available_poller( gpr_cv_signal(&inspect_worker->cv); } } else { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, " .. beaten to choose next poller"); } } @@ -904,7 +911,7 @@ static bool check_neighborhood_for_available_poller( } while (!found_worker && inspect_worker != inspect->root_worker); } if (!found_worker) { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, " .. mark pollset %p inactive", inspect); } inspect->seen_inactive = true; @@ -924,7 +931,7 @@ static bool check_neighborhood_for_available_poller( static void end_worker(grpc_pollset* pollset, grpc_pollset_worker* worker, grpc_pollset_worker** worker_hdl) { GPR_TIMER_SCOPE("end_worker", 0); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p END_WORKER:%p", pollset, worker); } if (worker_hdl != nullptr) *worker_hdl = nullptr; @@ -934,7 +941,7 @@ static void end_worker(grpc_pollset* pollset, grpc_pollset_worker* worker, grpc_core::ExecCtx::Get()->closure_list()); if (gpr_atm_no_barrier_load(&g_active_poller) == (gpr_atm)worker) { if (worker->next != worker && worker->next->state == UNKICKED) { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, " .. choose next poller to be peer %p", worker); } GPR_ASSERT(worker->next->initialized_cv); @@ -986,7 +993,7 @@ static void end_worker(grpc_pollset* pollset, grpc_pollset_worker* worker, if (worker->initialized_cv) { gpr_cv_destroy(&worker->cv); } - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, " .. remove worker"); } if (EMPTIED == worker_remove(pollset, worker)) { @@ -1024,7 +1031,7 @@ static grpc_error* pollset_work(grpc_pollset* ps, process the pending epoll events. The reason for decoupling do_epoll_wait and process_epoll_events is to - better distrubute the work (i.e handling epoll events) across multiple + better distribute the work (i.e handling epoll events) across multiple threads process_epoll_events() returns very quickly: It just queues the work on @@ -1055,7 +1062,7 @@ static grpc_error* pollset_kick(grpc_pollset* pollset, GPR_TIMER_SCOPE("pollset_kick", 0); GRPC_STATS_INC_POLLSET_KICK(); grpc_error* ret_err = GRPC_ERROR_NONE; - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_strvec log; gpr_strvec_init(&log); char* tmp; @@ -1088,7 +1095,7 @@ static grpc_error* pollset_kick(grpc_pollset* pollset, if (root_worker == nullptr) { GRPC_STATS_INC_POLLSET_KICKED_WITHOUT_POLLER(); pollset->kicked_without_poller = true; - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, " .. kicked_without_poller"); } goto done; @@ -1096,14 +1103,14 @@ static grpc_error* pollset_kick(grpc_pollset* pollset, grpc_pollset_worker* next_worker = root_worker->next; if (root_worker->state == KICKED) { GRPC_STATS_INC_POLLSET_KICKED_AGAIN(); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, " .. already kicked %p", root_worker); } SET_KICK_STATE(root_worker, KICKED); goto done; } else if (next_worker->state == KICKED) { GRPC_STATS_INC_POLLSET_KICKED_AGAIN(); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, " .. already kicked %p", next_worker); } SET_KICK_STATE(next_worker, KICKED); @@ -1114,7 +1121,7 @@ static grpc_error* pollset_kick(grpc_pollset* pollset, root_worker == (grpc_pollset_worker*)gpr_atm_no_barrier_load( &g_active_poller)) { GRPC_STATS_INC_POLLSET_KICK_WAKEUP_FD(); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, " .. kicked %p", root_worker); } SET_KICK_STATE(root_worker, KICKED); @@ -1122,7 +1129,7 @@ static grpc_error* pollset_kick(grpc_pollset* pollset, goto done; } else if (next_worker->state == UNKICKED) { GRPC_STATS_INC_POLLSET_KICK_WAKEUP_CV(); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, " .. kicked %p", next_worker); } GPR_ASSERT(next_worker->initialized_cv); @@ -1131,7 +1138,7 @@ static grpc_error* pollset_kick(grpc_pollset* pollset, goto done; } else if (next_worker->state == DESIGNATED_POLLER) { if (root_worker->state != DESIGNATED_POLLER) { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log( GPR_INFO, " .. kicked root non-poller %p (initialized_cv=%d) (poller=%p)", @@ -1145,7 +1152,7 @@ static grpc_error* pollset_kick(grpc_pollset* pollset, goto done; } else { GRPC_STATS_INC_POLLSET_KICK_WAKEUP_FD(); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, " .. non-root poller %p (root=%p)", next_worker, root_worker); } @@ -1161,7 +1168,7 @@ static grpc_error* pollset_kick(grpc_pollset* pollset, } } else { GRPC_STATS_INC_POLLSET_KICK_OWN_THREAD(); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, " .. kicked while waking up"); } goto done; @@ -1171,14 +1178,14 @@ static grpc_error* pollset_kick(grpc_pollset* pollset, } if (specific_worker->state == KICKED) { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, " .. specific worker already kicked"); } goto done; } else if (gpr_tls_get(&g_current_thread_worker) == (intptr_t)specific_worker) { GRPC_STATS_INC_POLLSET_KICK_OWN_THREAD(); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, " .. mark %p kicked", specific_worker); } SET_KICK_STATE(specific_worker, KICKED); @@ -1186,7 +1193,7 @@ static grpc_error* pollset_kick(grpc_pollset* pollset, } else if (specific_worker == (grpc_pollset_worker*)gpr_atm_no_barrier_load(&g_active_poller)) { GRPC_STATS_INC_POLLSET_KICK_WAKEUP_FD(); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, " .. kick active poller"); } SET_KICK_STATE(specific_worker, KICKED); @@ -1194,7 +1201,7 @@ static grpc_error* pollset_kick(grpc_pollset* pollset, goto done; } else if (specific_worker->initialized_cv) { GRPC_STATS_INC_POLLSET_KICK_WAKEUP_CV(); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, " .. kick waiting worker"); } SET_KICK_STATE(specific_worker, KICKED); @@ -1202,7 +1209,7 @@ static grpc_error* pollset_kick(grpc_pollset* pollset, goto done; } else { GRPC_STATS_INC_POLLSET_KICKED_AGAIN(); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, " .. kick non-waiting worker"); } SET_KICK_STATE(specific_worker, KICKED); diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc index c387f8359a0..08116b3ab53 100644 --- a/src/core/lib/iomgr/ev_epollex_linux.cc +++ b/src/core/lib/iomgr/ev_epollex_linux.cc @@ -164,7 +164,7 @@ struct grpc_fd { gpr_asprintf(&fd_name, "%s fd=%d", name, fd); grpc_iomgr_register_object(&iomgr_object, fd_name); #ifndef NDEBUG - if (grpc_trace_fd_refcount.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_fd_refcount)) { gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, this, fd_name); } #endif @@ -335,7 +335,7 @@ static gpr_mu fd_freelist_mu; #define UNREF_BY(fd, n, reason) unref_by(fd, n, reason, __FILE__, __LINE__) static void ref_by(grpc_fd* fd, int n, const char* reason, const char* file, int line) { - if (grpc_trace_fd_refcount.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_fd_refcount)) { gpr_log(GPR_DEBUG, "FD %d %p ref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]", fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst), @@ -364,7 +364,7 @@ static void fd_destroy(void* arg, grpc_error* error) { #ifndef NDEBUG static void unref_by(grpc_fd* fd, int n, const char* reason, const char* file, int line) { - if (grpc_trace_fd_refcount.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_fd_refcount)) { gpr_log(GPR_DEBUG, "FD %d %p unref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]", fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst), @@ -586,7 +586,7 @@ static grpc_error* pollable_create(pollable_type type, pollable** p) { static pollable* pollable_ref(pollable* p) { #else static pollable* pollable_ref(pollable* p, int line, const char* reason) { - if (grpc_trace_pollable_refcount.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_pollable_refcount)) { int r = static_cast gpr_atm_no_barrier_load(&p->refs.count); gpr_log(__FILE__, line, GPR_LOG_SEVERITY_DEBUG, "POLLABLE:%p ref %d->%d %s", p, r, r + 1, reason); @@ -601,7 +601,7 @@ static void pollable_unref(pollable* p) { #else static void pollable_unref(pollable* p, int line, const char* reason) { if (p == nullptr) return; - if (grpc_trace_pollable_refcount.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_pollable_refcount)) { int r = static_cast gpr_atm_no_barrier_load(&p->refs.count); gpr_log(__FILE__, line, GPR_LOG_SEVERITY_DEBUG, "POLLABLE:%p unref %d->%d %s", p, r, r - 1, reason); @@ -621,7 +621,7 @@ static grpc_error* pollable_add_fd(pollable* p, grpc_fd* fd) { grpc_error* error = GRPC_ERROR_NONE; static const char* err_desc = "pollable_add_fd"; const int epfd = p->epfd; - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "add fd %p (%d) to pollable %p", fd, fd->fd, p); } @@ -669,7 +669,7 @@ static void pollset_global_shutdown(void) { /* pollset->mu must be held while calling this function */ static void pollset_maybe_finish_shutdown(grpc_pollset* pollset) { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p (pollable:%p) maybe_finish_shutdown sc=%p (target:!NULL) " "rw=%p (target:NULL) cpsc=%d (target:0)", @@ -694,14 +694,14 @@ static grpc_error* kick_one_worker(grpc_pollset_worker* specific_worker) { grpc_core::MutexLock lock(&p->mu); GPR_ASSERT(specific_worker != nullptr); if (specific_worker->kicked) { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p kicked_specific_but_already_kicked", p); } GRPC_STATS_INC_POLLSET_KICKED_AGAIN(); return GRPC_ERROR_NONE; } if (gpr_tls_get(&g_current_thread_worker) == (intptr_t)specific_worker) { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p kicked_specific_but_awake", p); } GRPC_STATS_INC_POLLSET_KICK_OWN_THREAD(); @@ -710,7 +710,7 @@ static grpc_error* kick_one_worker(grpc_pollset_worker* specific_worker) { } if (specific_worker == p->root_worker) { GRPC_STATS_INC_POLLSET_KICK_WAKEUP_FD(); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p kicked_specific_via_wakeup_fd", p); } specific_worker->kicked = true; @@ -719,7 +719,7 @@ static grpc_error* kick_one_worker(grpc_pollset_worker* specific_worker) { } if (specific_worker->initialized_cv) { GRPC_STATS_INC_POLLSET_KICK_WAKEUP_CV(); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p kicked_specific_via_cv", p); } specific_worker->kicked = true; @@ -735,7 +735,7 @@ static grpc_error* pollset_kick(grpc_pollset* pollset, grpc_pollset_worker* specific_worker) { GPR_TIMER_SCOPE("pollset_kick", 0); GRPC_STATS_INC_POLLSET_KICK(); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p kick %p tls_pollset=%p tls_worker=%p pollset.root_worker=%p", pollset, specific_worker, @@ -745,7 +745,7 @@ static grpc_error* pollset_kick(grpc_pollset* pollset, if (specific_worker == nullptr) { if (gpr_tls_get(&g_current_thread_pollset) != (intptr_t)pollset) { if (pollset->root_worker == nullptr) { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p kicked_any_without_poller", pollset); } GRPC_STATS_INC_POLLSET_KICKED_WITHOUT_POLLER(); @@ -771,7 +771,7 @@ static grpc_error* pollset_kick(grpc_pollset* pollset, pollset->root_worker->links[PWLINK_POLLSET].next); } } else { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p kicked_any_but_awake", pollset); } GRPC_STATS_INC_POLLSET_KICK_OWN_THREAD(); @@ -891,7 +891,7 @@ static grpc_error* pollable_process_events(grpc_pollset* pollset, struct epoll_event* ev = &pollable_obj->events[n]; void* data_ptr = ev->data.ptr; if (1 & (intptr_t)data_ptr) { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p got pollset_wakeup %p", pollset, data_ptr); } append_error(&error, @@ -909,7 +909,7 @@ static grpc_error* pollable_process_events(grpc_pollset* pollset, bool write_ev = (ev->events & EPOLLOUT) != 0; bool err_fallback = error && !track_err; - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p got fd %p: cancel=%d read=%d " "write=%d", @@ -941,7 +941,7 @@ static grpc_error* pollable_epoll(pollable* p, grpc_millis deadline) { GPR_TIMER_SCOPE("pollable_epoll", 0); int timeout = poll_deadline_to_millis_timeout(deadline); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { char* desc = pollable_desc(p); gpr_log(GPR_INFO, "POLLABLE:%p[%s] poll for %dms", p, desc, timeout); gpr_free(desc); @@ -961,7 +961,7 @@ static grpc_error* pollable_epoll(pollable* p, grpc_millis deadline) { if (r < 0) return GRPC_OS_ERROR(errno, "epoll_wait"); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "POLLABLE:%p got %d events", p, r); } @@ -1031,7 +1031,7 @@ static bool begin_worker(grpc_pollset* pollset, grpc_pollset_worker* worker, worker->initialized_cv = true; gpr_cv_init(&worker->cv); gpr_mu_unlock(&pollset->mu); - if (grpc_polling_trace.enabled() && + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace) && worker->pollable_obj->root_worker != worker) { gpr_log(GPR_INFO, "PS:%p wait %p w=%p for %dms", pollset, worker->pollable_obj, worker, @@ -1040,18 +1040,18 @@ static bool begin_worker(grpc_pollset* pollset, grpc_pollset_worker* worker, while (do_poll && worker->pollable_obj->root_worker != worker) { if (gpr_cv_wait(&worker->cv, &worker->pollable_obj->mu, grpc_millis_to_timespec(deadline, GPR_CLOCK_REALTIME))) { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p timeout_wait %p w=%p", pollset, worker->pollable_obj, worker); } do_poll = false; } else if (worker->kicked) { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p wakeup %p w=%p", pollset, worker->pollable_obj, worker); } do_poll = false; - } else if (grpc_polling_trace.enabled() && + } else if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace) && worker->pollable_obj->root_worker != worker) { gpr_log(GPR_INFO, "PS:%p spurious_wakeup %p w=%p", pollset, worker->pollable_obj, worker); @@ -1124,7 +1124,7 @@ static grpc_error* pollset_work(grpc_pollset* pollset, #ifndef NDEBUG WORKER_PTR->originator = gettid(); #endif - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p work hdl=%p worker=%p now=%" PRId64 " deadline=%" PRId64 " kwp=%d pollable=%p", @@ -1165,7 +1165,7 @@ static grpc_error* pollset_transition_pollable_from_empty_to_fd_locked( grpc_pollset* pollset, grpc_fd* fd) { static const char* err_desc = "pollset_transition_pollable_from_empty_to_fd"; grpc_error* error = GRPC_ERROR_NONE; - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p add fd %p (%d); transition pollable from empty to fd", pollset, fd, fd->fd); @@ -1181,7 +1181,7 @@ static grpc_error* pollset_transition_pollable_from_fd_to_multi_locked( grpc_pollset* pollset, grpc_fd* and_add_fd) { static const char* err_desc = "pollset_transition_pollable_from_fd_to_multi"; grpc_error* error = GRPC_ERROR_NONE; - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log( GPR_INFO, "PS:%p add fd %p (%d); transition pollable from fd %p to multipoller", @@ -1253,7 +1253,7 @@ static grpc_error* pollset_as_multipollable_locked(grpc_pollset* pollset, error = pollable_create(PO_MULTI, &pollset->active_pollable); /* Any workers currently polling on this pollset must now be woked up so * that they can pick up the new active_pollable */ - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PS:%p active pollable transition from empty to multi", pollset); @@ -1357,7 +1357,7 @@ static void pollset_set_unref(grpc_pollset_set* pss) { static void pollset_set_add_fd(grpc_pollset_set* pss, grpc_fd* fd) { GPR_TIMER_SCOPE("pollset_set_add_fd", 0); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PSS:%p: add fd %p (%d)", pss, fd, fd->fd); } grpc_error* error = GRPC_ERROR_NONE; @@ -1381,7 +1381,7 @@ static void pollset_set_add_fd(grpc_pollset_set* pss, grpc_fd* fd) { static void pollset_set_del_fd(grpc_pollset_set* pss, grpc_fd* fd) { GPR_TIMER_SCOPE("pollset_set_del_fd", 0); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PSS:%p: del fd %p", pss, fd); } pss = pss_lock_adam(pss); @@ -1402,7 +1402,7 @@ static void pollset_set_del_fd(grpc_pollset_set* pss, grpc_fd* fd) { static void pollset_set_del_pollset(grpc_pollset_set* pss, grpc_pollset* ps) { GPR_TIMER_SCOPE("pollset_set_del_pollset", 0); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PSS:%p: del pollset %p", pss, ps); } pss = pss_lock_adam(pss); @@ -1454,7 +1454,7 @@ static grpc_error* add_fds_to_pollsets(grpc_fd** fds, size_t fd_count, static void pollset_set_add_pollset(grpc_pollset_set* pss, grpc_pollset* ps) { GPR_TIMER_SCOPE("pollset_set_add_pollset", 0); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PSS:%p: add pollset %p", pss, ps); } grpc_error* error = GRPC_ERROR_NONE; @@ -1491,7 +1491,7 @@ static void pollset_set_add_pollset(grpc_pollset_set* pss, grpc_pollset* ps) { static void pollset_set_add_pollset_set(grpc_pollset_set* a, grpc_pollset_set* b) { GPR_TIMER_SCOPE("pollset_set_add_pollset_set", 0); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PSS: merge (%p, %p)", a, b); } grpc_error* error = GRPC_ERROR_NONE; @@ -1525,7 +1525,7 @@ static void pollset_set_add_pollset_set(grpc_pollset_set* a, if (b_size > a_size) { GPR_SWAP(grpc_pollset_set*, a, b); } - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "PSS: parent %p to %p", b, a); } gpr_ref(&a->refs); diff --git a/src/core/lib/iomgr/ev_poll_posix.cc b/src/core/lib/iomgr/ev_poll_posix.cc index 0c95cb75c6d..cee6dcbe530 100644 --- a/src/core/lib/iomgr/ev_poll_posix.cc +++ b/src/core/lib/iomgr/ev_poll_posix.cc @@ -316,7 +316,7 @@ static void fork_fd_list_add_wakeup_fd(grpc_cached_wakeup_fd* fd) { #define UNREF_BY(fd, n, reason) unref_by(fd, n, reason, __FILE__, __LINE__) static void ref_by(grpc_fd* fd, int n, const char* reason, const char* file, int line) { - if (grpc_trace_fd_refcount.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_fd_refcount)) { gpr_log(GPR_DEBUG, "FD %d %p ref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]", fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst), @@ -333,7 +333,7 @@ static void ref_by(grpc_fd* fd, int n) { #ifndef NDEBUG static void unref_by(grpc_fd* fd, int n, const char* reason, const char* file, int line) { - if (grpc_trace_fd_refcount.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_fd_refcount)) { gpr_log(GPR_DEBUG, "FD %d %p unref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]", fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst), @@ -561,7 +561,7 @@ static void fd_notify_on_write(grpc_fd* fd, grpc_closure* closure) { } static void fd_notify_on_error(grpc_fd* fd, grpc_closure* closure) { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_ERROR, "Polling engine does not support tracking errors."); } GRPC_CLOSURE_SCHED(closure, GRPC_ERROR_CANCELLED); @@ -580,7 +580,7 @@ static void fd_set_writable(grpc_fd* fd) { } static void fd_set_error(grpc_fd* fd) { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_ERROR, "Polling engine does not support tracking errors."); } } @@ -1012,7 +1012,7 @@ static grpc_error* pollset_work(grpc_pollset* pollset, r = grpc_poll_function(pfds, pfd_count, timeout); GRPC_SCHEDULING_END_BLOCKING_REGION; - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "%p poll=%d", pollset, r); } @@ -1036,7 +1036,7 @@ static grpc_error* pollset_work(grpc_pollset* pollset, } } else { if (pfds[0].revents & POLLIN_CHECK) { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "%p: got_wakeup", pollset); } work_combine_error( @@ -1046,7 +1046,7 @@ static grpc_error* pollset_work(grpc_pollset* pollset, if (watchers[i].fd == nullptr) { fd_end_poll(&watchers[i], 0, 0); } else { - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_INFO, "%p got_event: %d r:%d w:%d [%d]", pollset, pfds[i].fd, (pfds[i].revents & POLLIN_CHECK) != 0, (pfds[i].revents & POLLOUT_CHECK) != 0, pfds[i].revents); diff --git a/src/core/lib/iomgr/ev_posix.cc b/src/core/lib/iomgr/ev_posix.cc index 898686b06c3..ddafb7b5539 100644 --- a/src/core/lib/iomgr/ev_posix.cc +++ b/src/core/lib/iomgr/ev_posix.cc @@ -31,13 +31,19 @@ #include #include "src/core/lib/debug/trace.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/useful.h" +#include "src/core/lib/gprpp/global_config.h" #include "src/core/lib/iomgr/ev_epoll1_linux.h" #include "src/core/lib/iomgr/ev_epollex_linux.h" #include "src/core/lib/iomgr/ev_poll_posix.h" #include "src/core/lib/iomgr/internal_errqueue.h" +GPR_GLOBAL_CONFIG_DEFINE_STRING( + grpc_poll_strategy, "all", + "Declares which polling engines to try when starting gRPC. " + "This is a comma-separated list of engines, which are tried in priority " + "order first -> last.") + grpc_core::TraceFlag grpc_polling_trace(false, "polling"); /* Disabled by default */ @@ -46,16 +52,15 @@ grpc_core::TraceFlag grpc_fd_trace(false, "fd_trace"); grpc_core::DebugOnlyTraceFlag grpc_trace_fd_refcount(false, "fd_refcount"); grpc_core::DebugOnlyTraceFlag grpc_polling_api_trace(false, "polling_api"); -#ifndef NDEBUG - // Polling API trace only enabled in debug builds +#ifndef NDEBUG #define GRPC_POLLING_API_TRACE(format, ...) \ - if (grpc_polling_api_trace.enabled()) { \ + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_api_trace)) { \ gpr_log(GPR_INFO, "(polling-api) " format, __VA_ARGS__); \ } #else #define GRPC_POLLING_API_TRACE(...) -#endif +#endif // NDEBUG /** Default poll() function - a pointer so that it can be overridden by some * tests */ @@ -66,7 +71,7 @@ int aix_poll(struct pollfd fds[], nfds_t nfds, int timeout) { return poll(fds, nfds, timeout); } grpc_poll_function_type grpc_poll_function = aix_poll; -#endif +#endif // GPR_AIX grpc_wakeup_fd grpc_global_wakeup_fd; @@ -205,14 +210,11 @@ void grpc_register_event_engine_factory(const char* name, const char* grpc_get_poll_strategy_name() { return g_poll_strategy_name; } void grpc_event_engine_init(void) { - char* s = gpr_getenv("GRPC_POLL_STRATEGY"); - if (s == nullptr) { - s = gpr_strdup("all"); - } + grpc_core::UniquePtr value = GPR_GLOBAL_CONFIG_GET(grpc_poll_strategy); char** strings = nullptr; size_t nstrings = 0; - split(s, &strings, &nstrings); + split(value.get(), &strings, &nstrings); for (size_t i = 0; g_event_engine == nullptr && i < nstrings; i++) { try_engine(strings[i]); @@ -224,10 +226,10 @@ void grpc_event_engine_init(void) { gpr_free(strings); if (g_event_engine == nullptr) { - gpr_log(GPR_ERROR, "No event engine could be initialized from %s", s); + gpr_log(GPR_ERROR, "No event engine could be initialized from %s", + value.get()); abort(); } - gpr_free(s); } void grpc_event_engine_shutdown(void) { diff --git a/src/core/lib/iomgr/ev_posix.h b/src/core/lib/iomgr/ev_posix.h index 699173fe255..30bb5e40faf 100644 --- a/src/core/lib/iomgr/ev_posix.h +++ b/src/core/lib/iomgr/ev_posix.h @@ -24,16 +24,19 @@ #include #include "src/core/lib/debug/trace.h" +#include "src/core/lib/gprpp/global_config.h" #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/iomgr/pollset_set.h" #include "src/core/lib/iomgr/wakeup_fd_posix.h" +GPR_GLOBAL_CONFIG_DECLARE_STRING(grpc_poll_strategy); + extern grpc_core::TraceFlag grpc_fd_trace; /* Disabled by default */ extern grpc_core::TraceFlag grpc_polling_trace; /* Disabled by default */ #define GRPC_FD_TRACE(format, ...) \ - if (grpc_fd_trace.enabled()) { \ + if (GRPC_TRACE_FLAG_ENABLED(grpc_fd_trace)) { \ gpr_log(GPR_INFO, "(fd-trace) " format, __VA_ARGS__); \ } diff --git a/src/core/lib/iomgr/executor.cc b/src/core/lib/iomgr/executor.cc index 47836acacc0..8adc0902bd1 100644 --- a/src/core/lib/iomgr/executor.cc +++ b/src/core/lib/iomgr/executor.cc @@ -36,15 +36,19 @@ #define MAX_DEPTH 2 -#define EXECUTOR_TRACE(format, ...) \ - if (executor_trace.enabled()) { \ - gpr_log(GPR_INFO, "EXECUTOR " format, __VA_ARGS__); \ - } - -#define EXECUTOR_TRACE0(str) \ - if (executor_trace.enabled()) { \ - gpr_log(GPR_INFO, "EXECUTOR " str); \ - } +#define EXECUTOR_TRACE(format, ...) \ + do { \ + if (GRPC_TRACE_FLAG_ENABLED(executor_trace)) { \ + gpr_log(GPR_INFO, "EXECUTOR " format, __VA_ARGS__); \ + } \ + } while (0) + +#define EXECUTOR_TRACE0(str) \ + do { \ + if (GRPC_TRACE_FLAG_ENABLED(executor_trace)) { \ + gpr_log(GPR_INFO, "EXECUTOR " str); \ + } \ + } while (0) namespace grpc_core { namespace { diff --git a/src/core/lib/iomgr/fork_posix.cc b/src/core/lib/iomgr/fork_posix.cc index 7f8fb7e828b..629b08162fb 100644 --- a/src/core/lib/iomgr/fork_posix.cc +++ b/src/core/lib/iomgr/fork_posix.cc @@ -28,7 +28,6 @@ #include #include -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gprpp/fork.h" #include "src/core/lib/gprpp/thd.h" #include "src/core/lib/iomgr/ev_posix.h" diff --git a/src/core/lib/iomgr/internal_errqueue.cc b/src/core/lib/iomgr/internal_errqueue.cc index 4e2bfe3ccd5..b68c66b7575 100644 --- a/src/core/lib/iomgr/internal_errqueue.cc +++ b/src/core/lib/iomgr/internal_errqueue.cc @@ -36,7 +36,7 @@ static bool errqueue_supported = false; bool kernel_supports_errqueue() { return errqueue_supported; } void grpc_errqueue_init() { -/* Both-compile time and run-time linux kernel versions should be atleast 4.0.0 +/* Both-compile time and run-time linux kernel versions should be at least 4.0.0 */ #ifdef GRPC_LINUX_ERRQUEUE struct utsname buffer; diff --git a/src/core/lib/iomgr/iomgr.cc b/src/core/lib/iomgr/iomgr.cc index 0fbfcfce04f..b86aa6f2d76 100644 --- a/src/core/lib/iomgr/iomgr.cc +++ b/src/core/lib/iomgr/iomgr.cc @@ -29,9 +29,9 @@ #include #include -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/useful.h" +#include "src/core/lib/gprpp/global_config.h" #include "src/core/lib/gprpp/thd.h" #include "src/core/lib/iomgr/buffer_list.h" #include "src/core/lib/iomgr/exec_ctx.h" @@ -41,6 +41,10 @@ #include "src/core/lib/iomgr/timer.h" #include "src/core/lib/iomgr/timer_manager.h" +GPR_GLOBAL_CONFIG_DEFINE_BOOL(grpc_abort_on_leaks, false, + "A debugging aid to cause a call to abort() when " + "gRPC objects are leaked past grpc_shutdown()"); + static gpr_mu g_mu; static gpr_cv g_rcv; static int g_shutdown; @@ -186,8 +190,5 @@ void grpc_iomgr_unregister_object(grpc_iomgr_object* obj) { } bool grpc_iomgr_abort_on_leaks(void) { - char* env = gpr_getenv("GRPC_ABORT_ON_LEAKS"); - bool should_we = gpr_is_true(env); - gpr_free(env); - return should_we; + return GPR_GLOBAL_CONFIG_GET(grpc_abort_on_leaks); } diff --git a/src/core/lib/iomgr/iomgr_windows.cc b/src/core/lib/iomgr/iomgr_windows.cc index 13b5f87bd18..728d4040818 100644 --- a/src/core/lib/iomgr/iomgr_windows.cc +++ b/src/core/lib/iomgr/iomgr_windows.cc @@ -61,6 +61,7 @@ static void iomgr_platform_init(void) { winsock_init(); grpc_iocp_init(); grpc_pollset_global_init(); + grpc_wsa_socket_flags_init(); } static void iomgr_platform_flush(void) { grpc_iocp_flush(); } diff --git a/src/core/lib/iomgr/lockfree_event.cc b/src/core/lib/iomgr/lockfree_event.cc index 085fea40a40..f0c40b4827d 100644 --- a/src/core/lib/iomgr/lockfree_event.cc +++ b/src/core/lib/iomgr/lockfree_event.cc @@ -94,7 +94,7 @@ void LockfreeEvent::NotifyOn(grpc_closure* closure) { * sure that the shutdown error has been initialized properly before us * referencing it. */ gpr_atm curr = gpr_atm_acq_load(&state_); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_ERROR, "LockfreeEvent::NotifyOn: %p curr=%p closure=%p", this, (void*)curr, closure); } @@ -160,7 +160,7 @@ bool LockfreeEvent::SetShutdown(grpc_error* shutdown_err) { while (true) { gpr_atm curr = gpr_atm_no_barrier_load(&state_); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_ERROR, "LockfreeEvent::SetShutdown: %p curr=%p err=%s", &state_, (void*)curr, grpc_error_string(shutdown_err)); } @@ -209,7 +209,7 @@ void LockfreeEvent::SetReady() { while (true) { gpr_atm curr = gpr_atm_no_barrier_load(&state_); - if (grpc_polling_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) { gpr_log(GPR_ERROR, "LockfreeEvent::SetReady: %p curr=%p", &state_, (void*)curr); } diff --git a/src/core/lib/iomgr/port.h b/src/core/lib/iomgr/port.h index d387de5b13c..605692ac0d6 100644 --- a/src/core/lib/iomgr/port.h +++ b/src/core/lib/iomgr/port.h @@ -44,6 +44,8 @@ #elif defined(GPR_WINDOWS) #define GRPC_WINSOCK_SOCKET 1 #define GRPC_WINDOWS_SOCKETUTILS 1 +#define GRPC_WINDOWS_SOCKET_ARES_EV_DRIVER 1 +#define GRPC_ARES_RESOLVE_LOCALHOST_MANUALLY 1 #elif defined(GPR_ANDROID) #define GRPC_HAVE_IPV6_RECVPKTINFO 1 #define GRPC_HAVE_IP_PKTINFO 1 diff --git a/src/core/lib/iomgr/resource_quota.cc b/src/core/lib/iomgr/resource_quota.cc index 06e19d71e0c..dffac348c52 100644 --- a/src/core/lib/iomgr/resource_quota.cc +++ b/src/core/lib/iomgr/resource_quota.cc @@ -317,7 +317,7 @@ static bool rq_alloc(grpc_resource_quota* resource_quota) { while ((resource_user = rulist_pop_head(resource_quota, GRPC_RULIST_AWAITING_ALLOCATION))) { gpr_mu_lock(&resource_user->mu); - if (grpc_resource_quota_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_resource_quota_trace)) { gpr_log(GPR_INFO, "RQ: check allocation for user %p shutdown=%" PRIdPTR " free_pool=%" PRId64, @@ -343,14 +343,14 @@ static bool rq_alloc(grpc_resource_quota* resource_quota) { resource_user->free_pool = 0; resource_quota->free_pool -= amt; rq_update_estimate(resource_quota); - if (grpc_resource_quota_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_resource_quota_trace)) { gpr_log(GPR_INFO, "RQ %s %s: grant alloc %" PRId64 " bytes; rq_free_pool -> %" PRId64, resource_quota->name, resource_user->name, amt, resource_quota->free_pool); } - } else if (grpc_resource_quota_trace.enabled() && + } else if (GRPC_TRACE_FLAG_ENABLED(grpc_resource_quota_trace) && resource_user->free_pool >= 0) { gpr_log(GPR_INFO, "RQ %s %s: discard already satisfied alloc request", resource_quota->name, resource_user->name); @@ -382,7 +382,7 @@ static bool rq_reclaim_from_per_user_free_pool( resource_user->free_pool = 0; resource_quota->free_pool += amt; rq_update_estimate(resource_quota); - if (grpc_resource_quota_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_resource_quota_trace)) { gpr_log(GPR_INFO, "RQ %s %s: reclaim_from_per_user_free_pool %" PRId64 " bytes; rq_free_pool -> %" PRId64, @@ -392,7 +392,7 @@ static bool rq_reclaim_from_per_user_free_pool( gpr_mu_unlock(&resource_user->mu); return true; } else { - if (grpc_resource_quota_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_resource_quota_trace)) { gpr_log(GPR_INFO, "RQ %s %s: failed to reclaim_from_per_user_free_pool; " "free_pool = %" PRId64 "; rq_free_pool = %" PRId64, @@ -412,7 +412,7 @@ static bool rq_reclaim(grpc_resource_quota* resource_quota, bool destructive) { : GRPC_RULIST_RECLAIMER_BENIGN; grpc_resource_user* resource_user = rulist_pop_head(resource_quota, list); if (resource_user == nullptr) return false; - if (grpc_resource_quota_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_resource_quota_trace)) { gpr_log(GPR_INFO, "RQ %s %s: initiate %s reclamation", resource_quota->name, resource_user->name, destructive ? "destructive" : "benign"); } @@ -543,7 +543,7 @@ static void ru_post_destructive_reclaimer(void* ru, grpc_error* error) { } static void ru_shutdown(void* ru, grpc_error* error) { - if (grpc_resource_quota_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_resource_quota_trace)) { gpr_log(GPR_INFO, "RU shutdown %p", ru); } grpc_resource_user* resource_user = static_cast(ru); @@ -885,7 +885,7 @@ static void resource_user_alloc_locked(grpc_resource_user* resource_user, grpc_closure* optional_on_done) { ru_ref_by(resource_user, static_cast(size)); resource_user->free_pool -= static_cast(size); - if (grpc_resource_quota_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_resource_quota_trace)) { gpr_log(GPR_INFO, "RQ %s %s: alloc %" PRIdPTR "; free_pool -> %" PRId64, resource_user->resource_quota->name, resource_user->name, size, resource_user->free_pool); @@ -944,7 +944,7 @@ void grpc_resource_user_free(grpc_resource_user* resource_user, size_t size) { GPR_ASSERT(prior >= static_cast(size)); bool was_zero_or_negative = resource_user->free_pool <= 0; resource_user->free_pool += static_cast(size); - if (grpc_resource_quota_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_resource_quota_trace)) { gpr_log(GPR_INFO, "RQ %s %s: free %" PRIdPTR "; free_pool -> %" PRId64, resource_user->resource_quota->name, resource_user->name, size, resource_user->free_pool); @@ -970,7 +970,7 @@ void grpc_resource_user_post_reclaimer(grpc_resource_user* resource_user, } void grpc_resource_user_finish_reclamation(grpc_resource_user* resource_user) { - if (grpc_resource_quota_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_resource_quota_trace)) { gpr_log(GPR_INFO, "RQ %s %s: reclamation complete", resource_user->resource_quota->name, resource_user->name); } diff --git a/src/core/lib/iomgr/socket_utils_common_posix.cc b/src/core/lib/iomgr/socket_utils_common_posix.cc index ea0adb1f6a6..2101651b33f 100644 --- a/src/core/lib/iomgr/socket_utils_common_posix.cc +++ b/src/core/lib/iomgr/socket_utils_common_posix.cc @@ -292,7 +292,7 @@ grpc_error* grpc_set_socket_tcp_user_timeout( } if (enable) { extern grpc_core::TraceFlag grpc_tcp_trace; - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "Enabling TCP_USER_TIMEOUT with a timeout of %d ms", timeout); } @@ -315,7 +315,7 @@ grpc_error* grpc_set_socket_tcp_user_timeout( } #else extern grpc_core::TraceFlag grpc_tcp_trace; - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "TCP_USER_TIMEOUT not supported for this platform"); } #endif /* GRPC_HAVE_TCP_USER_TIMEOUT */ diff --git a/src/core/lib/iomgr/socket_windows.cc b/src/core/lib/iomgr/socket_windows.cc index 999c6646ad4..c87cfa8e831 100644 --- a/src/core/lib/iomgr/socket_windows.cc +++ b/src/core/lib/iomgr/socket_windows.cc @@ -39,6 +39,8 @@ #include "src/core/lib/iomgr/sockaddr_windows.h" #include "src/core/lib/iomgr/socket_windows.h" +static DWORD s_wsa_socket_flags; + grpc_winsocket* grpc_winsocket_create(SOCKET socket, const char* name) { char* final_name; grpc_winsocket* r = (grpc_winsocket*)gpr_malloc(sizeof(grpc_winsocket)); @@ -181,4 +183,21 @@ int grpc_ipv6_loopback_available(void) { return g_ipv6_loopback_available; } +DWORD grpc_get_default_wsa_socket_flags() { return s_wsa_socket_flags; } + +void grpc_wsa_socket_flags_init() { + s_wsa_socket_flags = WSA_FLAG_OVERLAPPED; + /* WSA_FLAG_NO_HANDLE_INHERIT may be not supported on the older Windows + versions, see + https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx + for details. */ + SOCKET sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, + s_wsa_socket_flags | WSA_FLAG_NO_HANDLE_INHERIT); + if (sock != INVALID_SOCKET) { + /* Windows 7, Windows 2008 R2 with SP1 or later */ + s_wsa_socket_flags |= WSA_FLAG_NO_HANDLE_INHERIT; + closesocket(sock); + } +} + #endif /* GRPC_WINSOCK_SOCKET */ diff --git a/src/core/lib/iomgr/socket_windows.h b/src/core/lib/iomgr/socket_windows.h index 46d7d583560..5fed6909e6f 100644 --- a/src/core/lib/iomgr/socket_windows.h +++ b/src/core/lib/iomgr/socket_windows.h @@ -32,6 +32,10 @@ #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/iomgr_internal.h" +#ifndef WSA_FLAG_NO_HANDLE_INHERIT +#define WSA_FLAG_NO_HANDLE_INHERIT 0x80 +#endif + /* This holds the data for an outstanding read or write on a socket. The mutex to protect the concurrent access to that data is the one inside the winsocket wrapper. */ @@ -114,6 +118,10 @@ void grpc_socket_become_ready(grpc_winsocket* winsocket, The value is probed once, and cached for the life of the process. */ int grpc_ipv6_loopback_available(void); +void grpc_wsa_socket_flags_init(); + +DWORD grpc_get_default_wsa_socket_flags(); + #endif #endif /* GRPC_CORE_LIB_IOMGR_SOCKET_WINDOWS_H */ diff --git a/src/core/lib/iomgr/tcp_client_custom.cc b/src/core/lib/iomgr/tcp_client_custom.cc index 73344b18d8b..14a8b78dc68 100644 --- a/src/core/lib/iomgr/tcp_client_custom.cc +++ b/src/core/lib/iomgr/tcp_client_custom.cc @@ -64,7 +64,7 @@ static void on_alarm(void* acp, grpc_error* error) { int done; grpc_custom_socket* socket = (grpc_custom_socket*)acp; grpc_custom_tcp_connect* connect = socket->connector; - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { const char* str = grpc_error_string(error); gpr_log(GPR_INFO, "CLIENT_CONNECT: %s: on_alarm: error=%s", connect->addr_name, str); @@ -146,7 +146,7 @@ static void tcp_connect(grpc_closure* closure, grpc_endpoint** ep, socket->listener = nullptr; connect->refs = 2; - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "CLIENT_CONNECT: %p %s: asynchronously connecting", socket, connect->addr_name); } diff --git a/src/core/lib/iomgr/tcp_client_posix.cc b/src/core/lib/iomgr/tcp_client_posix.cc index 0bff74e88b3..ad9d7798d05 100644 --- a/src/core/lib/iomgr/tcp_client_posix.cc +++ b/src/core/lib/iomgr/tcp_client_posix.cc @@ -108,7 +108,7 @@ done: static void tc_on_alarm(void* acp, grpc_error* error) { int done; async_connect* ac = static_cast(acp); - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { const char* str = grpc_error_string(error); gpr_log(GPR_INFO, "CLIENT_CONNECT: %s: on_alarm: error=%s", ac->addr_str, str); @@ -145,7 +145,7 @@ static void on_writable(void* acp, grpc_error* error) { GRPC_ERROR_REF(error); - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { const char* str = grpc_error_string(error); gpr_log(GPR_INFO, "CLIENT_CONNECT: %s: on_writable: error=%s", ac->addr_str, str); @@ -328,7 +328,7 @@ void grpc_tcp_client_create_from_prepared_fd( grpc_schedule_on_exec_ctx); ac->channel_args = grpc_channel_args_copy(channel_args); - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "CLIENT_CONNECT: %s: asynchronously connecting fd %p", ac->addr_str, fdobj); } diff --git a/src/core/lib/iomgr/tcp_client_windows.cc b/src/core/lib/iomgr/tcp_client_windows.cc index e24431b9a3e..66699533d7a 100644 --- a/src/core/lib/iomgr/tcp_client_windows.cc +++ b/src/core/lib/iomgr/tcp_client_windows.cc @@ -148,7 +148,7 @@ static void tcp_connect(grpc_closure* on_done, grpc_endpoint** endpoint, } sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, - WSA_FLAG_OVERLAPPED); + grpc_get_default_wsa_socket_flags()); if (sock == INVALID_SOCKET) { error = GRPC_WSA_ERROR(WSAGetLastError(), "WSASocket"); goto failure; diff --git a/src/core/lib/iomgr/tcp_custom.cc b/src/core/lib/iomgr/tcp_custom.cc index f7ad120b026..66df5082e98 100644 --- a/src/core/lib/iomgr/tcp_custom.cc +++ b/src/core/lib/iomgr/tcp_custom.cc @@ -88,7 +88,7 @@ static void tcp_free(grpc_custom_socket* s) { #define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__) static void tcp_unref(custom_tcp_endpoint* tcp, const char* reason, const char* file, int line) { - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count); gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "TCP unref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp->socket, reason, @@ -101,7 +101,7 @@ static void tcp_unref(custom_tcp_endpoint* tcp, const char* reason, static void tcp_ref(custom_tcp_endpoint* tcp, const char* reason, const char* file, int line) { - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count); gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "TCP ref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp->socket, reason, @@ -123,7 +123,7 @@ static void tcp_ref(custom_tcp_endpoint* tcp) { gpr_ref(&tcp->refcount); } static void call_read_cb(custom_tcp_endpoint* tcp, grpc_error* error) { grpc_closure* cb = tcp->read_cb; - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "TCP:%p call_cb %p %p:%p", tcp->socket, cb, cb->cb, cb->cb_arg); size_t i; @@ -169,7 +169,7 @@ static void custom_read_callback(grpc_custom_socket* socket, size_t nread, static void tcp_read_allocation_done(void* tcpp, grpc_error* error) { custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)tcpp; - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "TCP:%p read_allocation_done: %s", tcp->socket, grpc_error_string(error)); } @@ -185,7 +185,7 @@ static void tcp_read_allocation_done(void* tcpp, grpc_error* error) { grpc_slice_buffer_reset_and_unref_internal(tcp->read_slices); call_read_cb(tcp, GRPC_ERROR_REF(error)); } - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { const char* str = grpc_error_string(error); gpr_log(GPR_INFO, "Initiating read on %p: error=%s", tcp->socket, str); } @@ -211,7 +211,7 @@ static void custom_write_callback(grpc_custom_socket* socket, custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)socket->endpoint; grpc_closure* cb = tcp->write_cb; tcp->write_cb = nullptr; - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { const char* str = grpc_error_string(error); gpr_log(GPR_INFO, "write complete on %p: error=%s", tcp->socket, str); } @@ -224,7 +224,7 @@ static void endpoint_write(grpc_endpoint* ep, grpc_slice_buffer* write_slices, custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep; GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { size_t j; for (j = 0; j < write_slices->count; j++) { @@ -280,7 +280,7 @@ static void endpoint_delete_from_pollset_set(grpc_endpoint* ep, static void endpoint_shutdown(grpc_endpoint* ep, grpc_error* why) { custom_tcp_endpoint* tcp = (custom_tcp_endpoint*)ep; if (!tcp->shutting_down) { - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { const char* str = grpc_error_string(why); gpr_log(GPR_INFO, "TCP %p shutdown why=%s", tcp->socket, str); } @@ -345,7 +345,7 @@ grpc_endpoint* custom_tcp_endpoint_create(grpc_custom_socket* socket, (custom_tcp_endpoint*)gpr_malloc(sizeof(custom_tcp_endpoint)); grpc_core::ExecCtx exec_ctx; - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "Creating TCP endpoint %p", socket); } memset(tcp, 0, sizeof(custom_tcp_endpoint)); diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc index 30305a94f37..cda7bba0d3a 100644 --- a/src/core/lib/iomgr/tcp_posix.cc +++ b/src/core/lib/iomgr/tcp_posix.cc @@ -163,7 +163,7 @@ static void tcp_drop_uncovered_then_handle_write(void* arg /* grpc_tcp */, static void done_poller(void* bp, grpc_error* error_ignored) { backup_poller* p = static_cast(bp); - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "BACKUP_POLLER:%p destroy", p); } grpc_pollset_destroy(BACKUP_POLLER_POLLSET(p)); @@ -172,7 +172,7 @@ static void done_poller(void* bp, grpc_error* error_ignored) { static void run_poller(void* bp, grpc_error* error_ignored) { backup_poller* p = static_cast(bp); - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "BACKUP_POLLER:%p run", p); } gpr_mu_lock(p->pollset_mu); @@ -188,18 +188,18 @@ static void run_poller(void* bp, grpc_error* error_ignored) { gpr_atm_full_cas(&g_uncovered_notifications_pending, 1, 0)) { gpr_mu_lock(p->pollset_mu); bool cas_ok = gpr_atm_full_cas(&g_backup_poller, (gpr_atm)p, 0); - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "BACKUP_POLLER:%p done cas_ok=%d", p, cas_ok); } gpr_mu_unlock(p->pollset_mu); - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "BACKUP_POLLER:%p shutdown", p); } grpc_pollset_shutdown(BACKUP_POLLER_POLLSET(p), GRPC_CLOSURE_INIT(&p->run_poller, done_poller, p, grpc_schedule_on_exec_ctx)); } else { - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "BACKUP_POLLER:%p reschedule", p); } GRPC_CLOSURE_SCHED(&p->run_poller, GRPC_ERROR_NONE); @@ -210,7 +210,7 @@ static void drop_uncovered(grpc_tcp* tcp) { backup_poller* p = (backup_poller*)gpr_atm_acq_load(&g_backup_poller); gpr_atm old_count = gpr_atm_full_fetch_add(&g_uncovered_notifications_pending, -1); - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "BACKUP_POLLER:%p uncover cnt %d->%d", p, static_cast(old_count), static_cast(old_count) - 1); } @@ -228,7 +228,7 @@ static void cover_self(grpc_tcp* tcp) { backup_poller* p; gpr_atm old_count = gpr_atm_no_barrier_fetch_add(&g_uncovered_notifications_pending, 2); - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "BACKUP_POLLER: cover cnt %d->%d", static_cast(old_count), 2 + static_cast(old_count)); } @@ -236,7 +236,7 @@ static void cover_self(grpc_tcp* tcp) { GRPC_STATS_INC_TCP_BACKUP_POLLERS_CREATED(); p = static_cast( gpr_zalloc(sizeof(*p) + grpc_pollset_size())); - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "BACKUP_POLLER:%p create", p); } grpc_pollset_init(BACKUP_POLLER_POLLSET(p), &p->pollset_mu); @@ -251,7 +251,7 @@ static void cover_self(grpc_tcp* tcp) { // spin waiting for backup poller } } - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "BACKUP_POLLER:%p add %p", p, tcp); } grpc_pollset_add_fd(BACKUP_POLLER_POLLSET(p), tcp->em_fd); @@ -261,32 +261,24 @@ static void cover_self(grpc_tcp* tcp) { } static void notify_on_read(grpc_tcp* tcp) { - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "TCP:%p notify_on_read", tcp); } grpc_fd_notify_on_read(tcp->em_fd, &tcp->read_done_closure); } static void notify_on_write(grpc_tcp* tcp) { - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "TCP:%p notify_on_write", tcp); } - if (grpc_event_engine_run_in_background()) { - // If there is a polling engine always running in the background, there is - // no need to run the backup poller. - GRPC_CLOSURE_INIT(&tcp->write_done_closure, tcp_handle_write, tcp, - grpc_schedule_on_exec_ctx); - } else { + if (!grpc_event_engine_run_in_background()) { cover_self(tcp); - GRPC_CLOSURE_INIT(&tcp->write_done_closure, - tcp_drop_uncovered_then_handle_write, tcp, - grpc_schedule_on_exec_ctx); } grpc_fd_notify_on_write(tcp->em_fd, &tcp->write_done_closure); } static void tcp_drop_uncovered_then_handle_write(void* arg, grpc_error* error) { - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "TCP:%p got_write: %s", arg, grpc_error_string(error)); } drop_uncovered(static_cast(arg)); @@ -371,7 +363,7 @@ static void tcp_free(grpc_tcp* tcp) { #define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__) static void tcp_unref(grpc_tcp* tcp, const char* reason, const char* file, int line) { - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count); gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP unref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp, reason, val, @@ -384,7 +376,7 @@ static void tcp_unref(grpc_tcp* tcp, const char* reason, const char* file, static void tcp_ref(grpc_tcp* tcp, const char* reason, const char* file, int line) { - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count); gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "TCP ref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp, reason, val, @@ -417,7 +409,7 @@ static void tcp_destroy(grpc_endpoint* ep) { static void call_read_cb(grpc_tcp* tcp, grpc_error* error) { grpc_closure* cb = tcp->read_cb; - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "TCP:%p call_cb %p %p:%p", tcp, cb, cb->cb, cb->cb_arg); size_t i; const char* str = grpc_error_string(error); @@ -581,7 +573,7 @@ static void tcp_do_read(grpc_tcp* tcp) { static void tcp_read_allocation_done(void* tcpp, grpc_error* error) { grpc_tcp* tcp = static_cast(tcpp); - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "TCP:%p read_allocation_done: %s", tcp, grpc_error_string(error)); } @@ -600,13 +592,13 @@ static void tcp_continue_read(grpc_tcp* tcp) { /* Wait for allocation only when there is no buffer left. */ if (tcp->incoming_buffer->length == 0 && tcp->incoming_buffer->count < MAX_READ_IOVEC) { - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "TCP:%p alloc_slices", tcp); } grpc_resource_user_alloc_slices(&tcp->slice_allocator, target_read_size, 1, tcp->incoming_buffer); } else { - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "TCP:%p do_read", tcp); } tcp_do_read(tcp); @@ -615,7 +607,7 @@ static void tcp_continue_read(grpc_tcp* tcp) { static void tcp_handle_read(void* arg /* grpc_tcp */, grpc_error* error) { grpc_tcp* tcp = static_cast(arg); - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "TCP:%p got_read: %s", tcp, grpc_error_string(error)); } @@ -694,7 +686,7 @@ static bool tcp_write_with_timestamps(grpc_tcp* tcp, struct msghdr* msg, if (setsockopt(tcp->fd, SOL_SOCKET, SO_TIMESTAMPING, static_cast(&opt), sizeof(opt)) != 0) { grpc_slice_buffer_reset_and_unref_internal(tcp->outgoing_buffer); - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_ERROR, "Failed to set timestamping options on the socket."); } return false; @@ -743,7 +735,7 @@ struct cmsghdr* process_timestamp(grpc_tcp* tcp, msghdr* msg, auto next_cmsg = CMSG_NXTHDR(msg, cmsg); cmsghdr* opt_stats = nullptr; if (next_cmsg == nullptr) { - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_ERROR, "Received timestamp without extended error"); } return cmsg; @@ -755,7 +747,7 @@ struct cmsghdr* process_timestamp(grpc_tcp* tcp, msghdr* msg, opt_stats = next_cmsg; next_cmsg = CMSG_NXTHDR(msg, opt_stats); if (next_cmsg == nullptr) { - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_ERROR, "Received timestamp without extended error"); } return opt_stats; @@ -765,7 +757,7 @@ struct cmsghdr* process_timestamp(grpc_tcp* tcp, msghdr* msg, if (!(next_cmsg->cmsg_level == SOL_IP || next_cmsg->cmsg_level == SOL_IPV6) || !(next_cmsg->cmsg_type == IP_RECVERR || next_cmsg->cmsg_type == IPV6_RECVERR)) { - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_ERROR, "Unexpected control message"); } return cmsg; @@ -847,7 +839,7 @@ static void process_errors(grpc_tcp* tcp) { cmsg->cmsg_type != SCM_TIMESTAMPING) { /* Got a control message that is not a timestamp. Don't know how to * handle this. */ - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "unknown control message cmsg_level:%d cmsg_type:%d", cmsg->cmsg_level, cmsg->cmsg_type); @@ -865,7 +857,7 @@ static void process_errors(grpc_tcp* tcp) { static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error* error) { grpc_tcp* tcp = static_cast(arg); - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "TCP:%p got_error: %s", tcp, grpc_error_string(error)); } @@ -884,8 +876,6 @@ static void tcp_handle_error(void* arg /* grpc_tcp */, grpc_error* error) { * ready. */ grpc_fd_set_readable(tcp->em_fd); grpc_fd_set_writable(tcp->em_fd); - GRPC_CLOSURE_INIT(&tcp->error_closure, tcp_handle_error, tcp, - grpc_schedule_on_exec_ctx); grpc_fd_notify_on_error(tcp->em_fd, &tcp->error_closure); } @@ -990,8 +980,7 @@ static bool tcp_flush(grpc_tcp* tcp, grpc_error** error) { // unref all and forget about all slices that have been written to this // point for (size_t idx = 0; idx < unwind_slice_idx; ++idx) { - grpc_slice_unref_internal( - grpc_slice_buffer_take_first(tcp->outgoing_buffer)); + grpc_slice_buffer_remove_first(tcp->outgoing_buffer); } return false; } else if (errno == EPIPE) { @@ -1044,14 +1033,14 @@ static void tcp_handle_write(void* arg /* grpc_tcp */, grpc_error* error) { } if (!tcp_flush(tcp, &error)) { - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "write: delayed"); } notify_on_write(tcp); } else { cb = tcp->write_cb; tcp->write_cb = nullptr; - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { const char* str = grpc_error_string(error); gpr_log(GPR_INFO, "write: %s", str); } @@ -1066,7 +1055,7 @@ static void tcp_write(grpc_endpoint* ep, grpc_slice_buffer* buf, grpc_tcp* tcp = reinterpret_cast(ep); grpc_error* error = GRPC_ERROR_NONE; - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { size_t i; for (i = 0; i < buf->count; i++) { @@ -1101,12 +1090,12 @@ static void tcp_write(grpc_endpoint* ep, grpc_slice_buffer* buf, if (!tcp_flush(tcp, &error)) { TCP_REF(tcp, "write"); tcp->write_cb = cb; - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "write: delayed"); } notify_on_write(tcp); } else { - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { const char* str = grpc_error_string(error); gpr_log(GPR_INFO, "write: %s", str); } @@ -1248,6 +1237,16 @@ grpc_endpoint* grpc_tcp_create(grpc_fd* em_fd, tcp->tb_head = nullptr; GRPC_CLOSURE_INIT(&tcp->read_done_closure, tcp_handle_read, tcp, grpc_schedule_on_exec_ctx); + if (grpc_event_engine_run_in_background()) { + // If there is a polling engine always running in the background, there is + // no need to run the backup poller. + GRPC_CLOSURE_INIT(&tcp->write_done_closure, tcp_handle_write, tcp, + grpc_schedule_on_exec_ctx); + } else { + GRPC_CLOSURE_INIT(&tcp->write_done_closure, + tcp_drop_uncovered_then_handle_write, tcp, + grpc_schedule_on_exec_ctx); + } /* Always assume there is something on the queue to read. */ tcp->inq = 1; #ifdef GRPC_HAVE_TCP_INQ diff --git a/src/core/lib/iomgr/tcp_server.cc b/src/core/lib/iomgr/tcp_server.cc index ea745f266b9..f2e4b1b51ea 100644 --- a/src/core/lib/iomgr/tcp_server.cc +++ b/src/core/lib/iomgr/tcp_server.cc @@ -41,6 +41,11 @@ grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s, return grpc_tcp_server_impl->add_port(s, addr, out_port); } +grpc_core::TcpServerFdHandler* grpc_tcp_server_create_fd_handler( + grpc_tcp_server* s) { + return grpc_tcp_server_impl->create_fd_handler(s); +} + unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server* s, unsigned port_index) { return grpc_tcp_server_impl->port_fd_count(s, port_index); diff --git a/src/core/lib/iomgr/tcp_server.h b/src/core/lib/iomgr/tcp_server.h index 8fcbb2f6807..774f06ee17a 100644 --- a/src/core/lib/iomgr/tcp_server.h +++ b/src/core/lib/iomgr/tcp_server.h @@ -22,7 +22,9 @@ #include #include +#include +#include "src/core/lib/gprpp/abstract.h" #include "src/core/lib/iomgr/closure.h" #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/resolve_address.h" @@ -37,6 +39,9 @@ typedef struct grpc_tcp_server_acceptor { /* Indices that may be passed to grpc_tcp_server_port_fd(). */ unsigned port_index; unsigned fd_index; + /* Data when the connection is passed to tcp_server from external. */ + bool external_connection; + grpc_byte_buffer* pending_data; } grpc_tcp_server_acceptor; /* Called for newly connected TCP connections. @@ -44,6 +49,17 @@ typedef struct grpc_tcp_server_acceptor { typedef void (*grpc_tcp_server_cb)(void* arg, grpc_endpoint* ep, grpc_pollset* accepting_pollset, grpc_tcp_server_acceptor* acceptor); +namespace grpc_core { +// An interface for a handler to take a externally connected fd as a internal +// connection. +class TcpServerFdHandler { + public: + virtual ~TcpServerFdHandler() = default; + virtual void Handle(int fd, grpc_byte_buffer* pending_read) GRPC_ABSTRACT; + + GRPC_ABSTRACT_BASE_CLASS; +}; +} // namespace grpc_core typedef struct grpc_tcp_server_vtable { grpc_error* (*create)(grpc_closure* shutdown_complete, @@ -54,6 +70,7 @@ typedef struct grpc_tcp_server_vtable { void* cb_arg); grpc_error* (*add_port)(grpc_tcp_server* s, const grpc_resolved_address* addr, int* out_port); + grpc_core::TcpServerFdHandler* (*create_fd_handler)(grpc_tcp_server* s); unsigned (*port_fd_count)(grpc_tcp_server* s, unsigned port_index); int (*port_fd)(grpc_tcp_server* s, unsigned port_index, unsigned fd_index); grpc_tcp_server* (*ref)(grpc_tcp_server* s); @@ -88,6 +105,11 @@ grpc_error* grpc_tcp_server_add_port(grpc_tcp_server* s, const grpc_resolved_address* addr, int* out_port); +/* Create and return a TcpServerFdHandler so that it can be used by upper layer + to hand over an externally connected fd to the grpc server. */ +grpc_core::TcpServerFdHandler* grpc_tcp_server_create_fd_handler( + grpc_tcp_server* s); + /* Number of fds at the given port_index, or 0 if port_index is out of bounds. */ unsigned grpc_tcp_server_port_fd_count(grpc_tcp_server* s, unsigned port_index); diff --git a/src/core/lib/iomgr/tcp_server_custom.cc b/src/core/lib/iomgr/tcp_server_custom.cc index 019b354473b..767404be21d 100644 --- a/src/core/lib/iomgr/tcp_server_custom.cc +++ b/src/core/lib/iomgr/tcp_server_custom.cc @@ -220,7 +220,7 @@ static void finish_accept(grpc_tcp_listener* sp, grpc_custom_socket* socket) { GRPC_LOG_IF_ERROR("getpeername error", err); GRPC_ERROR_UNREF(err); } - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { if (peer_name_string) { gpr_log(GPR_INFO, "SERVER_CONNECT: %p accepted connection: %s", sp->server, peer_name_string); @@ -233,6 +233,7 @@ static void finish_accept(grpc_tcp_listener* sp, grpc_custom_socket* socket) { acceptor->from_server = sp->server; acceptor->port_index = sp->port_index; acceptor->fd_index = 0; + acceptor->external_connection = false; sp->server->on_accept_cb(sp->server->on_accept_cb_arg, ep, nullptr, acceptor); gpr_free(peer_name_string); } @@ -372,7 +373,7 @@ static grpc_error* tcp_server_add_port(grpc_tcp_server* s, addr = &wildcard; } - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { char* port_string; grpc_sockaddr_to_string(&port_string, addr, 0); const char* str = grpc_error_string(error); @@ -418,7 +419,7 @@ static void tcp_server_start(grpc_tcp_server* server, grpc_pollset** pollsets, (void)pollsets; (void)pollset_count; GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD(); - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "SERVER_START %p", server); } GPR_ASSERT(on_accept_cb); @@ -456,16 +457,17 @@ static void tcp_server_shutdown_listeners(grpc_tcp_server* s) { } } +static grpc_core::TcpServerFdHandler* tcp_server_create_fd_handler( + grpc_tcp_server* s) { + return nullptr; +} + grpc_tcp_server_vtable custom_tcp_server_vtable = { - tcp_server_create, - tcp_server_start, - tcp_server_add_port, - tcp_server_port_fd_count, - tcp_server_port_fd, - tcp_server_ref, - tcp_server_shutdown_starting_add, - tcp_server_unref, - tcp_server_shutdown_listeners}; + tcp_server_create, tcp_server_start, + tcp_server_add_port, tcp_server_create_fd_handler, + tcp_server_port_fd_count, tcp_server_port_fd, + tcp_server_ref, tcp_server_shutdown_starting_add, + tcp_server_unref, tcp_server_shutdown_listeners}; #ifdef GRPC_UV_TEST grpc_tcp_server_vtable* default_tcp_server_vtable = &custom_tcp_server_vtable; diff --git a/src/core/lib/iomgr/tcp_server_posix.cc b/src/core/lib/iomgr/tcp_server_posix.cc index baef3886530..001f786b65d 100644 --- a/src/core/lib/iomgr/tcp_server_posix.cc +++ b/src/core/lib/iomgr/tcp_server_posix.cc @@ -27,8 +27,6 @@ #ifdef GRPC_POSIX_SOCKET_TCP_SERVER -#include "src/core/lib/iomgr/tcp_server.h" - #include #include #include @@ -47,11 +45,14 @@ #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/gprpp/memory.h" +#include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/iomgr/sockaddr.h" #include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/iomgr/socket_utils_posix.h" #include "src/core/lib/iomgr/tcp_posix.h" +#include "src/core/lib/iomgr/tcp_server.h" #include "src/core/lib/iomgr/tcp_server_utils_posix.h" #include "src/core/lib/iomgr/unix_sockets_posix.h" @@ -96,6 +97,7 @@ static grpc_error* tcp_server_create(grpc_closure* shutdown_complete, s->tail = nullptr; s->nports = 0; s->channel_args = grpc_channel_args_copy(args); + s->fd_handler = nullptr; gpr_atm_no_barrier_store(&s->next_pollset_to_assign, 0); *server = s; return GRPC_ERROR_NONE; @@ -117,6 +119,7 @@ static void finish_shutdown(grpc_tcp_server* s) { gpr_free(sp); } grpc_channel_args_destroy(s->channel_args); + grpc_core::Delete(s->fd_handler); gpr_free(s); } @@ -235,7 +238,7 @@ static void on_read(void* arg, grpc_error* err) { addr_str = grpc_sockaddr_to_uri(&addr); gpr_asprintf(&name, "tcp-server-connection:%s", addr_str); - if (grpc_tcp_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_tcp_trace)) { gpr_log(GPR_INFO, "SERVER_CONNECT: incoming connection: %s", addr_str); } @@ -254,6 +257,7 @@ static void on_read(void* arg, grpc_error* err) { acceptor->from_server = sp->server; acceptor->port_index = sp->port_index; acceptor->fd_index = sp->fd_index; + acceptor->external_connection = false; sp->server->on_accept_cb( sp->server->on_accept_cb_arg, @@ -562,14 +566,70 @@ static void tcp_server_shutdown_listeners(grpc_tcp_server* s) { gpr_mu_unlock(&s->mu); } +namespace { +class ExternalConnectionHandler : public grpc_core::TcpServerFdHandler { + public: + explicit ExternalConnectionHandler(grpc_tcp_server* s) : s_(s) {} + + // TODO(yangg) resolve duplicate code with on_read + void Handle(int fd, grpc_byte_buffer* buf) override { + grpc_pollset* read_notifier_pollset; + grpc_resolved_address addr; + char* addr_str; + char* name; + memset(&addr, 0, sizeof(addr)); + addr.len = static_cast(sizeof(struct sockaddr_storage)); + grpc_core::ExecCtx exec_ctx; + + if (getpeername(fd, reinterpret_cast(addr.addr), + &(addr.len)) < 0) { + gpr_log(GPR_ERROR, "Failed getpeername: %s", strerror(errno)); + close(fd); + return; + } + grpc_set_socket_no_sigpipe_if_possible(fd); + addr_str = grpc_sockaddr_to_uri(&addr); + gpr_asprintf(&name, "tcp-server-connection:%s", addr_str); + if (grpc_tcp_trace.enabled()) { + gpr_log(GPR_INFO, "SERVER_CONNECT: incoming external connection: %s", + addr_str); + } + grpc_fd* fdobj = grpc_fd_create(fd, name, true); + read_notifier_pollset = + s_->pollsets[static_cast(gpr_atm_no_barrier_fetch_add( + &s_->next_pollset_to_assign, 1)) % + s_->pollset_count]; + grpc_pollset_add_fd(read_notifier_pollset, fdobj); + grpc_tcp_server_acceptor* acceptor = + static_cast(gpr_malloc(sizeof(*acceptor))); + acceptor->from_server = s_; + acceptor->port_index = -1; + acceptor->fd_index = -1; + acceptor->external_connection = true; + acceptor->pending_data = buf; + s_->on_accept_cb(s_->on_accept_cb_arg, + grpc_tcp_create(fdobj, s_->channel_args, addr_str), + read_notifier_pollset, acceptor); + gpr_free(name); + gpr_free(addr_str); + } + + private: + grpc_tcp_server* s_; +}; +} // namespace + +static grpc_core::TcpServerFdHandler* tcp_server_create_fd_handler( + grpc_tcp_server* s) { + s->fd_handler = grpc_core::New(s); + return s->fd_handler; +} + grpc_tcp_server_vtable grpc_posix_tcp_server_vtable = { - tcp_server_create, - tcp_server_start, - tcp_server_add_port, - tcp_server_port_fd_count, - tcp_server_port_fd, - tcp_server_ref, - tcp_server_shutdown_starting_add, - tcp_server_unref, - tcp_server_shutdown_listeners}; + tcp_server_create, tcp_server_start, + tcp_server_add_port, tcp_server_create_fd_handler, + tcp_server_port_fd_count, tcp_server_port_fd, + tcp_server_ref, tcp_server_shutdown_starting_add, + tcp_server_unref, tcp_server_shutdown_listeners}; + #endif /* GRPC_POSIX_SOCKET_TCP_SERVER */ diff --git a/src/core/lib/iomgr/tcp_server_utils_posix.h b/src/core/lib/iomgr/tcp_server_utils_posix.h index dd199097b2c..390d6d266a2 100644 --- a/src/core/lib/iomgr/tcp_server_utils_posix.h +++ b/src/core/lib/iomgr/tcp_server_utils_posix.h @@ -92,6 +92,9 @@ struct grpc_tcp_server { /* channel args for this server */ grpc_channel_args* channel_args; + + /* a handler for external connections, owned */ + grpc_core::TcpServerFdHandler* fd_handler; }; /* If successful, add a listener to \a s for \a addr, set \a dsmode for the diff --git a/src/core/lib/iomgr/tcp_server_windows.cc b/src/core/lib/iomgr/tcp_server_windows.cc index b01afdcc9db..abfa3be5708 100644 --- a/src/core/lib/iomgr/tcp_server_windows.cc +++ b/src/core/lib/iomgr/tcp_server_windows.cc @@ -255,7 +255,7 @@ static grpc_error* start_accept_locked(grpc_tcp_listener* port) { } sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, - WSA_FLAG_OVERLAPPED); + grpc_get_default_wsa_socket_flags()); if (sock == INVALID_SOCKET) { error = GRPC_WSA_ERROR(WSAGetLastError(), "WSASocket"); goto failure; @@ -372,6 +372,7 @@ static void on_accept(void* arg, grpc_error* error) { acceptor->from_server = sp->server; acceptor->port_index = sp->port_index; acceptor->fd_index = 0; + acceptor->external_connection = false; sp->server->on_accept_cb(sp->server->on_accept_cb_arg, ep, NULL, acceptor); } /* As we were notified from the IOCP of one and exactly one accept, @@ -493,7 +494,7 @@ static grpc_error* tcp_server_add_port(grpc_tcp_server* s, } sock = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, - WSA_FLAG_OVERLAPPED); + grpc_get_default_wsa_socket_flags()); if (sock == INVALID_SOCKET) { error = GRPC_WSA_ERROR(WSAGetLastError(), "WSASocket"); goto done; @@ -545,16 +546,17 @@ static int tcp_server_port_fd(grpc_tcp_server* s, unsigned port_index, return -1; } +static grpc_core::TcpServerFdHandler* tcp_server_create_fd_handler( + grpc_tcp_server* s) { + return nullptr; +} + static void tcp_server_shutdown_listeners(grpc_tcp_server* s) {} grpc_tcp_server_vtable grpc_windows_tcp_server_vtable = { - tcp_server_create, - tcp_server_start, - tcp_server_add_port, - tcp_server_port_fd_count, - tcp_server_port_fd, - tcp_server_ref, - tcp_server_shutdown_starting_add, - tcp_server_unref, - tcp_server_shutdown_listeners}; + tcp_server_create, tcp_server_start, + tcp_server_add_port, tcp_server_create_fd_handler, + tcp_server_port_fd_count, tcp_server_port_fd, + tcp_server_ref, tcp_server_shutdown_starting_add, + tcp_server_unref, tcp_server_shutdown_listeners}; #endif /* GRPC_WINSOCK_SOCKET */ diff --git a/src/core/lib/iomgr/tcp_windows.cc b/src/core/lib/iomgr/tcp_windows.cc index 60d34ef897f..ae6b2b68e62 100644 --- a/src/core/lib/iomgr/tcp_windows.cc +++ b/src/core/lib/iomgr/tcp_windows.cc @@ -74,20 +74,6 @@ static grpc_error* set_dualstack(SOCKET sock) { : GRPC_WSA_ERROR(WSAGetLastError(), "setsockopt(IPV6_V6ONLY)"); } -static grpc_error* enable_loopback_fast_path(SOCKET sock) { - int status; - uint32_t param = 1; - DWORD ret; - status = WSAIoctl(sock, /*SIO_LOOPBACK_FAST_PATH==*/_WSAIOW(IOC_VENDOR, 16), - ¶m, sizeof(param), NULL, 0, &ret, 0, 0); - if (status == SOCKET_ERROR) { - status = WSAGetLastError(); - } - return status == 0 || status == WSAEOPNOTSUPP - ? GRPC_ERROR_NONE - : GRPC_WSA_ERROR(status, "WSAIoctl(SIO_LOOPBACK_FAST_PATH)"); -} - static grpc_error* enable_socket_low_latency(SOCKET sock) { int status; BOOL param = TRUE; @@ -106,8 +92,6 @@ grpc_error* grpc_tcp_prepare_socket(SOCKET sock) { if (err != GRPC_ERROR_NONE) return err; err = set_dualstack(sock); if (err != GRPC_ERROR_NONE) return err; - err = enable_loopback_fast_path(sock); - if (err != GRPC_ERROR_NONE) return err; err = enable_socket_low_latency(sock); if (err != GRPC_ERROR_NONE) return err; return GRPC_ERROR_NONE; diff --git a/src/core/lib/iomgr/timer_generic.cc b/src/core/lib/iomgr/timer_generic.cc index 6a925add80c..00c18789481 100644 --- a/src/core/lib/iomgr/timer_generic.cc +++ b/src/core/lib/iomgr/timer_generic.cc @@ -361,7 +361,7 @@ static void timer_init(grpc_timer* timer, grpc_millis deadline, timer->hash_table_next = nullptr; #endif - if (grpc_timer_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_trace)) { gpr_log(GPR_INFO, "TIMER %p: SET %" PRId64 " now %" PRId64 " call %p[%p]", timer, deadline, grpc_core::ExecCtx::Get()->Now(), closure, closure->cb); @@ -397,7 +397,7 @@ static void timer_init(grpc_timer* timer, grpc_millis deadline, timer->heap_index = INVALID_HEAP_INDEX; list_join(&shard->list, timer); } - if (grpc_timer_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_trace)) { gpr_log(GPR_INFO, " .. add to shard %d with queue_deadline_cap=%" PRId64 " => is_first_timer=%s", @@ -419,7 +419,7 @@ static void timer_init(grpc_timer* timer, grpc_millis deadline, grpc_timer_check. */ if (is_first_timer) { gpr_mu_lock(&g_shared_mutables.mu); - if (grpc_timer_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_trace)) { gpr_log(GPR_INFO, " .. old shard min_deadline=%" PRId64, shard->min_deadline); } @@ -463,7 +463,7 @@ static void timer_cancel(grpc_timer* timer) { timer_shard* shard = &g_shards[GPR_HASH_POINTER(timer, g_num_shards)]; gpr_mu_lock(&shard->mu); - if (grpc_timer_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_trace)) { gpr_log(GPR_INFO, "TIMER %p: CANCEL pending=%s", timer, timer->pending ? "true" : "false"); } @@ -487,7 +487,7 @@ static void timer_cancel(grpc_timer* timer) { /* Rebalances the timer shard by computing a new 'queue_deadline_cap' and moving all relevant timers in shard->list (i.e timers with deadlines earlier than 'queue_deadline_cap') into into shard->heap. - Returns 'true' if shard->heap has atleast ONE element + Returns 'true' if shard->heap has at least ONE element REQUIRES: shard->mu locked */ static bool refill_heap(timer_shard* shard, grpc_millis now) { /* Compute the new queue window width and bound by the limits: */ @@ -504,7 +504,7 @@ static bool refill_heap(timer_shard* shard, grpc_millis now) { saturating_add(GPR_MAX(now, shard->queue_deadline_cap), static_cast(deadline_delta * 1000.0)); - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { gpr_log(GPR_INFO, " .. shard[%d]->queue_deadline_cap --> %" PRId64, static_cast(shard - g_shards), shard->queue_deadline_cap); } @@ -512,7 +512,7 @@ static bool refill_heap(timer_shard* shard, grpc_millis now) { next = timer->next; if (timer->deadline < shard->queue_deadline_cap) { - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { gpr_log(GPR_INFO, " .. add timer with deadline %" PRId64 " to heap", timer->deadline); } @@ -529,7 +529,7 @@ static bool refill_heap(timer_shard* shard, grpc_millis now) { static grpc_timer* pop_one(timer_shard* shard, grpc_millis now) { grpc_timer* timer; for (;;) { - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { gpr_log(GPR_INFO, " .. shard[%d]: heap_empty=%s", static_cast(shard - g_shards), grpc_timer_heap_is_empty(&shard->heap) ? "true" : "false"); @@ -539,13 +539,13 @@ static grpc_timer* pop_one(timer_shard* shard, grpc_millis now) { if (!refill_heap(shard, now)) return nullptr; } timer = grpc_timer_heap_top(&shard->heap); - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { gpr_log(GPR_INFO, " .. check top timer deadline=%" PRId64 " now=%" PRId64, timer->deadline, now); } if (timer->deadline > now) return nullptr; - if (grpc_timer_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_trace)) { gpr_log(GPR_INFO, "TIMER %p: FIRE %" PRId64 "ms late via %s scheduler", timer, now - timer->deadline, timer->closure->scheduler->vtable->name); @@ -569,7 +569,7 @@ static size_t pop_timers(timer_shard* shard, grpc_millis now, } *new_min_deadline = compute_min_deadline(shard); gpr_mu_unlock(&shard->mu); - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { gpr_log(GPR_INFO, " .. shard[%d] popped %" PRIdPTR, static_cast(shard - g_shards), n); } @@ -606,7 +606,7 @@ static grpc_timer_check_result run_some_expired_timers(grpc_millis now, gpr_mu_lock(&g_shared_mutables.mu); result = GRPC_TIMERS_CHECKED_AND_EMPTY; - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { gpr_log(GPR_INFO, " .. shard[%d]->min_deadline = %" PRId64, static_cast(g_shard_queue[0] - g_shards), g_shard_queue[0]->min_deadline); @@ -624,7 +624,7 @@ static grpc_timer_check_result run_some_expired_timers(grpc_millis now, result = GRPC_TIMERS_FIRED; } - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { gpr_log(GPR_INFO, " .. result --> %d" ", shard[%d]->min_deadline %" PRId64 " --> %" PRId64 @@ -691,7 +691,7 @@ static grpc_timer_check_result timer_check(grpc_millis* next) { if (next != nullptr) { *next = GPR_MIN(*next, min_timer); } - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { gpr_log(GPR_INFO, "TIMER CHECK SKIP: now=%" PRId64 " min_timer=%" PRId64, now, min_timer); } @@ -704,7 +704,7 @@ static grpc_timer_check_result timer_check(grpc_millis* next) { : GRPC_ERROR_CREATE_FROM_STATIC_STRING("Shutting down timer system"); // tracing - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { char* next_str; if (next == nullptr) { next_str = gpr_strdup("NULL"); @@ -728,7 +728,7 @@ static grpc_timer_check_result timer_check(grpc_millis* next) { grpc_timer_check_result r = run_some_expired_timers(now, next, shutdown_error); // tracing - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { char* next_str; if (next == nullptr) { next_str = gpr_strdup("NULL"); diff --git a/src/core/lib/iomgr/timer_manager.cc b/src/core/lib/iomgr/timer_manager.cc index 4469db70dd0..bdf54909b4c 100644 --- a/src/core/lib/iomgr/timer_manager.cc +++ b/src/core/lib/iomgr/timer_manager.cc @@ -90,7 +90,7 @@ static void start_timer_thread_and_unlock(void) { ++g_waiter_count; ++g_thread_count; gpr_mu_unlock(&g_mu); - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { gpr_log(GPR_INFO, "Spawn timer thread"); } completed_thread* ct = @@ -126,7 +126,7 @@ static void run_some_timers() { // if there's no thread waiting with a timeout, kick an existing untimed // waiter so that the next deadline is not missed if (!g_has_timed_waiter) { - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { gpr_log(GPR_INFO, "kick untimed waiter"); } gpr_cv_signal(&g_cv_wait); @@ -134,7 +134,7 @@ static void run_some_timers() { gpr_mu_unlock(&g_mu); } // without our lock, flush the exec_ctx - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { gpr_log(GPR_INFO, "flush exec_ctx"); } grpc_core::ExecCtx::Get()->Flush(); @@ -189,7 +189,7 @@ static bool wait_until(grpc_millis next) { g_has_timed_waiter = true; g_timed_waiter_deadline = next; - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { grpc_millis wait_time = next - grpc_core::ExecCtx::Get()->Now(); gpr_log(GPR_INFO, "sleep for a %" PRId64 " milliseconds", wait_time); } @@ -198,7 +198,8 @@ static bool wait_until(grpc_millis next) { } } - if (grpc_timer_check_trace.enabled() && next == GRPC_MILLIS_INF_FUTURE) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace) && + next == GRPC_MILLIS_INF_FUTURE) { gpr_log(GPR_INFO, "sleep until kicked"); } @@ -210,7 +211,7 @@ static bool wait_until(grpc_millis next) { gpr_cv_wait(&g_cv_wait, &g_mu, grpc_millis_to_timespec(next, GPR_CLOCK_MONOTONIC)); - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { gpr_log(GPR_INFO, "wait ended: was_timed:%d kicked:%d", my_timed_waiter_generation == g_timed_waiter_generation, g_kicked); @@ -255,7 +256,7 @@ static void timer_main_loop() { Consequently, we can just sleep forever here and be happy at some saved wakeup cycles. */ - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { gpr_log(GPR_INFO, "timers not checked: expect another thread to"); } next = GRPC_MILLIS_INF_FUTURE; @@ -281,7 +282,7 @@ static void timer_thread_cleanup(completed_thread* ct) { ct->next = g_completed_threads; g_completed_threads = ct; gpr_mu_unlock(&g_mu); - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { gpr_log(GPR_INFO, "End timer thread"); } } @@ -327,18 +328,18 @@ void grpc_timer_manager_init(void) { static void stop_threads(void) { gpr_mu_lock(&g_mu); - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { gpr_log(GPR_INFO, "stop timer threads: threaded=%d", g_threaded); } if (g_threaded) { g_threaded = false; gpr_cv_broadcast(&g_cv_wait); - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { gpr_log(GPR_INFO, "num timer threads: %d", g_thread_count); } while (g_thread_count > 0) { gpr_cv_wait(&g_cv_shutdown, &g_mu, gpr_inf_future(GPR_CLOCK_MONOTONIC)); - if (grpc_timer_check_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_timer_check_trace)) { gpr_log(GPR_INFO, "num timer threads: %d", g_thread_count); } gc_completed_threads(); diff --git a/src/core/lib/iomgr/udp_server.cc b/src/core/lib/iomgr/udp_server.cc index 5f8865ca57f..3e853945555 100644 --- a/src/core/lib/iomgr/udp_server.cc +++ b/src/core/lib/iomgr/udp_server.cc @@ -332,7 +332,7 @@ void GrpcUdpListener::OnFdAboutToOrphan() { GRPC_CLOSURE_INIT(&destroyed_closure_, destroyed_port, server_, grpc_schedule_on_exec_ctx); if (!orphan_notified_ && udp_handler_ != nullptr) { - /* Singals udp_handler that the FD is about to be closed and + /* Signals udp_handler that the FD is about to be closed and * should no longer be used. */ GRPC_CLOSURE_INIT(&orphan_fd_closure_, shutdown_fd, this, grpc_schedule_on_exec_ctx); @@ -645,7 +645,7 @@ int grpc_udp_server_add_port(grpc_udp_server* s, grpc_sockaddr_set_port(addr, allocated_port1); port = allocated_port1; } else if (allocated_port1 >= 0) { - /* The following sucessfully created socket should have same port as + /* The following successfully created socket should have same port as * the first one. */ GPR_ASSERT(port == allocated_port1); } diff --git a/src/core/lib/profiling/basic_timers.cc b/src/core/lib/profiling/basic_timers.cc index b19ad9fc23d..37689fe89d1 100644 --- a/src/core/lib/profiling/basic_timers.cc +++ b/src/core/lib/profiling/basic_timers.cc @@ -31,7 +31,8 @@ #include #include -#include "src/core/lib/gpr/env.h" +#include "src/core/lib/gprpp/global_config.h" +#include "src/core/lib/profiling/timers.h" typedef enum { BEGIN = '{', END = '}', MARK = '.' } marker_type; @@ -74,11 +75,16 @@ static __thread int g_thread_id; static int g_next_thread_id; static int g_writing_enabled = 1; +GPR_GLOBAL_CONFIG_DEFINE_STRING(grpc_latency_trace, "latency_trace.txt", + "Output file name for latency trace") + static const char* output_filename() { if (output_filename_or_null == NULL) { - output_filename_or_null = gpr_getenv("LATENCY_TRACE"); - if (output_filename_or_null == NULL || - strlen(output_filename_or_null) == 0) { + grpc_core::UniquePtr value = + GPR_GLOBAL_CONFIG_GET(grpc_latency_trace); + if (strlen(value.get()) > 0) { + output_filename_or_null = value.release(); + } else { output_filename_or_null = "latency_trace.txt"; } } diff --git a/src/core/lib/security/context/security_context.cc b/src/core/lib/security/context/security_context.cc index 8443ee0695a..ef60165899d 100644 --- a/src/core/lib/security/context/security_context.cc +++ b/src/core/lib/security/context/security_context.cc @@ -21,8 +21,8 @@ #include #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/gpr/arena.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/gprpp/arena.h" #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/security/context/security_context.h" @@ -102,9 +102,9 @@ grpc_client_security_context::~grpc_client_security_context() { } grpc_client_security_context* grpc_client_security_context_create( - gpr_arena* arena, grpc_call_credentials* creds) { - return new (gpr_arena_alloc(arena, sizeof(grpc_client_security_context))) - grpc_client_security_context(creds != nullptr ? creds->Ref() : nullptr); + grpc_core::Arena* arena, grpc_call_credentials* creds) { + return arena->New( + creds != nullptr ? creds->Ref() : nullptr); } void grpc_client_security_context_destroy(void* ctx) { @@ -123,9 +123,8 @@ grpc_server_security_context::~grpc_server_security_context() { } grpc_server_security_context* grpc_server_security_context_create( - gpr_arena* arena) { - return new (gpr_arena_alloc(arena, sizeof(grpc_server_security_context))) - grpc_server_security_context(); + grpc_core::Arena* arena) { + return arena->New(); } void grpc_server_security_context_destroy(void* ctx) { diff --git a/src/core/lib/security/context/security_context.h b/src/core/lib/security/context/security_context.h index b43ee5e62d5..b1991089ae5 100644 --- a/src/core/lib/security/context/security_context.h +++ b/src/core/lib/security/context/security_context.h @@ -21,6 +21,7 @@ #include +#include "src/core/lib/gprpp/arena.h" #include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/pollset.h" @@ -28,8 +29,6 @@ extern grpc_core::DebugOnlyTraceFlag grpc_trace_auth_context_refcount; -struct gpr_arena; - /* --- grpc_auth_context --- High level authentication context object. Can optionally be chained. */ @@ -121,7 +120,7 @@ struct grpc_client_security_context { }; grpc_client_security_context* grpc_client_security_context_create( - gpr_arena* arena, grpc_call_credentials* creds); + grpc_core::Arena* arena, grpc_call_credentials* creds); void grpc_client_security_context_destroy(void* ctx); /* --- grpc_server_security_context --- @@ -137,7 +136,7 @@ struct grpc_server_security_context { }; grpc_server_security_context* grpc_server_security_context_create( - gpr_arena* arena); + grpc_core::Arena* arena); void grpc_server_security_context_destroy(void* ctx); /* --- Channel args for auth context --- */ diff --git a/src/core/lib/security/credentials/jwt/jwt_credentials.cc b/src/core/lib/security/credentials/jwt/jwt_credentials.cc index 70fe45e56dc..df1d05c83b3 100644 --- a/src/core/lib/security/credentials/jwt/jwt_credentials.cc +++ b/src/core/lib/security/credentials/jwt/jwt_credentials.cc @@ -160,7 +160,7 @@ static char* redact_private_key(const char* json_key) { grpc_call_credentials* grpc_service_account_jwt_access_credentials_create( const char* json_key, gpr_timespec token_lifetime, void* reserved) { - if (grpc_api_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace)) { char* clean_json = redact_private_key(json_key); gpr_log(GPR_INFO, "grpc_service_account_jwt_access_credentials_create(" diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc b/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc index b9af757d05e..b001868b3d3 100644 --- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc +++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc @@ -459,7 +459,7 @@ grpc_call_credentials* grpc_google_refresh_token_credentials_create( const char* json_refresh_token, void* reserved) { grpc_auth_refresh_token token = grpc_auth_refresh_token_create_from_string(json_refresh_token); - if (grpc_api_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace)) { char* loggable_token = create_loggable_refresh_token(&token); gpr_log(GPR_INFO, "grpc_refresh_token_credentials_create(json_refresh_token=%s, " diff --git a/src/core/lib/security/credentials/plugin/plugin_credentials.cc b/src/core/lib/security/credentials/plugin/plugin_credentials.cc index 59fecbca992..333366d0f0a 100644 --- a/src/core/lib/security/credentials/plugin/plugin_credentials.cc +++ b/src/core/lib/security/credentials/plugin/plugin_credentials.cc @@ -119,7 +119,7 @@ static void plugin_md_request_metadata_ready(void* request, GRPC_EXEC_CTX_FLAG_THREAD_RESOURCE_LOOP); grpc_plugin_credentials::pending_request* r = static_cast(request); - if (grpc_plugin_credentials_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) { gpr_log(GPR_INFO, "plugin_credentials[%p]: request %p: plugin returned " "asynchronously", @@ -132,7 +132,7 @@ static void plugin_md_request_metadata_ready(void* request, grpc_error* error = process_plugin_result(r, md, num_md, status, error_details); GRPC_CLOSURE_SCHED(r->on_request_metadata, error); - } else if (grpc_plugin_credentials_trace.enabled()) { + } else if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) { gpr_log(GPR_INFO, "plugin_credentials[%p]: request %p: plugin was previously " "cancelled", @@ -162,7 +162,7 @@ bool grpc_plugin_credentials::get_request_metadata( pending_requests_ = request; gpr_mu_unlock(&mu_); // Invoke the plugin. The callback holds a ref to us. - if (grpc_plugin_credentials_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) { gpr_log(GPR_INFO, "plugin_credentials[%p]: request %p: invoking plugin", this, request); } @@ -174,7 +174,7 @@ bool grpc_plugin_credentials::get_request_metadata( if (!plugin_.get_metadata( plugin_.state, context, plugin_md_request_metadata_ready, request, creds_md, &num_creds_md, &status, &error_details)) { - if (grpc_plugin_credentials_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) { gpr_log(GPR_INFO, "plugin_credentials[%p]: request %p: plugin will return " "asynchronously", @@ -189,7 +189,7 @@ bool grpc_plugin_credentials::get_request_metadata( // asynchronously by plugin_cancel_get_request_metadata(), so return // false. Otherwise, process the result. if (request->cancelled) { - if (grpc_plugin_credentials_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) { gpr_log(GPR_INFO, "plugin_credentials[%p]: request %p was cancelled, error " "will be returned asynchronously", @@ -197,7 +197,7 @@ bool grpc_plugin_credentials::get_request_metadata( } retval = false; } else { - if (grpc_plugin_credentials_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) { gpr_log(GPR_INFO, "plugin_credentials[%p]: request %p: plugin returned " "synchronously", @@ -223,7 +223,7 @@ void grpc_plugin_credentials::cancel_get_request_metadata( for (pending_request* pending_request = pending_requests_; pending_request != nullptr; pending_request = pending_request->next) { if (pending_request->md_array == md_array) { - if (grpc_plugin_credentials_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) { gpr_log(GPR_INFO, "plugin_credentials[%p]: cancelling request %p", this, pending_request); } diff --git a/src/core/lib/security/security_connector/load_system_roots_linux.cc b/src/core/lib/security/security_connector/load_system_roots_linux.cc index 924fa8a3e26..82d5bf6bcdd 100644 --- a/src/core/lib/security/security_connector/load_system_roots_linux.cc +++ b/src/core/lib/security/security_connector/load_system_roots_linux.cc @@ -38,12 +38,15 @@ #include #include -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/useful.h" +#include "src/core/lib/gprpp/global_config.h" #include "src/core/lib/gprpp/inlined_vector.h" #include "src/core/lib/iomgr/load_file.h" +GPR_GLOBAL_CONFIG_DEFINE_STRING(grpc_system_ssl_roots_dir, "", + "Custom directory to SSL Roots"); + namespace grpc_core { namespace { @@ -139,10 +142,9 @@ grpc_slice CreateRootCertsBundle(const char* certs_directory) { grpc_slice LoadSystemRootCerts() { grpc_slice result = grpc_empty_slice(); // Prioritize user-specified custom directory if flag is set. - char* custom_dir = gpr_getenv("GRPC_SYSTEM_SSL_ROOTS_DIR"); - if (custom_dir != nullptr) { - result = CreateRootCertsBundle(custom_dir); - gpr_free(custom_dir); + UniquePtr custom_dir = GPR_GLOBAL_CONFIG_GET(grpc_system_ssl_roots_dir); + if (strlen(custom_dir.get()) > 0) { + result = CreateRootCertsBundle(custom_dir.get()); } // If the custom directory is empty/invalid/not specified, fallback to // distribution-specific directory. diff --git a/src/core/lib/security/security_connector/security_connector.cc b/src/core/lib/security/security_connector/security_connector.cc index 96a19605466..47c0ad5aa3d 100644 --- a/src/core/lib/security/security_connector/security_connector.cc +++ b/src/core/lib/security/security_connector/security_connector.cc @@ -28,7 +28,6 @@ #include "src/core/ext/transport/chttp2/alpn/alpn.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/handshaker.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/iomgr/load_file.h" diff --git a/src/core/lib/security/security_connector/security_connector.h b/src/core/lib/security/security_connector/security_connector.h index 4c74c5cfea0..f71ee54402d 100644 --- a/src/core/lib/security/security_connector/security_connector.h +++ b/src/core/lib/security/security_connector/security_connector.h @@ -102,7 +102,7 @@ class grpc_channel_security_connector : public grpc_security_connector { grpc_auth_context* auth_context, grpc_closure* on_call_host_checked, grpc_error** error) GRPC_ABSTRACT; - /// Cancels a pending asychronous call to + /// Cancels a pending asynchronous call to /// grpc_channel_security_connector_check_call_host() with /// \a on_call_host_checked as its callback. virtual void cancel_check_call_host(grpc_closure* on_call_host_checked, diff --git a/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc b/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc index e76f4f15a7c..f920dc6046d 100644 --- a/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc +++ b/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc @@ -310,7 +310,7 @@ class grpc_ssl_server_security_connector private: /* Attempts to fetch the server certificate config if a callback is available. * Current certificate config will continue to be used if the callback returns - * an error. Returns true if new credentials were sucessfully loaded. */ + * an error. Returns true if new credentials were successfully loaded. */ bool try_fetch_ssl_server_credentials() { grpc_ssl_server_certificate_config* certificate_config = nullptr; bool status; diff --git a/src/core/lib/security/security_connector/ssl_utils.cc b/src/core/lib/security/security_connector/ssl_utils.cc index c9af5ca6ad0..cb0d5437988 100644 --- a/src/core/lib/security/security_connector/ssl_utils.cc +++ b/src/core/lib/security/security_connector/ssl_utils.cc @@ -27,9 +27,9 @@ #include "src/core/ext/transport/chttp2/alpn/alpn.h" #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/gprpp/global_config.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/load_file.h" #include "src/core/lib/security/context/security_context.h" @@ -45,11 +45,16 @@ static const char* installed_roots_path = INSTALL_PREFIX "/share/grpc/roots.pem"; #endif -/** Environment variable used as a flag to enable/disable loading system root +/** Config variable that points to the default SSL roots file. This file + must be a PEM encoded file with all the roots such as the one that can be + downloaded from https://pki.google.com/roots.pem. */ +GPR_GLOBAL_CONFIG_DEFINE_STRING(grpc_default_ssl_roots_file_path, "", + "Path to the default SSL roots file."); + +/** Config variable used as a flag to enable/disable loading system root certificates from the OS trust store. */ -#ifndef GRPC_NOT_USE_SYSTEM_SSL_ROOTS_ENV_VAR -#define GRPC_NOT_USE_SYSTEM_SSL_ROOTS_ENV_VAR "GRPC_NOT_USE_SYSTEM_SSL_ROOTS" -#endif +GPR_GLOBAL_CONFIG_DEFINE_BOOL(grpc_not_use_system_ssl_roots, false, + "Disable loading system root certificates."); #ifndef TSI_OPENSSL_ALPN_SUPPORT #define TSI_OPENSSL_ALPN_SUPPORT 1 @@ -65,20 +70,22 @@ void grpc_set_ssl_roots_override_callback(grpc_ssl_roots_override_callback cb) { /* -- Cipher suites. -- */ -/* Defines the cipher suites that we accept by default. All these cipher suites - are compliant with HTTP2. */ -#define GRPC_SSL_CIPHER_SUITES \ - "ECDHE-ECDSA-AES128-GCM-SHA256:" \ - "ECDHE-ECDSA-AES256-GCM-SHA384:" \ - "ECDHE-RSA-AES128-GCM-SHA256:" \ - "ECDHE-RSA-AES256-GCM-SHA384" - static gpr_once cipher_suites_once = GPR_ONCE_INIT; static const char* cipher_suites = nullptr; +// All cipher suites for default are compliant with HTTP2. +GPR_GLOBAL_CONFIG_DEFINE_STRING( + grpc_ssl_cipher_suites, + "ECDHE-ECDSA-AES128-GCM-SHA256:" + "ECDHE-ECDSA-AES256-GCM-SHA384:" + "ECDHE-RSA-AES128-GCM-SHA256:" + "ECDHE-RSA-AES256-GCM-SHA384", + "A colon separated list of cipher suites to use with OpenSSL") + static void init_cipher_suites(void) { - char* overridden = gpr_getenv("GRPC_SSL_CIPHER_SUITES"); - cipher_suites = overridden != nullptr ? overridden : GRPC_SSL_CIPHER_SUITES; + grpc_core::UniquePtr value = + GPR_GLOBAL_CONFIG_GET(grpc_ssl_cipher_suites); + cipher_suites = value.release(); } /* --- Util --- */ @@ -428,17 +435,14 @@ const char* DefaultSslRootStore::GetPemRootCerts() { grpc_slice DefaultSslRootStore::ComputePemRootCerts() { grpc_slice result = grpc_empty_slice(); - char* not_use_system_roots_env_value = - gpr_getenv(GRPC_NOT_USE_SYSTEM_SSL_ROOTS_ENV_VAR); - const bool not_use_system_roots = gpr_is_true(not_use_system_roots_env_value); - gpr_free(not_use_system_roots_env_value); - // First try to load the roots from the environment. - char* default_root_certs_path = - gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR); - if (default_root_certs_path != nullptr) { - GRPC_LOG_IF_ERROR("load_file", - grpc_load_file(default_root_certs_path, 1, &result)); - gpr_free(default_root_certs_path); + const bool not_use_system_roots = + GPR_GLOBAL_CONFIG_GET(grpc_not_use_system_ssl_roots); + // First try to load the roots from the configuration. + UniquePtr default_root_certs_path = + GPR_GLOBAL_CONFIG_GET(grpc_default_ssl_roots_file_path); + if (strlen(default_root_certs_path.get()) > 0) { + GRPC_LOG_IF_ERROR( + "load_file", grpc_load_file(default_root_certs_path.get(), 1, &result)); } // Try overridden roots if needed. grpc_ssl_roots_override_result ovrd_res = GRPC_SSL_ROOTS_OVERRIDE_FAIL; diff --git a/src/core/lib/security/security_connector/ssl_utils.h b/src/core/lib/security/security_connector/ssl_utils.h index 080e277f944..1765a344c2a 100644 --- a/src/core/lib/security/security_connector/ssl_utils.h +++ b/src/core/lib/security/security_connector/ssl_utils.h @@ -26,6 +26,7 @@ #include #include +#include "src/core/lib/gprpp/global_config.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/error.h" #include "src/core/lib/security/security_connector/security_connector.h" @@ -33,7 +34,10 @@ #include "src/core/tsi/transport_security.h" #include "src/core/tsi/transport_security_interface.h" -/* --- Util. --- */ +GPR_GLOBAL_CONFIG_DECLARE_STRING(grpc_default_ssl_roots_file_path); +GPR_GLOBAL_CONFIG_DECLARE_BOOL(grpc_not_use_system_ssl_roots); + +/* --- Util --- */ /* --- URL schemes. --- */ #define GRPC_SSL_URL_SCHEME "https" diff --git a/src/core/lib/security/transport/client_auth_filter.cc b/src/core/lib/security/transport/client_auth_filter.cc index f90c92efdc2..0c40dd7ff1e 100644 --- a/src/core/lib/security/transport/client_auth_filter.cc +++ b/src/core/lib/security/transport/client_auth_filter.cc @@ -92,7 +92,7 @@ struct call_data { } grpc_call_stack* owning_call; - grpc_call_combiner* call_combiner; + grpc_core::CallCombiner* call_combiner; grpc_core::RefCountedPtr creds; grpc_slice host = grpc_empty_slice(); grpc_slice method = grpc_empty_slice(); @@ -270,11 +270,9 @@ static void send_security_metadata(grpc_call_element* elem, GRPC_ERROR_UNREF(error); } else { // Async return; register cancellation closure with call combiner. - grpc_call_combiner_set_notify_on_cancel( - calld->call_combiner, - GRPC_CLOSURE_INIT(&calld->get_request_metadata_cancel_closure, - cancel_get_request_metadata, elem, - grpc_schedule_on_exec_ctx)); + calld->call_combiner->SetNotifyOnCancel(GRPC_CLOSURE_INIT( + &calld->get_request_metadata_cancel_closure, + cancel_get_request_metadata, elem, grpc_schedule_on_exec_ctx)); } } @@ -345,11 +343,9 @@ static void auth_start_transport_stream_op_batch( GRPC_ERROR_UNREF(error); } else { // Async return; register cancellation closure with call combiner. - grpc_call_combiner_set_notify_on_cancel( - calld->call_combiner, - GRPC_CLOSURE_INIT(&calld->check_call_host_cancel_closure, - cancel_check_call_host, elem, - grpc_schedule_on_exec_ctx)); + calld->call_combiner->SetNotifyOnCancel(GRPC_CLOSURE_INIT( + &calld->check_call_host_cancel_closure, cancel_check_call_host, + elem, grpc_schedule_on_exec_ctx)); } gpr_free(call_host); return; /* early exit */ diff --git a/src/core/lib/security/transport/secure_endpoint.cc b/src/core/lib/security/transport/secure_endpoint.cc index 2a862492bd7..0aac7d8d780 100644 --- a/src/core/lib/security/transport/secure_endpoint.cc +++ b/src/core/lib/security/transport/secure_endpoint.cc @@ -113,7 +113,7 @@ static void destroy(secure_endpoint* ep) { grpc_core::Delete(ep); } secure_endpoint_ref((ep), (reason), __FILE__, __LINE__) static void secure_endpoint_unref(secure_endpoint* ep, const char* reason, const char* file, int line) { - if (grpc_trace_secure_endpoint.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_secure_endpoint)) { gpr_atm val = gpr_atm_no_barrier_load(&ep->ref.count); gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP unref %p : %s %" PRIdPTR " -> %" PRIdPTR, ep, reason, val, @@ -126,7 +126,7 @@ static void secure_endpoint_unref(secure_endpoint* ep, const char* reason, static void secure_endpoint_ref(secure_endpoint* ep, const char* reason, const char* file, int line) { - if (grpc_trace_secure_endpoint.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_secure_endpoint)) { gpr_atm val = gpr_atm_no_barrier_load(&ep->ref.count); gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "SECENDP ref %p : %s %" PRIdPTR " -> %" PRIdPTR, ep, reason, val, @@ -155,7 +155,7 @@ static void flush_read_staging_buffer(secure_endpoint* ep, uint8_t** cur, } static void call_read_cb(secure_endpoint* ep, grpc_error* error) { - if (grpc_trace_secure_endpoint.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_secure_endpoint)) { size_t i; for (i = 0; i < ep->read_buffer->count; i++) { char* data = grpc_dump_slice(ep->read_buffer->slices[i], @@ -292,7 +292,7 @@ static void endpoint_write(grpc_endpoint* secure_ep, grpc_slice_buffer* slices, grpc_slice_buffer_reset_and_unref_internal(&ep->output_buffer); - if (grpc_trace_secure_endpoint.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_secure_endpoint)) { for (i = 0; i < slices->count; i++) { char* data = grpc_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); diff --git a/src/core/lib/security/transport/security_handshaker.cc b/src/core/lib/security/transport/security_handshaker.cc index 3605bbe5974..fdc64727b96 100644 --- a/src/core/lib/security/transport/security_handshaker.cc +++ b/src/core/lib/security/transport/security_handshaker.cc @@ -144,11 +144,11 @@ size_t SecurityHandshaker::MoveReadBufferIntoHandshakeBuffer() { } size_t offset = 0; while (args_->read_buffer->count > 0) { - grpc_slice next_slice = grpc_slice_buffer_take_first(args_->read_buffer); - memcpy(handshake_buffer_ + offset, GRPC_SLICE_START_PTR(next_slice), - GRPC_SLICE_LENGTH(next_slice)); - offset += GRPC_SLICE_LENGTH(next_slice); - grpc_slice_unref_internal(next_slice); + grpc_slice* next_slice = grpc_slice_buffer_peek_first(args_->read_buffer); + memcpy(handshake_buffer_ + offset, GRPC_SLICE_START_PTR(*next_slice), + GRPC_SLICE_LENGTH(*next_slice)); + offset += GRPC_SLICE_LENGTH(*next_slice); + grpc_slice_buffer_remove_first(args_->read_buffer); } return bytes_in_read_buffer; } diff --git a/src/core/lib/security/transport/server_auth_filter.cc b/src/core/lib/security/transport/server_auth_filter.cc index 81b9c2ce074..43509e6c61b 100644 --- a/src/core/lib/security/transport/server_auth_filter.cc +++ b/src/core/lib/security/transport/server_auth_filter.cc @@ -74,7 +74,7 @@ struct call_data { ~call_data() { GRPC_ERROR_UNREF(recv_initial_metadata_error); } - grpc_call_combiner* call_combiner; + grpc_core::CallCombiner* call_combiner; grpc_call_stack* owning_call; grpc_transport_stream_op_batch* recv_initial_metadata_batch; grpc_closure* original_recv_initial_metadata_ready; @@ -219,8 +219,7 @@ static void recv_initial_metadata_ready(void* arg, grpc_error* error) { // to drop the call combiner early if we get cancelled. GRPC_CLOSURE_INIT(&calld->cancel_closure, cancel_call, elem, grpc_schedule_on_exec_ctx); - grpc_call_combiner_set_notify_on_cancel(calld->call_combiner, - &calld->cancel_closure); + calld->call_combiner->SetNotifyOnCancel(&calld->cancel_closure); GRPC_CALL_STACK_REF(calld->owning_call, "server_auth_metadata"); calld->md = metadata_batch_to_md_array( batch->payload->recv_initial_metadata.recv_initial_metadata); diff --git a/src/core/lib/slice/b64.h b/src/core/lib/slice/b64.h index 4475568c25b..88b880a4542 100644 --- a/src/core/lib/slice/b64.h +++ b/src/core/lib/slice/b64.h @@ -23,7 +23,7 @@ #include -/* Encodes data using base64. It is the caller's responsability to free +/* Encodes data using base64. It is the caller's responsibility to free the returned char * using gpr_free. Returns NULL on NULL input. TODO(makdharma) : change the flags to bool from int */ char* grpc_base64_encode(const void* data, size_t data_size, int url_safe, @@ -35,7 +35,7 @@ size_t grpc_base64_estimate_encoded_size(size_t data_size, int url_safe, int multiline); /* Encodes data using base64 and write it to memory pointed to by result. It is - * the caller's responsiblity to allocate enough memory in |result| to fit the + * the caller's responsibility to allocate enough memory in |result| to fit the * encoded data. */ void grpc_base64_encode_core(char* result, const void* vdata, size_t data_size, int url_safe, int multiline); diff --git a/src/core/lib/slice/slice.cc b/src/core/lib/slice/slice.cc index 2bf2b0f499f..75acb28e99c 100644 --- a/src/core/lib/slice/slice.cc +++ b/src/core/lib/slice/slice.cc @@ -410,6 +410,31 @@ int grpc_slice_eq(grpc_slice a, grpc_slice b) { return grpc_slice_default_eq_impl(a, b); } +int grpc_slice_differs_refcounted(const grpc_slice& a, + const grpc_slice& b_not_inline) { + size_t a_len; + const uint8_t* a_ptr; + if (a.refcount) { + a_len = a.data.refcounted.length; + a_ptr = a.data.refcounted.bytes; + } else { + a_len = a.data.inlined.length; + a_ptr = &a.data.inlined.bytes[0]; + } + if (a_len != b_not_inline.data.refcounted.length) { + return true; + } + if (a_len == 0) { + return false; + } + // This check *must* occur after the a_len == 0 check + // to retain compatibility with grpc_slice_eq. + if (a_ptr == nullptr) { + return true; + } + return memcmp(a_ptr, b_not_inline.data.refcounted.bytes, a_len); +} + int grpc_slice_cmp(grpc_slice a, grpc_slice b) { int d = static_cast(GRPC_SLICE_LENGTH(a) - GRPC_SLICE_LENGTH(b)); if (d != 0) return d; diff --git a/src/core/lib/slice/slice_buffer.cc b/src/core/lib/slice/slice_buffer.cc index 1f1c08b1594..e1929250d4a 100644 --- a/src/core/lib/slice/slice_buffer.cc +++ b/src/core/lib/slice/slice_buffer.cc @@ -33,6 +33,10 @@ #define GROW(x) (3 * (x) / 2) static void maybe_embiggen(grpc_slice_buffer* sb) { + if (sb->count == 0) { + sb->slices = sb->base_slices; + } + /* How far away from sb->base_slices is sb->slices pointer */ size_t slice_offset = static_cast(sb->slices - sb->base_slices); size_t slice_count = sb->count + slice_offset; @@ -177,6 +181,7 @@ void grpc_slice_buffer_reset_and_unref_internal(grpc_slice_buffer* sb) { sb->count = 0; sb->length = 0; + sb->slices = sb->base_slices; } void grpc_slice_buffer_reset_and_unref(grpc_slice_buffer* sb) { @@ -370,6 +375,24 @@ grpc_slice grpc_slice_buffer_take_first(grpc_slice_buffer* sb) { return slice; } +void grpc_slice_buffer_remove_first(grpc_slice_buffer* sb) { + GPR_DEBUG_ASSERT(sb->count > 0); + sb->length -= GRPC_SLICE_LENGTH(sb->slices[0]); + grpc_slice_unref_internal(sb->slices[0]); + sb->slices++; + if (--sb->count == 0) { + sb->slices = sb->base_slices; + } +} + +void grpc_slice_buffer_sub_first(grpc_slice_buffer* sb, size_t begin, + size_t end) { + // TODO(soheil): Introduce a ptr version for sub. + sb->length -= GRPC_SLICE_LENGTH(sb->slices[0]); + sb->slices[0] = grpc_slice_sub_no_ref(sb->slices[0], begin, end); + sb->length += end - begin; +} + void grpc_slice_buffer_undo_take_first(grpc_slice_buffer* sb, grpc_slice slice) { sb->slices--; diff --git a/src/core/lib/slice/slice_intern.cc b/src/core/lib/slice/slice_intern.cc index 0f190c186fa..15909d9b96f 100644 --- a/src/core/lib/slice/slice_intern.cc +++ b/src/core/lib/slice/slice_intern.cc @@ -19,6 +19,7 @@ #include #include "src/core/lib/slice/slice_internal.h" +#include "src/core/lib/slice/slice_utils.h" #include #include @@ -143,7 +144,8 @@ grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice, static_metadata_hash_ent ent = static_metadata_hash[(hash + i) % GPR_ARRAY_SIZE(static_metadata_hash)]; if (ent.hash == hash && ent.idx < GRPC_STATIC_MDSTR_COUNT && - grpc_slice_eq(grpc_static_slice_table[ent.idx], slice)) { + grpc_slice_eq_static_interned(slice, + grpc_static_slice_table[ent.idx])) { *returned_slice_is_different = true; return grpc_static_slice_table[ent.idx]; } @@ -170,7 +172,8 @@ grpc_slice grpc_slice_intern(grpc_slice slice) { static_metadata_hash_ent ent = static_metadata_hash[(hash + i) % GPR_ARRAY_SIZE(static_metadata_hash)]; if (ent.hash == hash && ent.idx < GRPC_STATIC_MDSTR_COUNT && - grpc_slice_eq(grpc_static_slice_table[ent.idx], slice)) { + grpc_slice_eq_static_interned(slice, + grpc_static_slice_table[ent.idx])) { return grpc_static_slice_table[ent.idx]; } } @@ -183,7 +186,8 @@ grpc_slice grpc_slice_intern(grpc_slice slice) { /* search for an existing string */ size_t idx = TABLE_IDX(hash, shard->capacity); for (s = shard->strs[idx]; s; s = s->bucket_next) { - if (s->hash == hash && grpc_slice_eq(slice, materialize(s))) { + if (s->hash == hash && + grpc_slice_eq_static_interned(slice, materialize(s))) { if (s->refcnt.RefIfNonZero()) { gpr_mu_unlock(&shard->mu); return materialize(s); diff --git a/src/core/lib/slice/slice_internal.h b/src/core/lib/slice/slice_internal.h index db8c8e5c7cc..e4aba015315 100644 --- a/src/core/lib/slice/slice_internal.h +++ b/src/core/lib/slice/slice_internal.h @@ -21,6 +21,8 @@ #include +#include + #include #include #include @@ -222,7 +224,7 @@ inline uint32_t grpc_slice_refcount::Hash(const grpc_slice& slice) { g_hash_seed); } -inline grpc_slice grpc_slice_ref_internal(const grpc_slice& slice) { +inline const grpc_slice& grpc_slice_ref_internal(const grpc_slice& slice) { if (slice.refcount) { slice.refcount->Ref(); } @@ -240,6 +242,20 @@ void grpc_slice_buffer_partial_unref_internal(grpc_slice_buffer* sb, size_t idx); void grpc_slice_buffer_destroy_internal(grpc_slice_buffer* sb); +// Returns a pointer to the first slice in the slice buffer without giving +// ownership to or a reference count on that slice. +inline grpc_slice* grpc_slice_buffer_peek_first(grpc_slice_buffer* sb) { + GPR_DEBUG_ASSERT(sb->count > 0); + return &sb->slices[0]; +} + +// Removes the first slice from the slice buffer. +void grpc_slice_buffer_remove_first(grpc_slice_buffer* sb); + +// Calls grpc_slice_sub with the given parameters on the first slice. +void grpc_slice_buffer_sub_first(grpc_slice_buffer* sb, size_t begin, + size_t end); + /* Check if a slice is interned */ bool grpc_slice_is_interned(const grpc_slice& slice); diff --git a/src/core/lib/slice/slice_utils.h b/src/core/lib/slice/slice_utils.h new file mode 100644 index 00000000000..7589bf8f0f7 --- /dev/null +++ b/src/core/lib/slice/slice_utils.h @@ -0,0 +1,50 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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_LIB_SLICE_SLICE_UTILS_H +#define GRPC_CORE_LIB_SLICE_SLICE_UTILS_H + +#include + +#include + +// When we compare two slices, and we know the latter is not inlined, we can +// short circuit our comparison operator. We specifically use differs() +// semantics instead of equals() semantics due to more favourable code +// generation when using differs(). Specifically, we may use the output of +// grpc_slice_differs_refcounted for control flow. If we use differs() +// semantics, we end with a tailcall to memcmp(). If we use equals() semantics, +// we need to invert the result that memcmp provides us, which costs several +// instructions to do so. If we're using the result for control flow (i.e. +// branching based on the output) then we're just performing the extra +// operations to invert the result pointlessly. Concretely, we save 6 ops on +// x86-64/clang with differs(). +int grpc_slice_differs_refcounted(const grpc_slice& a, + const grpc_slice& b_not_inline); +// When we compare two slices, and we *know* that one of them is static or +// interned, we can short circuit our slice equality function. The second slice +// here must be static or interned; slice a can be any slice, inlined or not. +inline bool grpc_slice_eq_static_interned(const grpc_slice& a, + const grpc_slice& b_static_interned) { + if (a.refcount == b_static_interned.refcount) { + return true; + } + return !grpc_slice_differs_refcounted(a, b_static_interned); +} + +#endif /* GRPC_CORE_LIB_SLICE_SLICE_UTILS_H */ diff --git a/src/core/lib/surface/api_trace.h b/src/core/lib/surface/api_trace.h index 72ed830554f..51d1f522230 100644 --- a/src/core/lib/surface/api_trace.h +++ b/src/core/lib/surface/api_trace.h @@ -45,7 +45,7 @@ extern grpc_core::TraceFlag grpc_api_trace; /* Due to the limitations of C89's preprocessor, the arity of the var-arg list 'nargs' must be specified. */ #define GRPC_API_TRACE(fmt, nargs, args) \ - if (grpc_api_trace.enabled()) { \ + if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace)) { \ gpr_log(GPR_INFO, fmt GRPC_API_TRACE_UNWRAP##nargs args); \ } diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc index 8aaff4a67d5..254476f47e3 100644 --- a/src/core/lib/surface/call.cc +++ b/src/core/lib/surface/call.cc @@ -35,14 +35,15 @@ #include "src/core/lib/compression/algorithm_metadata.h" #include "src/core/lib/debug/stats.h" #include "src/core/lib/gpr/alloc.h" -#include "src/core/lib/gpr/arena.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/useful.h" +#include "src/core/lib/gprpp/arena.h" #include "src/core/lib/gprpp/manual_constructor.h" +#include "src/core/lib/gprpp/ref_counted.h" #include "src/core/lib/iomgr/timer.h" #include "src/core/lib/profiling/timers.h" -#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_string_helpers.h" +#include "src/core/lib/slice/slice_utils.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/call.h" #include "src/core/lib/surface/call_test_only.h" @@ -124,14 +125,12 @@ struct child_call { #define RECV_INITIAL_METADATA_FIRST ((gpr_atm)1) struct grpc_call { - grpc_call(gpr_arena* arena, const grpc_call_create_args& args) + grpc_call(grpc_core::Arena* arena, const grpc_call_create_args& args) : arena(arena), cq(args.cq), channel(args.channel), is_client(args.server_transport_data == nullptr), stream_op_payload(context) { - gpr_ref_init(&ext_ref, 1); - grpc_call_combiner_init(&call_combiner); for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { metadata_batch[i][j].deadline = GRPC_MILLIS_INF_FUTURE; @@ -141,12 +140,11 @@ struct grpc_call { ~grpc_call() { gpr_free(static_cast(const_cast(final_info.error_string))); - grpc_call_combiner_destroy(&call_combiner); } - gpr_refcount ext_ref; - gpr_arena* arena; - grpc_call_combiner call_combiner; + grpc_core::RefCount ext_ref; + grpc_core::Arena* arena; + grpc_core::CallCombiner call_combiner; grpc_completion_queue* cq; grpc_polling_entity pollent; grpc_channel* channel; @@ -292,13 +290,13 @@ static void add_init_error(grpc_error** composite, grpc_error* new_err) { } void* grpc_call_arena_alloc(grpc_call* call, size_t size) { - return gpr_arena_alloc(call->arena, size); + return call->arena->Alloc(size); } static parent_call* get_or_create_parent_call(grpc_call* call) { parent_call* p = (parent_call*)gpr_atm_acq_load(&call->parent_call_atm); if (p == nullptr) { - p = new (gpr_arena_alloc(call->arena, sizeof(*p))) parent_call(); + p = call->arena->New(); if (!gpr_atm_rel_cas(&call->parent_call_atm, (gpr_atm) nullptr, (gpr_atm)p)) { p->~parent_call(); @@ -323,16 +321,23 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args, GRPC_CHANNEL_INTERNAL_REF(args->channel, "call"); + grpc_core::Arena* arena; + grpc_call* call; grpc_error* error = GRPC_ERROR_NONE; grpc_channel_stack* channel_stack = grpc_channel_get_channel_stack(args->channel); - grpc_call* call; size_t initial_size = grpc_channel_get_call_size_estimate(args->channel); GRPC_STATS_INC_CALL_INITIAL_SIZE(initial_size); - gpr_arena* arena = gpr_arena_create(initial_size); - call = new (gpr_arena_alloc( - arena, GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call)) + - channel_stack->call_stack_size)) grpc_call(arena, *args); + size_t call_and_stack_size = + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call)) + + channel_stack->call_stack_size; + size_t call_alloc_size = + call_and_stack_size + (args->parent ? sizeof(child_call) : 0); + + std::pair arena_with_call = + grpc_core::Arena::CreateWithAlloc(initial_size, call_alloc_size); + arena = arena_with_call.first; + call = new (arena_with_call.second) grpc_call(arena, *args); *out_call = call; grpc_slice path = grpc_empty_slice(); if (call->is_client) { @@ -344,8 +349,8 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args, MAX_SEND_EXTRA_METADATA_COUNT); for (size_t i = 0; i < args->add_initial_metadata_count; i++) { call->send_extra_metadata[i].md = args->add_initial_metadata[i]; - if (grpc_slice_eq(GRPC_MDKEY(args->add_initial_metadata[i]), - GRPC_MDSTR_PATH)) { + if (grpc_slice_eq_static_interned( + GRPC_MDKEY(args->add_initial_metadata[i]), GRPC_MDSTR_PATH)) { path = grpc_slice_ref_internal( GRPC_MDVALUE(args->add_initial_metadata[i])); } @@ -364,8 +369,8 @@ grpc_error* grpc_call_create(const grpc_call_create_args* args, bool immediately_cancel = false; if (args->parent != nullptr) { - call->child = new (gpr_arena_alloc(arena, sizeof(child_call))) - child_call(args->parent); + call->child = new (reinterpret_cast(arena_with_call.second) + + call_and_stack_size) child_call(args->parent); GRPC_CALL_INTERNAL_REF(args->parent, "child"); GPR_ASSERT(call->is_client); @@ -502,9 +507,9 @@ void grpc_call_internal_unref(grpc_call* c REF_ARG) { static void release_call(void* call, grpc_error* error) { grpc_call* c = static_cast(call); grpc_channel* channel = c->channel; - gpr_arena* arena = c->arena; + grpc_core::Arena* arena = c->arena; c->~grpc_call(); - grpc_channel_update_call_size_estimate(channel, gpr_arena_destroy(arena)); + grpc_channel_update_call_size_estimate(channel, arena->Destroy()); GRPC_CHANNEL_INTERNAL_UNREF(channel, "call"); } @@ -548,10 +553,10 @@ static void destroy_call(void* call, grpc_error* error) { grpc_schedule_on_exec_ctx)); } -void grpc_call_ref(grpc_call* c) { gpr_ref(&c->ext_ref); } +void grpc_call_ref(grpc_call* c) { c->ext_ref.Ref(); } void grpc_call_unref(grpc_call* c) { - if (!gpr_unref(&c->ext_ref)) return; + if (GPR_LIKELY(!c->ext_ref.Unref())) return; GPR_TIMER_SCOPE("grpc_call_unref", 0); @@ -589,7 +594,7 @@ void grpc_call_unref(grpc_call* c) { // holding to the call stack. Also flush the closures on exec_ctx so that // filters that schedule cancel notification closures on exec_ctx do not // need to take a ref of the call stack to guarantee closure liveness. - grpc_call_combiner_set_notify_on_cancel(&c->call_combiner, nullptr); + c->call_combiner.SetNotifyOnCancel(nullptr); grpc_core::ExecCtx::Get()->Flush(); } GRPC_CALL_INTERNAL_UNREF(c, "destroy"); @@ -685,7 +690,7 @@ static void cancel_with_error(grpc_call* c, grpc_error* error) { // any in-flight asynchronous actions that may be holding the call // combiner. This ensures that the cancel_stream batch can be sent // down the filter stack in a timely manner. - grpc_call_combiner_cancel(&c->call_combiner, GRPC_ERROR_REF(error)); + c->call_combiner.Cancel(GRPC_ERROR_REF(error)); cancel_state* state = static_cast(gpr_malloc(sizeof(*state))); state->call = c; GRPC_CLOSURE_INIT(&state->finish_batch, done_termination, state, @@ -718,7 +723,7 @@ static void cancel_with_status(grpc_call* c, grpc_status_code status, } static void set_final_status(grpc_call* call, grpc_error* error) { - if (grpc_call_error_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_call_error_trace)) { gpr_log(GPR_DEBUG, "set_final_status %s", call->is_client ? "CLI" : "SVR"); gpr_log(GPR_DEBUG, "%s", grpc_error_string(error)); } @@ -1069,7 +1074,7 @@ static void recv_trailing_filter(void* args, grpc_metadata_batch* b, publish_app_metadata(call, b, true); } -gpr_arena* grpc_call_get_arena(grpc_call* call) { return call->arena; } +grpc_core::Arena* grpc_call_get_arena(grpc_call* call) { return call->arena; } grpc_call_stack* grpc_call_get_call_stack(grpc_call* call) { return CALL_STACK_FROM_CALL(call); @@ -1130,8 +1135,7 @@ static batch_control* reuse_or_allocate_batch_control(grpc_call* call, bctl->~batch_control(); bctl->op = {}; } else { - bctl = new (gpr_arena_alloc(call->arena, sizeof(batch_control))) - batch_control(); + bctl = call->arena->New(); *pslot = bctl; } bctl->call = call; @@ -1221,7 +1225,7 @@ static void post_batch_completion(batch_control* bctl) { } static void finish_batch_step(batch_control* bctl) { - if (gpr_unref(&bctl->steps_to_complete)) { + if (GPR_UNLIKELY(gpr_unref(&bctl->steps_to_complete))) { post_batch_completion(bctl); } } @@ -1276,7 +1280,7 @@ static void receiving_slice_ready(void* bctlp, grpc_error* error) { } if (error != GRPC_ERROR_NONE) { - if (grpc_trace_operation_failures.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures)) { GRPC_LOG_IF_ERROR("receiving_slice_ready", GRPC_ERROR_REF(error)); } call->receiving_stream.reset(); @@ -1400,7 +1404,7 @@ static void validate_filtered_metadata(batch_control* bctl) { GPR_ASSERT(call->encodings_accepted_by_peer != 0); if (!GPR_BITGET(call->encodings_accepted_by_peer, compression_algorithm)) { - if (grpc_compression_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_compression_trace)) { const char* algo_name = nullptr; grpc_compression_algorithm_name(compression_algorithm, &algo_name); gpr_log(GPR_ERROR, @@ -1559,7 +1563,10 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops, goto done_with_error; } /* process compression level */ - memset(&call->compression_md, 0, sizeof(call->compression_md)); + grpc_metadata& compression_md = call->compression_md; + compression_md.key = grpc_empty_slice(); + compression_md.value = grpc_empty_slice(); + compression_md.flags = 0; size_t additional_metadata_count = 0; grpc_compression_level effective_compression_level = GRPC_COMPRESS_LEVEL_NONE; @@ -1582,8 +1589,8 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops, call, effective_compression_level); /* the following will be picked up by the compress filter and used * as the call's compression algorithm. */ - call->compression_md.key = GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST; - call->compression_md.value = grpc_compression_algorithm_slice(calgo); + compression_md.key = GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST; + compression_md.value = grpc_compression_algorithm_slice(calgo); additional_metadata_count++; } @@ -1597,8 +1604,7 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops, if (!prepare_application_metadata( call, static_cast(op->data.send_initial_metadata.count), op->data.send_initial_metadata.metadata, 0, call->is_client, - &call->compression_md, - static_cast(additional_metadata_count))) { + &compression_md, static_cast(additional_metadata_count))) { error = GRPC_CALL_ERROR_INVALID_METADATA; goto done_with_error; } diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h index bd7295fe110..15392fea6dc 100644 --- a/src/core/lib/surface/call.h +++ b/src/core/lib/surface/call.h @@ -23,6 +23,7 @@ #include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/channel/context.h" +#include "src/core/lib/gprpp/arena.h" #include "src/core/lib/surface/api_trace.h" #include @@ -72,7 +73,7 @@ void grpc_call_internal_unref(grpc_call* call); #define GRPC_CALL_INTERNAL_UNREF(call, reason) grpc_call_internal_unref(call) #endif -gpr_arena* grpc_call_get_arena(grpc_call* call); +grpc_core::Arena* grpc_call_get_arena(grpc_call* call); grpc_call_stack* grpc_call_get_call_stack(grpc_call* call); @@ -101,7 +102,11 @@ void grpc_call_context_set(grpc_call* call, grpc_context_index elem, void* grpc_call_context_get(grpc_call* call, grpc_context_index elem); #define GRPC_CALL_LOG_BATCH(sev, call, ops, nops, tag) \ - if (grpc_api_trace.enabled()) grpc_call_log_batch(sev, call, ops, nops, tag) + do { \ + if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace)) { \ + grpc_call_log_batch(sev, call, ops, nops, tag); \ + } \ + } while (0) uint8_t grpc_call_is_client(grpc_call* call); diff --git a/src/core/lib/surface/call_details.cc b/src/core/lib/surface/call_details.cc index 7f20b1dae74..55e9e3425f2 100644 --- a/src/core/lib/surface/call_details.cc +++ b/src/core/lib/surface/call_details.cc @@ -29,7 +29,6 @@ void grpc_call_details_init(grpc_call_details* cd) { GRPC_API_TRACE("grpc_call_details_init(cd=%p)", 1, (cd)); - memset(cd, 0, sizeof(*cd)); cd->method = grpc_empty_slice(); cd->host = grpc_empty_slice(); } diff --git a/src/core/lib/surface/completion_queue.cc b/src/core/lib/surface/completion_queue.cc index 7d679204bac..e796071eedc 100644 --- a/src/core/lib/surface/completion_queue.cc +++ b/src/core/lib/surface/completion_queue.cc @@ -411,13 +411,16 @@ static const cq_vtable g_cq_vtable[] = { grpc_core::TraceFlag grpc_cq_pluck_trace(false, "queue_pluck"); -#define GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, event) \ - if (grpc_api_trace.enabled() && (grpc_cq_pluck_trace.enabled() || \ - (event)->type != GRPC_QUEUE_TIMEOUT)) { \ - char* _ev = grpc_event_string(event); \ - gpr_log(GPR_INFO, "RETURN_EVENT[%p]: %s", cq, _ev); \ - gpr_free(_ev); \ - } +#define GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, event) \ + do { \ + if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace) && \ + (GRPC_TRACE_FLAG_ENABLED(grpc_cq_pluck_trace) || \ + (event)->type != GRPC_QUEUE_TIMEOUT)) { \ + char* _ev = grpc_event_string(event); \ + gpr_log(GPR_INFO, "RETURN_EVENT[%p]: %s", cq, _ev); \ + gpr_free(_ev); \ + } \ + } while (0) static void on_pollset_shutdown_done(void* cq, grpc_error* error); @@ -572,7 +575,7 @@ int grpc_get_cq_poll_num(grpc_completion_queue* cq) { #ifndef NDEBUG void grpc_cq_internal_ref(grpc_completion_queue* cq, const char* reason, const char* file, int line) { - if (grpc_trace_cq_refcount.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_cq_refcount)) { gpr_atm val = gpr_atm_no_barrier_load(&cq->owning_refs.count); gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p ref %" PRIdPTR " -> %" PRIdPTR " %s", cq, val, val + 1, @@ -592,7 +595,7 @@ static void on_pollset_shutdown_done(void* arg, grpc_error* error) { #ifndef NDEBUG void grpc_cq_internal_unref(grpc_completion_queue* cq, const char* reason, const char* file, int line) { - if (grpc_trace_cq_refcount.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_cq_refcount)) { gpr_atm val = gpr_atm_no_barrier_load(&cq->owning_refs.count); gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p unref %" PRIdPTR " -> %" PRIdPTR " %s", cq, val, val - 1, @@ -678,14 +681,16 @@ static void cq_end_op_for_next(grpc_completion_queue* cq, void* tag, void* done_arg, grpc_cq_completion* storage) { GPR_TIMER_SCOPE("cq_end_op_for_next", 0); - if (grpc_api_trace.enabled() || - (grpc_trace_operation_failures.enabled() && error != GRPC_ERROR_NONE)) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace) || + (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) && + error != GRPC_ERROR_NONE)) { const char* errmsg = grpc_error_string(error); GRPC_API_TRACE( "cq_end_op_for_next(cq=%p, tag=%p, error=%s, " "done=%p, done_arg=%p, storage=%p)", 6, (cq, tag, errmsg, done, done_arg, storage)); - if (grpc_trace_operation_failures.enabled() && error != GRPC_ERROR_NONE) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) && + error != GRPC_ERROR_NONE) { gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg); } } @@ -759,14 +764,16 @@ static void cq_end_op_for_pluck(grpc_completion_queue* cq, void* tag, cq_pluck_data* cqd = static_cast DATA_FROM_CQ(cq); int is_success = (error == GRPC_ERROR_NONE); - if (grpc_api_trace.enabled() || - (grpc_trace_operation_failures.enabled() && error != GRPC_ERROR_NONE)) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace) || + (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) && + error != GRPC_ERROR_NONE)) { const char* errmsg = grpc_error_string(error); GRPC_API_TRACE( "cq_end_op_for_pluck(cq=%p, tag=%p, error=%s, " "done=%p, done_arg=%p, storage=%p)", 6, (cq, tag, errmsg, done, done_arg, storage)); - if (grpc_trace_operation_failures.enabled() && error != GRPC_ERROR_NONE) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) && + error != GRPC_ERROR_NONE) { gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg); } } @@ -824,14 +831,16 @@ static void cq_end_op_for_callback( cq_callback_data* cqd = static_cast DATA_FROM_CQ(cq); bool is_success = (error == GRPC_ERROR_NONE); - if (grpc_api_trace.enabled() || - (grpc_trace_operation_failures.enabled() && error != GRPC_ERROR_NONE)) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_api_trace) || + (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) && + error != GRPC_ERROR_NONE)) { const char* errmsg = grpc_error_string(error); GRPC_API_TRACE( "cq_end_op_for_callback(cq=%p, tag=%p, error=%s, " "done=%p, done_arg=%p, storage=%p)", 6, (cq, tag, errmsg, done, done_arg, storage)); - if (grpc_trace_operation_failures.enabled() && error != GRPC_ERROR_NONE) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_operation_failures) && + error != GRPC_ERROR_NONE) { gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg); } } @@ -906,7 +915,7 @@ class ExecCtxNext : public grpc_core::ExecCtx { #ifndef NDEBUG static void dump_pending_tags(grpc_completion_queue* cq) { - if (!grpc_trace_pending_tags.enabled()) return; + if (!GRPC_TRACE_FLAG_ENABLED(grpc_trace_pending_tags)) return; gpr_strvec v; gpr_strvec_init(&v); @@ -1002,15 +1011,15 @@ static grpc_event cq_next(grpc_completion_queue* cq, gpr_timespec deadline, continue; } - memset(&ret, 0, sizeof(ret)); ret.type = GRPC_QUEUE_SHUTDOWN; + ret.success = 0; break; } if (!is_finished_arg.first_loop && grpc_core::ExecCtx::Get()->Now() >= deadline_millis) { - memset(&ret, 0, sizeof(ret)); ret.type = GRPC_QUEUE_TIMEOUT; + ret.success = 0; dump_pending_tags(cq); break; } @@ -1027,8 +1036,8 @@ static grpc_event cq_next(grpc_completion_queue* cq, gpr_timespec deadline, gpr_log(GPR_ERROR, "Completion queue next failed: %s", msg); GRPC_ERROR_UNREF(err); - memset(&ret, 0, sizeof(ret)); ret.type = GRPC_QUEUE_TIMEOUT; + ret.success = 0; dump_pending_tags(cq); break; } @@ -1176,7 +1185,7 @@ static grpc_event cq_pluck(grpc_completion_queue* cq, void* tag, grpc_pollset_worker* worker = nullptr; cq_pluck_data* cqd = static_cast DATA_FROM_CQ(cq); - if (grpc_cq_pluck_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_cq_pluck_trace)) { GRPC_API_TRACE( "grpc_completion_queue_pluck(" "cq=%p, tag=%p, " @@ -1234,8 +1243,8 @@ static grpc_event cq_pluck(grpc_completion_queue* cq, void* tag, } if (cqd->shutdown.Load(grpc_core::MemoryOrder::RELAXED)) { gpr_mu_unlock(cq->mu); - memset(&ret, 0, sizeof(ret)); ret.type = GRPC_QUEUE_SHUTDOWN; + ret.success = 0; break; } if (!add_plucker(cq, tag, &worker)) { @@ -1244,9 +1253,9 @@ static grpc_event cq_pluck(grpc_completion_queue* cq, void* tag, "is %d", GRPC_MAX_COMPLETION_QUEUE_PLUCKERS); gpr_mu_unlock(cq->mu); - memset(&ret, 0, sizeof(ret)); /* TODO(ctiller): should we use a different result here */ ret.type = GRPC_QUEUE_TIMEOUT; + ret.success = 0; dump_pending_tags(cq); break; } @@ -1254,8 +1263,8 @@ static grpc_event cq_pluck(grpc_completion_queue* cq, void* tag, grpc_core::ExecCtx::Get()->Now() >= deadline_millis) { del_plucker(cq, tag, &worker); gpr_mu_unlock(cq->mu); - memset(&ret, 0, sizeof(ret)); ret.type = GRPC_QUEUE_TIMEOUT; + ret.success = 0; dump_pending_tags(cq); break; } @@ -1269,8 +1278,8 @@ static grpc_event cq_pluck(grpc_completion_queue* cq, void* tag, gpr_log(GPR_ERROR, "Completion queue pluck failed: %s", msg); GRPC_ERROR_UNREF(err); - memset(&ret, 0, sizeof(ret)); ret.type = GRPC_QUEUE_TIMEOUT; + ret.success = 0; dump_pending_tags(cq); break; } diff --git a/src/core/lib/surface/init.cc b/src/core/lib/surface/init.cc index 1ed1a66b184..2a6d307ddab 100644 --- a/src/core/lib/surface/init.cc +++ b/src/core/lib/surface/init.cc @@ -154,7 +154,7 @@ void grpc_init(void) { * at the appropriate time */ grpc_register_security_filters(); register_builtin_channel_init(); - grpc_tracer_init("GRPC_TRACE"); + grpc_tracer_init(); /* no more changes to channel init pipelines */ grpc_channel_init_finalize(); grpc_iomgr_start(); diff --git a/src/core/lib/surface/lame_client.cc b/src/core/lib/surface/lame_client.cc index 5f5f10d2ebf..dde39b8c681 100644 --- a/src/core/lib/surface/lame_client.cc +++ b/src/core/lib/surface/lame_client.cc @@ -39,7 +39,7 @@ namespace grpc_core { namespace { struct CallData { - grpc_call_combiner* call_combiner; + grpc_core::CallCombiner* call_combiner; grpc_linked_mdelem status; grpc_linked_mdelem details; grpc_core::Atomic filled_metadata; diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc index f661012b528..2377c4d8f23 100644 --- a/src/core/lib/surface/server.cc +++ b/src/core/lib/surface/server.cc @@ -190,7 +190,7 @@ struct call_data { grpc_closure publish; call_data* pending_next = nullptr; - grpc_call_combiner* call_combiner; + grpc_core::CallCombiner* call_combiner; }; struct request_matcher { @@ -347,8 +347,8 @@ static void channel_broadcaster_shutdown(channel_broadcaster* cb, */ static void request_matcher_init(request_matcher* rm, grpc_server* server) { - memset(rm, 0, sizeof(*rm)); rm->server = server; + rm->pending_head = rm->pending_tail = nullptr; rm->requests_per_cq = static_cast( gpr_malloc(sizeof(*rm->requests_per_cq) * server->cq_count)); for (size_t i = 0; i < server->cq_count; i++) { @@ -464,7 +464,8 @@ static void destroy_channel(channel_data* chand, grpc_error* error) { GRPC_CLOSURE_INIT(&chand->finish_destroy_channel_closure, finish_destroy_channel, chand, grpc_schedule_on_exec_ctx); - if (grpc_server_channel_trace.enabled() && error != GRPC_ERROR_NONE) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_server_channel_trace) && + error != GRPC_ERROR_NONE) { const char* msg = grpc_error_string(error); gpr_log(GPR_INFO, "Disconnected client: %s", msg); } @@ -601,8 +602,9 @@ static void finish_start_new_rpc( break; case GRPC_SRM_PAYLOAD_READ_INITIAL_BYTE_BUFFER: { grpc_op op; - memset(&op, 0, sizeof(op)); op.op = GRPC_OP_RECV_MESSAGE; + op.flags = 0; + op.reserved = nullptr; op.data.recv_message.recv_message = &calld->payload; GRPC_CLOSURE_INIT(&calld->publish, publish_new_rpc, elem, grpc_schedule_on_exec_ctx); @@ -1098,20 +1100,6 @@ void* grpc_server_register_method( return m; } -static void start_listeners(void* s, grpc_error* error) { - grpc_server* server = static_cast(s); - for (listener* l = server->listeners; l; l = l->next) { - l->start(server, l->arg, server->pollsets, server->pollset_count); - } - - gpr_mu_lock(&server->mu_global); - server->starting = false; - gpr_cv_signal(&server->starting_cv); - gpr_mu_unlock(&server->mu_global); - - server_unref(server); -} - void grpc_server_start(grpc_server* server) { size_t i; grpc_core::ExecCtx exec_ctx; @@ -1133,13 +1121,18 @@ void grpc_server_start(grpc_server* server) { request_matcher_init(&rm->matcher, server); } - server_ref(server); + gpr_mu_lock(&server->mu_global); server->starting = true; - GRPC_CLOSURE_SCHED( - GRPC_CLOSURE_CREATE( - start_listeners, server, - grpc_core::Executor::Scheduler(grpc_core::ExecutorJobType::SHORT)), - GRPC_ERROR_NONE); + gpr_mu_unlock(&server->mu_global); + + for (listener* l = server->listeners; l; l = l->next) { + l->start(server, l->arg, server->pollsets, server->pollset_count); + } + + gpr_mu_lock(&server->mu_global); + server->starting = false; + gpr_cv_signal(&server->starting_cv); + gpr_mu_unlock(&server->mu_global); } void grpc_server_get_pollsets(grpc_server* server, grpc_pollset*** pollsets, diff --git a/src/core/lib/surface/version.cc b/src/core/lib/surface/version.cc index 8aeadaf5078..7d9d49bc2aa 100644 --- a/src/core/lib/surface/version.cc +++ b/src/core/lib/surface/version.cc @@ -25,4 +25,4 @@ const char* grpc_version_string(void) { return "7.0.0"; } -const char* grpc_g_stands_for(void) { return "gandalf"; } +const char* grpc_g_stands_for(void) { return "gale"; } diff --git a/src/core/lib/transport/bdp_estimator.cc b/src/core/lib/transport/bdp_estimator.cc index 8e71f869894..8835e32bcff 100644 --- a/src/core/lib/transport/bdp_estimator.cc +++ b/src/core/lib/transport/bdp_estimator.cc @@ -46,7 +46,7 @@ grpc_millis BdpEstimator::CompletePing() { 1e-9 * static_cast(dt_ts.tv_nsec); double bw = dt > 0 ? (static_cast(accumulator_) / dt) : 0; int start_inter_ping_delay = inter_ping_delay_; - if (grpc_bdp_estimator_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_bdp_estimator_trace)) { gpr_log(GPR_INFO, "bdp[%s]:complete acc=%" PRId64 " est=%" PRId64 " dt=%lf bw=%lfMbs bw_est=%lfMbs", @@ -57,7 +57,7 @@ grpc_millis BdpEstimator::CompletePing() { if (accumulator_ > 2 * estimate_ / 3 && bw > bw_est_) { estimate_ = GPR_MAX(accumulator_, estimate_ * 2); bw_est_ = bw; - if (grpc_bdp_estimator_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_bdp_estimator_trace)) { gpr_log(GPR_INFO, "bdp[%s]: estimate increased to %" PRId64, name_, estimate_); } @@ -74,7 +74,7 @@ grpc_millis BdpEstimator::CompletePing() { } if (start_inter_ping_delay != inter_ping_delay_) { stable_estimate_count_ = 0; - if (grpc_bdp_estimator_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_bdp_estimator_trace)) { gpr_log(GPR_INFO, "bdp[%s]:update_inter_time to %dms", name_, inter_ping_delay_); } diff --git a/src/core/lib/transport/bdp_estimator.h b/src/core/lib/transport/bdp_estimator.h index ab13ae4be4c..6dc4d6bb05e 100644 --- a/src/core/lib/transport/bdp_estimator.h +++ b/src/core/lib/transport/bdp_estimator.h @@ -49,7 +49,7 @@ class BdpEstimator { // grpc_bdp_estimator_add_incoming_bytes once a ping has been scheduled by a // transport (but not necessarily started) void SchedulePing() { - if (grpc_bdp_estimator_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_bdp_estimator_trace)) { gpr_log(GPR_INFO, "bdp[%s]:sched acc=%" PRId64 " est=%" PRId64, name_, accumulator_, estimate_); } @@ -62,7 +62,7 @@ class BdpEstimator { // once // the ping is on the wire void StartPing() { - if (grpc_bdp_estimator_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_bdp_estimator_trace)) { gpr_log(GPR_INFO, "bdp[%s]:start acc=%" PRId64 " est=%" PRId64, name_, accumulator_, estimate_); } diff --git a/src/core/lib/transport/connectivity_state.cc b/src/core/lib/transport/connectivity_state.cc index 5b73085c7f3..bf35fd09def 100644 --- a/src/core/lib/transport/connectivity_state.cc +++ b/src/core/lib/transport/connectivity_state.cc @@ -75,7 +75,7 @@ grpc_connectivity_state grpc_connectivity_state_check( grpc_connectivity_state_tracker* tracker) { grpc_connectivity_state cur = static_cast( gpr_atm_no_barrier_load(&tracker->current_state_atm)); - if (grpc_connectivity_state_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_connectivity_state_trace)) { gpr_log(GPR_INFO, "CONWATCH: %p %s: get %s", tracker, tracker->name, grpc_connectivity_state_name(cur)); } @@ -92,7 +92,7 @@ bool grpc_connectivity_state_notify_on_state_change( grpc_closure* notify) { grpc_connectivity_state cur = static_cast( gpr_atm_no_barrier_load(&tracker->current_state_atm)); - if (grpc_connectivity_state_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_connectivity_state_trace)) { if (current == nullptr) { gpr_log(GPR_INFO, "CONWATCH: %p %s: unsubscribe notify=%p", tracker, tracker->name, notify); @@ -143,7 +143,7 @@ void grpc_connectivity_state_set(grpc_connectivity_state_tracker* tracker, grpc_connectivity_state cur = static_cast( gpr_atm_no_barrier_load(&tracker->current_state_atm)); grpc_connectivity_state_watcher* w; - if (grpc_connectivity_state_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_connectivity_state_trace)) { gpr_log(GPR_INFO, "SET: %p %s: %s --> %s [%s]", tracker, tracker->name, grpc_connectivity_state_name(cur), grpc_connectivity_state_name(state), reason); @@ -156,7 +156,7 @@ void grpc_connectivity_state_set(grpc_connectivity_state_tracker* tracker, while ((w = tracker->watchers) != nullptr) { *w->current = state; tracker->watchers = w->next; - if (grpc_connectivity_state_trace.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(grpc_connectivity_state_trace)) { gpr_log(GPR_INFO, "NOTIFY: %p %s: %p", tracker, tracker->name, w->notify); } GRPC_CLOSURE_SCHED(w->notify, GRPC_ERROR_NONE); diff --git a/src/core/lib/transport/error_utils.cc b/src/core/lib/transport/error_utils.cc index 558f1d494cd..eb4e8c3a282 100644 --- a/src/core/lib/transport/error_utils.cc +++ b/src/core/lib/transport/error_utils.cc @@ -48,6 +48,18 @@ void grpc_error_get_status(grpc_error* error, grpc_millis deadline, grpc_status_code* code, grpc_slice* slice, grpc_http2_error_code* http_error, const char** error_string) { + // Fast path: We expect no error. + if (GPR_LIKELY(error == GRPC_ERROR_NONE)) { + if (code != nullptr) *code = GRPC_STATUS_OK; + if (slice != nullptr) { + grpc_error_get_str(error, GRPC_ERROR_STR_GRPC_MESSAGE, slice); + } + if (http_error != nullptr) { + *http_error = GRPC_HTTP2_NO_ERROR; + } + return; + } + // Start with the parent error and recurse through the tree of children // until we find the first one that has a status code. grpc_error* found_error = diff --git a/src/core/lib/transport/metadata.cc b/src/core/lib/transport/metadata.cc index b7e7fd40c00..4609eb42cdc 100644 --- a/src/core/lib/transport/metadata.cc +++ b/src/core/lib/transport/metadata.cc @@ -41,6 +41,10 @@ #include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/transport/static_metadata.h" +using grpc_core::AllocatedMetadata; +using grpc_core::InternedMetadata; +using grpc_core::UserData; + /* There are two kinds of mdelem and mdstr instances. * Static instances are declared in static_metadata.{h,c} and * are initialized by grpc_mdctx_global_init(). @@ -54,13 +58,40 @@ grpc_core::DebugOnlyTraceFlag grpc_trace_metadata(false, "metadata"); #ifndef NDEBUG #define DEBUG_ARGS , const char *file, int line -#define FWD_DEBUG_ARGS , file, line -#define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s), __FILE__, __LINE__) -#else +#define FWD_DEBUG_ARGS file, line + +void grpc_mdelem_trace_ref(void* md, const grpc_slice& key, + const grpc_slice& value, intptr_t refcnt, + const char* file, int line) { + if (grpc_trace_metadata.enabled()) { + char* key_str = grpc_slice_to_c_string(key); + char* value_str = grpc_slice_to_c_string(value); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "ELM REF:%p:%" PRIdPTR "->%" PRIdPTR ": '%s' = '%s'", md, refcnt, + refcnt + 1, key_str, value_str); + gpr_free(key_str); + gpr_free(value_str); + } +} + +void grpc_mdelem_trace_unref(void* md, const grpc_slice& key, + const grpc_slice& value, intptr_t refcnt, + const char* file, int line) { + if (grpc_trace_metadata.enabled()) { + char* key_str = grpc_slice_to_c_string(key); + char* value_str = grpc_slice_to_c_string(value); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "ELM UNREF:%p:%" PRIdPTR "->%" PRIdPTR ": '%s' = '%s'", md, + refcnt, refcnt - 1, key_str, value_str); + gpr_free(key_str); + gpr_free(value_str); + } +} + +#else // ifndef NDEBUG #define DEBUG_ARGS #define FWD_DEBUG_ARGS -#define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s)) -#endif +#endif // ifndef NDEBUG #define INITIAL_SHARD_CAPACITY 8 #define LOG2_SHARD_COUNT 4 @@ -69,43 +100,87 @@ grpc_core::DebugOnlyTraceFlag grpc_trace_metadata(false, "metadata"); #define TABLE_IDX(hash, capacity) (((hash) >> (LOG2_SHARD_COUNT)) % (capacity)) #define SHARD_IDX(hash) ((hash) & ((1 << (LOG2_SHARD_COUNT)) - 1)) -typedef void (*destroy_user_data_func)(void* user_data); - -struct UserData { - gpr_mu mu_user_data; - gpr_atm destroy_user_data; - gpr_atm user_data; -}; - -/* Shadow structure for grpc_mdelem_data for interned elements */ -typedef struct interned_metadata { - /* must be byte compatible with grpc_mdelem_data */ - grpc_slice key; - grpc_slice value; - - /* private only data */ - gpr_atm refcnt; - - UserData user_data; +AllocatedMetadata::AllocatedMetadata(const grpc_slice& key, + const grpc_slice& value) + : key_(grpc_slice_ref_internal(key)), + value_(grpc_slice_ref_internal(value)), + refcnt_(1) { +#ifndef NDEBUG + if (grpc_trace_metadata.enabled()) { + char* key_str = grpc_slice_to_c_string(key_); + char* value_str = grpc_slice_to_c_string(value_); + gpr_log(GPR_DEBUG, "ELM ALLOC:%p:%" PRIdPTR ": '%s' = '%s'", this, + RefValue(), key_str, value_str); + gpr_free(key_str); + gpr_free(value_str); + } +#endif +} - struct interned_metadata* bucket_next; -} interned_metadata; +AllocatedMetadata::~AllocatedMetadata() { + grpc_slice_unref_internal(key_); + grpc_slice_unref_internal(value_); + void* user_data = user_data_.data.Load(grpc_core::MemoryOrder::RELAXED); + if (user_data) { + destroy_user_data_func destroy_user_data = + user_data_.destroy_user_data.Load(grpc_core::MemoryOrder::RELAXED); + destroy_user_data(user_data); + } +} -/* Shadow structure for grpc_mdelem_data for allocated elements */ -typedef struct allocated_metadata { - /* must be byte compatible with grpc_mdelem_data */ - grpc_slice key; - grpc_slice value; +InternedMetadata::InternedMetadata(const grpc_slice& key, + const grpc_slice& value, uint32_t hash, + InternedMetadata* next) + : key_(grpc_slice_ref_internal(key)), + value_(grpc_slice_ref_internal(value)), + refcnt_(1), + hash_(hash), + link_(next) { +#ifndef NDEBUG + if (grpc_trace_metadata.enabled()) { + char* key_str = grpc_slice_to_c_string(key_); + char* value_str = grpc_slice_to_c_string(value_); + gpr_log(GPR_DEBUG, "ELM NEW:%p:%" PRIdPTR ": '%s' = '%s'", this, + RefValue(), key_str, value_str); + gpr_free(key_str); + gpr_free(value_str); + } +#endif +} - /* private only data */ - gpr_atm refcnt; +InternedMetadata::~InternedMetadata() { + grpc_slice_unref_internal(key_); + grpc_slice_unref_internal(value_); + void* user_data = user_data_.data.Load(grpc_core::MemoryOrder::RELAXED); + if (user_data) { + destroy_user_data_func destroy_user_data = + user_data_.destroy_user_data.Load(grpc_core::MemoryOrder::RELAXED); + destroy_user_data(user_data); + } +} - UserData user_data; -} allocated_metadata; +size_t InternedMetadata::CleanupLinkedMetadata( + InternedMetadata::BucketLink* head) { + size_t num_freed = 0; + InternedMetadata::BucketLink* prev_next = head; + InternedMetadata *md, *next; + + for (md = head->next; md; md = next) { + next = md->link_.next; + if (md->AllRefsDropped()) { + prev_next->next = next; + grpc_core::Delete(md); + num_freed++; + } else { + prev_next = &md->link_; + } + } + return num_freed; +} typedef struct mdtab_shard { gpr_mu mu; - interned_metadata** elems; + InternedMetadata::BucketLink* elems; size_t count; size_t capacity; /** Estimate of the number of unreferenced mdelems in the hash table. @@ -126,7 +201,7 @@ void grpc_mdctx_global_init(void) { shard->count = 0; gpr_atm_no_barrier_store(&shard->free_estimate, 0); shard->capacity = INITIAL_SHARD_CAPACITY; - shard->elems = static_cast( + shard->elems = static_cast( gpr_zalloc(sizeof(*shard->elems) * shard->capacity)); } } @@ -136,7 +211,6 @@ void grpc_mdctx_global_shutdown() { mdtab_shard* shard = &g_shards[i]; gpr_mu_destroy(&shard->mu); gc_mdtab(shard); - /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */ if (shard->count != 0) { gpr_log(GPR_DEBUG, "WARNING: %" PRIuPTR " metadata elements were leaked", shard->count); @@ -144,6 +218,7 @@ void grpc_mdctx_global_shutdown() { abort(); } } + GPR_DEBUG_ASSERT(shard->count == 0); gpr_free(shard->elems); } } @@ -154,57 +229,34 @@ static int is_mdelem_static(grpc_mdelem e) { &grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; } -static void ref_md_locked(mdtab_shard* shard, - interned_metadata* md DEBUG_ARGS) { +void InternedMetadata::RefWithShardLocked(mdtab_shard* shard) { #ifndef NDEBUG if (grpc_trace_metadata.enabled()) { - char* key_str = grpc_slice_to_c_string(md->key); - char* value_str = grpc_slice_to_c_string(md->value); - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "ELM REF:%p:%" PRIdPTR "->%" PRIdPTR ": '%s' = '%s'", (void*)md, - gpr_atm_no_barrier_load(&md->refcnt), - gpr_atm_no_barrier_load(&md->refcnt) + 1, key_str, value_str); + char* key_str = grpc_slice_to_c_string(key_); + char* value_str = grpc_slice_to_c_string(value_); + intptr_t value = RefValue(); + gpr_log(__FILE__, __LINE__, GPR_LOG_SEVERITY_DEBUG, + "ELM REF:%p:%" PRIdPTR "->%" PRIdPTR ": '%s' = '%s'", this, value, + value + 1, key_str, value_str); gpr_free(key_str); gpr_free(value_str); } #endif - if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 1)) { + if (FirstRef()) { gpr_atm_no_barrier_fetch_add(&shard->free_estimate, -1); } } static void gc_mdtab(mdtab_shard* shard) { GPR_TIMER_SCOPE("gc_mdtab", 0); - - size_t i; - interned_metadata** prev_next; - interned_metadata *md, *next; - gpr_atm num_freed = 0; - - for (i = 0; i < shard->capacity; i++) { - prev_next = &shard->elems[i]; - for (md = shard->elems[i]; md; md = next) { - void* user_data = - (void*)gpr_atm_no_barrier_load(&md->user_data.user_data); - next = md->bucket_next; - if (gpr_atm_acq_load(&md->refcnt) == 0) { - grpc_slice_unref_internal(md->key); - grpc_slice_unref_internal(md->value); - if (md->user_data.user_data) { - ((destroy_user_data_func)gpr_atm_no_barrier_load( - &md->user_data.destroy_user_data))(user_data); - } - gpr_mu_destroy(&md->user_data.mu_user_data); - gpr_free(md); - *prev_next = next; - num_freed++; - shard->count--; - } else { - prev_next = &md->bucket_next; - } - } + size_t num_freed = 0; + for (size_t i = 0; i < shard->capacity; ++i) { + intptr_t freed = InternedMetadata::CleanupLinkedMetadata(&shard->elems[i]); + num_freed += freed; + shard->count -= freed; } - gpr_atm_no_barrier_fetch_add(&shard->free_estimate, -num_freed); + gpr_atm_no_barrier_fetch_add(&shard->free_estimate, + -static_cast(num_freed)); } static void grow_mdtab(mdtab_shard* shard) { @@ -212,22 +264,21 @@ static void grow_mdtab(mdtab_shard* shard) { size_t capacity = shard->capacity * 2; size_t i; - interned_metadata** mdtab; - interned_metadata *md, *next; + InternedMetadata::BucketLink* mdtab; + InternedMetadata *md, *next; uint32_t hash; - mdtab = static_cast( - gpr_zalloc(sizeof(interned_metadata*) * capacity)); + mdtab = static_cast( + gpr_zalloc(sizeof(InternedMetadata::BucketLink) * capacity)); for (i = 0; i < shard->capacity; i++) { - for (md = shard->elems[i]; md; md = next) { + for (md = shard->elems[i].next; md; md = next) { size_t idx; - hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash(md->key), - grpc_slice_hash(md->value)); - next = md->bucket_next; + hash = md->hash(); + next = md->bucket_next(); idx = TABLE_IDX(hash, capacity); - md->bucket_next = mdtab[idx]; - mdtab[idx] = md; + md->set_bucket_next(mdtab[idx].next); + mdtab[idx].next = md; } } gpr_free(shard->elems); @@ -247,34 +298,22 @@ static void rehash_mdtab(mdtab_shard* shard) { grpc_mdelem grpc_mdelem_create( const grpc_slice& key, const grpc_slice& value, grpc_mdelem_data* compatible_external_backing_store) { + // External storage if either slice is not interned and the caller already + // created a backing store. If no backing store, we allocate one. if (!grpc_slice_is_interned(key) || !grpc_slice_is_interned(value)) { if (compatible_external_backing_store != nullptr) { + // Caller provided backing store. return GRPC_MAKE_MDELEM(compatible_external_backing_store, GRPC_MDELEM_STORAGE_EXTERNAL); + } else { + // We allocate backing store. + return GRPC_MAKE_MDELEM(grpc_core::New(key, value), + GRPC_MDELEM_STORAGE_ALLOCATED); } - - allocated_metadata* allocated = - static_cast(gpr_malloc(sizeof(*allocated))); - allocated->key = grpc_slice_ref_internal(key); - allocated->value = grpc_slice_ref_internal(value); - gpr_atm_rel_store(&allocated->refcnt, 1); - allocated->user_data.user_data = 0; - allocated->user_data.destroy_user_data = 0; - gpr_mu_init(&allocated->user_data.mu_user_data); -#ifndef NDEBUG - if (grpc_trace_metadata.enabled()) { - char* key_str = grpc_slice_to_c_string(allocated->key); - char* value_str = grpc_slice_to_c_string(allocated->value); - gpr_log(GPR_DEBUG, "ELM ALLOC:%p:%" PRIdPTR ": '%s' = '%s'", - (void*)allocated, gpr_atm_no_barrier_load(&allocated->refcnt), - key_str, value_str); - gpr_free(key_str); - gpr_free(value_str); - } -#endif - return GRPC_MAKE_MDELEM(allocated, GRPC_MDELEM_STORAGE_ALLOCATED); } + // Not all static slice input yields a statically stored metadata element. + // It may be worth documenting why. if (GRPC_IS_STATIC_METADATA_STRING(key) && GRPC_IS_STATIC_METADATA_STRING(value)) { grpc_mdelem static_elem = grpc_static_mdelem_for_static_strings( @@ -286,7 +325,7 @@ grpc_mdelem grpc_mdelem_create( uint32_t hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash(key), grpc_slice_hash(value)); - interned_metadata* md; + InternedMetadata* md; mdtab_shard* shard = &g_shards[SHARD_IDX(hash)]; size_t idx; @@ -296,34 +335,18 @@ grpc_mdelem grpc_mdelem_create( idx = TABLE_IDX(hash, shard->capacity); /* search for an existing pair */ - for (md = shard->elems[idx]; md; md = md->bucket_next) { - if (grpc_slice_eq(key, md->key) && grpc_slice_eq(value, md->value)) { - REF_MD_LOCKED(shard, md); + for (md = shard->elems[idx].next; md; md = md->bucket_next()) { + if (grpc_slice_eq(key, md->key()) && grpc_slice_eq(value, md->value())) { + md->RefWithShardLocked(shard); gpr_mu_unlock(&shard->mu); return GRPC_MAKE_MDELEM(md, GRPC_MDELEM_STORAGE_INTERNED); } } /* not found: create a new pair */ - md = static_cast(gpr_malloc(sizeof(interned_metadata))); - gpr_atm_rel_store(&md->refcnt, 1); - md->key = grpc_slice_ref_internal(key); - md->value = grpc_slice_ref_internal(value); - md->user_data.user_data = 0; - md->user_data.destroy_user_data = 0; - md->bucket_next = shard->elems[idx]; - shard->elems[idx] = md; - gpr_mu_init(&md->user_data.mu_user_data); -#ifndef NDEBUG - if (grpc_trace_metadata.enabled()) { - char* key_str = grpc_slice_to_c_string(md->key); - char* value_str = grpc_slice_to_c_string(md->value); - gpr_log(GPR_DEBUG, "ELM NEW:%p:%" PRIdPTR ": '%s' = '%s'", (void*)md, - gpr_atm_no_barrier_load(&md->refcnt), key_str, value_str); - gpr_free(key_str); - gpr_free(value_str); - } -#endif + md = grpc_core::New(key, value, hash, + shard->elems[idx].next); + shard->elems[idx].next = md; shard->count++; if (shard->count > shard->capacity * 2) { @@ -354,130 +377,10 @@ grpc_mdelem grpc_mdelem_from_grpc_metadata(grpc_metadata* metadata) { changed ? nullptr : reinterpret_cast(metadata)); } -grpc_mdelem grpc_mdelem_ref(grpc_mdelem gmd DEBUG_ARGS) { - switch (GRPC_MDELEM_STORAGE(gmd)) { - case GRPC_MDELEM_STORAGE_EXTERNAL: - case GRPC_MDELEM_STORAGE_STATIC: - break; - case GRPC_MDELEM_STORAGE_INTERNED: { - interned_metadata* md = - reinterpret_cast GRPC_MDELEM_DATA(gmd); -#ifndef NDEBUG - if (grpc_trace_metadata.enabled()) { - char* key_str = grpc_slice_to_c_string(md->key); - char* value_str = grpc_slice_to_c_string(md->value); - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "ELM REF:%p:%" PRIdPTR "->%" PRIdPTR ": '%s' = '%s'", - (void*)md, gpr_atm_no_barrier_load(&md->refcnt), - gpr_atm_no_barrier_load(&md->refcnt) + 1, key_str, value_str); - gpr_free(key_str); - gpr_free(value_str); - } -#endif - /* we can assume the ref count is >= 1 as the application is calling - this function - meaning that no adjustment to mdtab_free is necessary, - simplifying the logic here to be just an atomic increment */ - /* use C assert to have this removed in opt builds */ - GPR_ASSERT(gpr_atm_no_barrier_load(&md->refcnt) >= 1); - gpr_atm_no_barrier_fetch_add(&md->refcnt, 1); - break; - } - case GRPC_MDELEM_STORAGE_ALLOCATED: { - allocated_metadata* md = - reinterpret_cast GRPC_MDELEM_DATA(gmd); -#ifndef NDEBUG - if (grpc_trace_metadata.enabled()) { - char* key_str = grpc_slice_to_c_string(md->key); - char* value_str = grpc_slice_to_c_string(md->value); - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "ELM REF:%p:%" PRIdPTR "->%" PRIdPTR ": '%s' = '%s'", - (void*)md, gpr_atm_no_barrier_load(&md->refcnt), - gpr_atm_no_barrier_load(&md->refcnt) + 1, key_str, value_str); - gpr_free(key_str); - gpr_free(value_str); - } -#endif - /* we can assume the ref count is >= 1 as the application is calling - this function - meaning that no adjustment to mdtab_free is necessary, - simplifying the logic here to be just an atomic increment */ - /* use C assert to have this removed in opt builds */ - gpr_atm_no_barrier_fetch_add(&md->refcnt, 1); - break; - } - } - return gmd; -} - -void grpc_mdelem_unref(grpc_mdelem gmd DEBUG_ARGS) { - switch (GRPC_MDELEM_STORAGE(gmd)) { - case GRPC_MDELEM_STORAGE_EXTERNAL: - case GRPC_MDELEM_STORAGE_STATIC: - break; - case GRPC_MDELEM_STORAGE_INTERNED: { - interned_metadata* md = - reinterpret_cast GRPC_MDELEM_DATA(gmd); -#ifndef NDEBUG - if (grpc_trace_metadata.enabled()) { - char* key_str = grpc_slice_to_c_string(md->key); - char* value_str = grpc_slice_to_c_string(md->value); - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "ELM UNREF:%p:%" PRIdPTR "->%" PRIdPTR ": '%s' = '%s'", - (void*)md, gpr_atm_no_barrier_load(&md->refcnt), - gpr_atm_no_barrier_load(&md->refcnt) - 1, key_str, value_str); - gpr_free(key_str); - gpr_free(value_str); - } -#endif - uint32_t hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash(md->key), - grpc_slice_hash(md->value)); - const gpr_atm prev_refcount = gpr_atm_full_fetch_add(&md->refcnt, -1); - GPR_ASSERT(prev_refcount >= 1); - if (1 == prev_refcount) { - /* once the refcount hits zero, some other thread can come along and - free md at any time: it's unsafe from this point on to access it */ - mdtab_shard* shard = &g_shards[SHARD_IDX(hash)]; - gpr_atm_no_barrier_fetch_add(&shard->free_estimate, 1); - } - break; - } - case GRPC_MDELEM_STORAGE_ALLOCATED: { - allocated_metadata* md = - reinterpret_cast GRPC_MDELEM_DATA(gmd); -#ifndef NDEBUG - if (grpc_trace_metadata.enabled()) { - char* key_str = grpc_slice_to_c_string(md->key); - char* value_str = grpc_slice_to_c_string(md->value); - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "ELM UNREF:%p:%" PRIdPTR "->%" PRIdPTR ": '%s' = '%s'", - (void*)md, gpr_atm_no_barrier_load(&md->refcnt), - gpr_atm_no_barrier_load(&md->refcnt) - 1, key_str, value_str); - gpr_free(key_str); - gpr_free(value_str); - } -#endif - const gpr_atm prev_refcount = gpr_atm_full_fetch_add(&md->refcnt, -1); - GPR_ASSERT(prev_refcount >= 1); - if (1 == prev_refcount) { - grpc_slice_unref_internal(md->key); - grpc_slice_unref_internal(md->value); - if (md->user_data.user_data) { - destroy_user_data_func destroy_user_data = - (destroy_user_data_func)gpr_atm_no_barrier_load( - &md->user_data.destroy_user_data); - destroy_user_data((void*)md->user_data.user_data); - } - gpr_mu_destroy(&md->user_data.mu_user_data); - gpr_free(md); - } - break; - } - } -} - static void* get_user_data(UserData* user_data, void (*destroy_func)(void*)) { - if (gpr_atm_acq_load(&user_data->destroy_user_data) == - (gpr_atm)destroy_func) { - return (void*)gpr_atm_no_barrier_load(&user_data->user_data); + if (user_data->destroy_user_data.Load(grpc_core::MemoryOrder::ACQUIRE) == + destroy_func) { + return user_data->data.Load(grpc_core::MemoryOrder::RELAXED); } else { return nullptr; } @@ -491,57 +394,52 @@ void* grpc_mdelem_get_user_data(grpc_mdelem md, void (*destroy_func)(void*)) { return (void*)grpc_static_mdelem_user_data[GRPC_MDELEM_DATA(md) - grpc_static_mdelem_table]; case GRPC_MDELEM_STORAGE_ALLOCATED: { - allocated_metadata* am = - reinterpret_cast(GRPC_MDELEM_DATA(md)); - return get_user_data(&am->user_data, destroy_func); + auto* am = reinterpret_cast(GRPC_MDELEM_DATA(md)); + return get_user_data(am->user_data(), destroy_func); } case GRPC_MDELEM_STORAGE_INTERNED: { - interned_metadata* im = - reinterpret_cast GRPC_MDELEM_DATA(md); - return get_user_data(&im->user_data, destroy_func); + auto* im = reinterpret_cast GRPC_MDELEM_DATA(md); + return get_user_data(im->user_data(), destroy_func); } } GPR_UNREACHABLE_CODE(return nullptr); } static void* set_user_data(UserData* ud, void (*destroy_func)(void*), - void* user_data) { - GPR_ASSERT((user_data == nullptr) == (destroy_func == nullptr)); - gpr_mu_lock(&ud->mu_user_data); - if (gpr_atm_no_barrier_load(&ud->destroy_user_data)) { + void* data) { + GPR_ASSERT((data == nullptr) == (destroy_func == nullptr)); + grpc_core::ReleasableMutexLock lock(&ud->mu_user_data); + if (ud->destroy_user_data.Load(grpc_core::MemoryOrder::RELAXED)) { /* user data can only be set once */ - gpr_mu_unlock(&ud->mu_user_data); + lock.Unlock(); if (destroy_func != nullptr) { - destroy_func(user_data); + destroy_func(data); } - return (void*)gpr_atm_no_barrier_load(&ud->user_data); + return ud->data.Load(grpc_core::MemoryOrder::RELAXED); } - gpr_atm_no_barrier_store(&ud->user_data, (gpr_atm)user_data); - gpr_atm_rel_store(&ud->destroy_user_data, (gpr_atm)destroy_func); - gpr_mu_unlock(&ud->mu_user_data); - return user_data; + ud->data.Store(data, grpc_core::MemoryOrder::RELAXED); + ud->destroy_user_data.Store(destroy_func, grpc_core::MemoryOrder::RELEASE); + return data; } void* grpc_mdelem_set_user_data(grpc_mdelem md, void (*destroy_func)(void*), - void* user_data) { + void* data) { switch (GRPC_MDELEM_STORAGE(md)) { case GRPC_MDELEM_STORAGE_EXTERNAL: - destroy_func(user_data); + destroy_func(data); return nullptr; case GRPC_MDELEM_STORAGE_STATIC: - destroy_func(user_data); + destroy_func(data); return (void*)grpc_static_mdelem_user_data[GRPC_MDELEM_DATA(md) - grpc_static_mdelem_table]; case GRPC_MDELEM_STORAGE_ALLOCATED: { - allocated_metadata* am = - reinterpret_cast(GRPC_MDELEM_DATA(md)); - return set_user_data(&am->user_data, destroy_func, user_data); + auto* am = reinterpret_cast(GRPC_MDELEM_DATA(md)); + return set_user_data(am->user_data(), destroy_func, data); } case GRPC_MDELEM_STORAGE_INTERNED: { - interned_metadata* im = - reinterpret_cast GRPC_MDELEM_DATA(md); + auto* im = reinterpret_cast GRPC_MDELEM_DATA(md); GPR_ASSERT(!is_mdelem_static(md)); - return set_user_data(&im->user_data, destroy_func, user_data); + return set_user_data(im->user_data(), destroy_func, data); } } GPR_UNREACHABLE_CODE(return nullptr); @@ -554,3 +452,33 @@ bool grpc_mdelem_eq(grpc_mdelem a, grpc_mdelem b) { return grpc_slice_eq(GRPC_MDKEY(a), GRPC_MDKEY(b)) && grpc_slice_eq(GRPC_MDVALUE(a), GRPC_MDVALUE(b)); } + +static void note_disposed_interned_metadata(uint32_t hash) { + mdtab_shard* shard = &g_shards[SHARD_IDX(hash)]; + gpr_atm_no_barrier_fetch_add(&shard->free_estimate, 1); +} + +void grpc_mdelem_do_unref(grpc_mdelem gmd DEBUG_ARGS) { + switch (GRPC_MDELEM_STORAGE(gmd)) { + case GRPC_MDELEM_STORAGE_EXTERNAL: + case GRPC_MDELEM_STORAGE_STATIC: + return; + case GRPC_MDELEM_STORAGE_INTERNED: { + auto* md = reinterpret_cast GRPC_MDELEM_DATA(gmd); + uint32_t hash = md->hash(); + if (GPR_UNLIKELY(md->Unref(FWD_DEBUG_ARGS))) { + /* once the refcount hits zero, some other thread can come along and + free md at any time: it's unsafe from this point on to access it */ + note_disposed_interned_metadata(hash); + } + break; + } + case GRPC_MDELEM_STORAGE_ALLOCATED: { + auto* md = reinterpret_cast GRPC_MDELEM_DATA(gmd); + if (GPR_UNLIKELY(md->Unref(FWD_DEBUG_ARGS))) { + grpc_core::Delete(md); + } + break; + } + } +} diff --git a/src/core/lib/transport/metadata.h b/src/core/lib/transport/metadata.h index 5e016567eb2..f59476ccc21 100644 --- a/src/core/lib/transport/metadata.h +++ b/src/core/lib/transport/metadata.h @@ -21,11 +21,16 @@ #include +#include + #include #include #include "src/core/lib/debug/trace.h" #include "src/core/lib/gpr/useful.h" +#include "src/core/lib/gprpp/atomic.h" +#include "src/core/lib/gprpp/sync.h" +#include "src/core/lib/slice/slice_utils.h" extern grpc_core::DebugOnlyTraceFlag grpc_trace_metadata; @@ -63,7 +68,7 @@ extern grpc_core::DebugOnlyTraceFlag grpc_trace_metadata; typedef struct grpc_mdelem grpc_mdelem; /* if changing this, make identical changes in: - - interned_metadata, allocated_metadata in metadata.c + - grpc_core::{InternedMetadata, AllocatedMetadata} - grpc_metadata in grpc_types.h */ typedef struct grpc_mdelem_data { const grpc_slice key; @@ -134,26 +139,209 @@ bool grpc_mdelem_eq(grpc_mdelem a, grpc_mdelem b); * grpc_mdelem_eq and remove unnecessary checks. */ inline bool grpc_mdelem_static_value_eq(grpc_mdelem a, grpc_mdelem b_static) { if (a.payload == b_static.payload) return true; - return grpc_slice_eq(GRPC_MDVALUE(a), GRPC_MDVALUE(b_static)); + return grpc_slice_eq_static_interned(GRPC_MDVALUE(a), GRPC_MDVALUE(b_static)); } /* Mutator and accessor for grpc_mdelem user data. The destructor function is used as a type tag and is checked during user_data fetch. */ void* grpc_mdelem_get_user_data(grpc_mdelem md, void (*if_destroy_func)(void*)); void* grpc_mdelem_set_user_data(grpc_mdelem md, void (*destroy_func)(void*), - void* user_data); + void* data); + +// Defined in metadata.cc. +struct mdtab_shard; + +#ifndef NDEBUG +void grpc_mdelem_trace_ref(void* md, const grpc_slice& key, + const grpc_slice& value, intptr_t refcnt, + const char* file, int line); +void grpc_mdelem_trace_unref(void* md, const grpc_slice& key, + const grpc_slice& value, intptr_t refcnt, + const char* file, int line); +#endif +namespace grpc_core { + +typedef void (*destroy_user_data_func)(void* data); + +struct UserData { + Mutex mu_user_data; + grpc_core::Atomic destroy_user_data; + grpc_core::Atomic data; +}; + +class InternedMetadata { + public: + struct BucketLink { + explicit BucketLink(InternedMetadata* md) : next(md) {} + + InternedMetadata* next = nullptr; + }; + + InternedMetadata(const grpc_slice& key, const grpc_slice& value, + uint32_t hash, InternedMetadata* next); + ~InternedMetadata(); + +#ifndef NDEBUG + void Ref(const char* file, int line) { + grpc_mdelem_trace_ref(this, key_, value_, RefValue(), file, line); + const intptr_t prior = refcnt_.FetchAdd(1, MemoryOrder::RELAXED); + GPR_ASSERT(prior > 0); + } + bool Unref(const char* file, int line) { + grpc_mdelem_trace_unref(this, key_, value_, RefValue(), file, line); + return Unref(); + } +#else + // We define a naked Ref() in the else-clause to make sure we don't + // inadvertently skip the assert on debug builds. + void Ref() { + /* we can assume the ref count is >= 1 as the application is calling + this function - meaning that no adjustment to mdtab_free is necessary, + simplifying the logic here to be just an atomic increment */ + refcnt_.FetchAdd(1, MemoryOrder::RELAXED); + } +#endif // ifndef NDEBUG + bool Unref() { + const intptr_t prior = refcnt_.FetchSub(1, MemoryOrder::ACQ_REL); + GPR_DEBUG_ASSERT(prior > 0); + return prior == 1; + } + + void RefWithShardLocked(mdtab_shard* shard); + const grpc_slice& key() const { return key_; } + const grpc_slice& value() const { return value_; } + UserData* user_data() { return &user_data_; } + uint32_t hash() { return hash_; } + InternedMetadata* bucket_next() { return link_.next; } + void set_bucket_next(InternedMetadata* md) { link_.next = md; } + + static size_t CleanupLinkedMetadata(BucketLink* head); + + private: + bool AllRefsDropped() { return refcnt_.Load(MemoryOrder::ACQUIRE) == 0; } + bool FirstRef() { return refcnt_.FetchAdd(1, MemoryOrder::RELAXED) == 0; } + intptr_t RefValue() { return refcnt_.Load(MemoryOrder::RELAXED); } + + /* must be byte compatible with grpc_mdelem_data */ + grpc_slice key_; + grpc_slice value_; + + /* private only data */ + grpc_core::Atomic refcnt_; + uint32_t hash_; + + UserData user_data_; + + BucketLink link_; +}; + +/* Shadow structure for grpc_mdelem_data for allocated elements */ +class AllocatedMetadata { + public: + AllocatedMetadata(const grpc_slice& key, const grpc_slice& value); + ~AllocatedMetadata(); + + const grpc_slice& key() const { return key_; } + const grpc_slice& value() const { return value_; } + UserData* user_data() { return &user_data_; } + +#ifndef NDEBUG + void Ref(const char* file, int line) { + grpc_mdelem_trace_ref(this, key_, value_, RefValue(), file, line); + Ref(); + } + bool Unref(const char* file, int line) { + grpc_mdelem_trace_unref(this, key_, value_, RefValue(), file, line); + return Unref(); + } +#endif // ifndef NDEBUG + void Ref() { + /* we can assume the ref count is >= 1 as the application is calling + this function - meaning that no adjustment to mdtab_free is necessary, + simplifying the logic here to be just an atomic increment */ + refcnt_.FetchAdd(1, MemoryOrder::RELAXED); + } + bool Unref() { + const intptr_t prior = refcnt_.FetchSub(1, MemoryOrder::ACQ_REL); + GPR_DEBUG_ASSERT(prior > 0); + return prior == 1; + } + + private: + intptr_t RefValue() { return refcnt_.Load(MemoryOrder::RELAXED); } + + /* must be byte compatible with grpc_mdelem_data */ + grpc_slice key_; + grpc_slice value_; + + /* private only data */ + grpc_core::Atomic refcnt_; + + UserData user_data_; +}; + +} // namespace grpc_core #ifndef NDEBUG #define GRPC_MDELEM_REF(s) grpc_mdelem_ref((s), __FILE__, __LINE__) +inline grpc_mdelem grpc_mdelem_ref(grpc_mdelem gmd, const char* file, + int line) { +#else // ifndef NDEBUG +#define GRPC_MDELEM_REF(s) grpc_mdelem_ref((s)) +inline grpc_mdelem grpc_mdelem_ref(grpc_mdelem gmd) { +#endif // ifndef NDEBUG + switch (GRPC_MDELEM_STORAGE(gmd)) { + case GRPC_MDELEM_STORAGE_EXTERNAL: + case GRPC_MDELEM_STORAGE_STATIC: + break; + case GRPC_MDELEM_STORAGE_INTERNED: { + auto* md = + reinterpret_cast GRPC_MDELEM_DATA(gmd); + /* use C assert to have this removed in opt builds */ +#ifndef NDEBUG + md->Ref(file, line); +#else + md->Ref(); +#endif + break; + } + case GRPC_MDELEM_STORAGE_ALLOCATED: { + auto* md = + reinterpret_cast GRPC_MDELEM_DATA(gmd); +#ifndef NDEBUG + md->Ref(file, line); +#else + md->Ref(); +#endif + break; + } + } + return gmd; +} + +#ifndef NDEBUG #define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s), __FILE__, __LINE__) -grpc_mdelem grpc_mdelem_ref(grpc_mdelem md, const char* file, int line); -void grpc_mdelem_unref(grpc_mdelem md, const char* file, int line); +void grpc_mdelem_do_unref(grpc_mdelem gmd, const char* file, int line); +inline void grpc_mdelem_unref(grpc_mdelem gmd, const char* file, int line) { #else -#define GRPC_MDELEM_REF(s) grpc_mdelem_ref((s)) #define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s)) -grpc_mdelem grpc_mdelem_ref(grpc_mdelem md); -void grpc_mdelem_unref(grpc_mdelem md); +void grpc_mdelem_do_unref(grpc_mdelem gmd); +inline void grpc_mdelem_unref(grpc_mdelem gmd) { #endif + switch (GRPC_MDELEM_STORAGE(gmd)) { + case GRPC_MDELEM_STORAGE_EXTERNAL: + case GRPC_MDELEM_STORAGE_STATIC: + return; + case GRPC_MDELEM_STORAGE_INTERNED: + case GRPC_MDELEM_STORAGE_ALLOCATED: +#ifndef NDEBUG + grpc_mdelem_do_unref(gmd, file, line); +#else + grpc_mdelem_do_unref(gmd); +#endif + return; + } +} #define GRPC_MDNULL GRPC_MAKE_MDELEM(NULL, GRPC_MDELEM_STORAGE_EXTERNAL) #define GRPC_MDISNULL(md) (GRPC_MDELEM_DATA(md) == NULL) diff --git a/src/core/lib/transport/static_metadata.cc b/src/core/lib/transport/static_metadata.cc index fc5bb647573..61ee1d46f77 100644 --- a/src/core/lib/transport/static_metadata.cc +++ b/src/core/lib/transport/static_metadata.cc @@ -384,9 +384,9 @@ static const uint8_t elem_idxs[] = { 52, 53, 54, 76, 69, 55, 56, 70, 58, 78, 80, 81, 82, 83, 59, 64, 60, 75, 72, 255, 85, 255, 255, 68, 255, 255, 0}; -grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) { +grpc_mdelem grpc_static_mdelem_for_static_strings(intptr_t a, intptr_t b) { if (a == -1 || b == -1) return GRPC_MDNULL; - uint32_t k = (uint32_t)(a * 107 + b); + uint32_t k = static_cast(a * 107 + b); uint32_t h = elems_phash(k); return h < GPR_ARRAY_SIZE(elem_keys) && elem_keys[h] == k && elem_idxs[h] != 255 diff --git a/src/core/lib/transport/static_metadata.h b/src/core/lib/transport/static_metadata.h index 88293ae0613..a3f23de0953 100644 --- a/src/core/lib/transport/static_metadata.h +++ b/src/core/lib/transport/static_metadata.h @@ -29,6 +29,8 @@ #include +#include + #include "src/core/lib/transport/metadata.h" #define GRPC_STATIC_MDSTR_COUNT 107 @@ -263,7 +265,8 @@ extern grpc_slice_refcount (slice).refcount->GetType() == grpc_slice_refcount::Type::STATIC) #define GRPC_STATIC_METADATA_INDEX(static_slice) \ - ((int)((static_slice).refcount - grpc_static_metadata_refcounts)) + (static_cast( \ + ((static_slice).refcount - grpc_static_metadata_refcounts))) #define GRPC_STATIC_MDELEM_COUNT 86 extern grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; @@ -527,7 +530,7 @@ extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT]; #define GRPC_MDELEM_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \ (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[85], GRPC_MDELEM_STORAGE_STATIC)) -grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b); +grpc_mdelem grpc_static_mdelem_for_static_strings(intptr_t a, intptr_t b); typedef enum { GRPC_BATCH_PATH, GRPC_BATCH_METHOD, @@ -586,11 +589,11 @@ typedef union { } named; } grpc_metadata_batch_callouts; -#define GRPC_BATCH_INDEX_OF(slice) \ - (GRPC_IS_STATIC_METADATA_STRING((slice)) \ - ? (grpc_metadata_batch_callouts_index)GPR_CLAMP( \ - GRPC_STATIC_METADATA_INDEX((slice)), 0, \ - GRPC_BATCH_CALLOUTS_COUNT) \ +#define GRPC_BATCH_INDEX_OF(slice) \ + (GRPC_IS_STATIC_METADATA_STRING((slice)) \ + ? static_cast( \ + GPR_CLAMP(GRPC_STATIC_METADATA_INDEX((slice)), 0, \ + static_cast(GRPC_BATCH_CALLOUTS_COUNT))) \ : GRPC_BATCH_CALLOUTS_COUNT) extern const uint8_t grpc_static_accept_encoding_metadata[8]; diff --git a/src/core/lib/transport/transport.cc b/src/core/lib/transport/transport.cc index 9f666b382e9..29c1e561891 100644 --- a/src/core/lib/transport/transport.cc +++ b/src/core/lib/transport/transport.cc @@ -124,7 +124,8 @@ void grpc_transport_destroy(grpc_transport* transport) { int grpc_transport_init_stream(grpc_transport* transport, grpc_stream* stream, grpc_stream_refcount* refcount, - const void* server_data, gpr_arena* arena) { + const void* server_data, + grpc_core::Arena* arena) { return transport->vtable->init_stream(transport, stream, refcount, server_data, arena); } @@ -174,7 +175,7 @@ grpc_endpoint* grpc_transport_get_endpoint(grpc_transport* transport) { // it's grpc_transport_stream_op_batch_finish_with_failure void grpc_transport_stream_op_batch_finish_with_failure( grpc_transport_stream_op_batch* batch, grpc_error* error, - grpc_call_combiner* call_combiner) { + grpc_core::CallCombiner* call_combiner) { if (batch->send_message) { batch->payload->send_message.send_message.reset(); } diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h index c372003902a..a6a6e904f08 100644 --- a/src/core/lib/transport/transport.h +++ b/src/core/lib/transport/transport.h @@ -24,7 +24,7 @@ #include #include "src/core/lib/channel/context.h" -#include "src/core/lib/gpr/arena.h" +#include "src/core/lib/gprpp/arena.h" #include "src/core/lib/iomgr/call_combiner.h" #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/polling_entity.h" @@ -98,7 +98,7 @@ inline void grpc_stream_unref(grpc_stream_refcount* refcount, #else inline void grpc_stream_unref(grpc_stream_refcount* refcount) { #endif - if (refcount->refs.Unref()) { + if (GPR_UNLIKELY(refcount->refs.Unref())) { grpc_stream_destroy(refcount); } } @@ -358,7 +358,8 @@ size_t grpc_transport_stream_size(grpc_transport* transport); supplied from the accept_stream callback function */ int grpc_transport_init_stream(grpc_transport* transport, grpc_stream* stream, grpc_stream_refcount* refcount, - const void* server_data, gpr_arena* arena); + const void* server_data, + grpc_core::Arena* arena); void grpc_transport_set_pops(grpc_transport* transport, grpc_stream* stream, grpc_polling_entity* pollent); @@ -379,7 +380,7 @@ void grpc_transport_destroy_stream(grpc_transport* transport, void grpc_transport_stream_op_batch_finish_with_failure( grpc_transport_stream_op_batch* op, grpc_error* error, - grpc_call_combiner* call_combiner); + grpc_core::CallCombiner* call_combiner); char* grpc_transport_stream_op_batch_string(grpc_transport_stream_op_batch* op); char* grpc_transport_op_string(grpc_transport_op* op); diff --git a/src/core/lib/transport/transport_impl.h b/src/core/lib/transport/transport_impl.h index ba5e05df0af..526cc1b1bac 100644 --- a/src/core/lib/transport/transport_impl.h +++ b/src/core/lib/transport/transport_impl.h @@ -34,7 +34,7 @@ typedef struct grpc_transport_vtable { /* implementation of grpc_transport_init_stream */ int (*init_stream)(grpc_transport* self, grpc_stream* stream, grpc_stream_refcount* refcount, const void* server_data, - gpr_arena* arena); + grpc_core::Arena* arena); /* implementation of grpc_transport_set_pollset */ void (*set_pollset)(grpc_transport* self, grpc_stream* stream, diff --git a/src/core/tsi/alts/handshaker/alts_shared_resource.h b/src/core/tsi/alts/handshaker/alts_shared_resource.h index 8ae0089a11c..d8638e7df69 100644 --- a/src/core/tsi/alts/handshaker/alts_shared_resource.h +++ b/src/core/tsi/alts/handshaker/alts_shared_resource.h @@ -48,7 +48,7 @@ alts_shared_resource_dedicated* grpc_alts_get_shared_resource_dedicated(void); /** * This method destroys the alts_shared_resource_dedicated object - * shared by all TSI handshakes. The applicaiton is responsible for + * shared by all TSI handshakes. The application is responsible for * invoking the API before calling grpc_shutdown(). */ void grpc_alts_shared_resource_dedicated_shutdown(); diff --git a/src/core/tsi/fake_transport_security.cc b/src/core/tsi/fake_transport_security.cc index 4d4c4950451..fde88dd819b 100644 --- a/src/core/tsi/fake_transport_security.cc +++ b/src/core/tsi/fake_transport_security.cc @@ -585,7 +585,7 @@ static tsi_result fake_handshaker_get_bytes_to_send_to_peer( if (next_message_to_send > TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { next_message_to_send = TSI_FAKE_HANDSHAKE_MESSAGE_MAX; } - if (tsi_tracing_enabled.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(tsi_tracing_enabled)) { gpr_log(GPR_INFO, "%s prepared %s.", impl->is_client ? "Client" : "Server", tsi_fake_handshake_message_to_string(impl->next_message_to_send)); @@ -597,7 +597,7 @@ static tsi_result fake_handshaker_get_bytes_to_send_to_peer( if (!impl->is_client && impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { /* We're done. */ - if (tsi_tracing_enabled.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(tsi_tracing_enabled)) { gpr_log(GPR_INFO, "Server is done."); } impl->result = TSI_OK; @@ -636,7 +636,7 @@ static tsi_result fake_handshaker_process_bytes_from_peer( tsi_fake_handshake_message_to_string(received_msg), tsi_fake_handshake_message_to_string(expected_msg)); } - if (tsi_tracing_enabled.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(tsi_tracing_enabled)) { gpr_log(GPR_INFO, "%s received %s.", impl->is_client ? "Client" : "Server", tsi_fake_handshake_message_to_string(received_msg)); } @@ -644,7 +644,7 @@ static tsi_result fake_handshaker_process_bytes_from_peer( impl->needs_incoming_message = 0; if (impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) { /* We're done. */ - if (tsi_tracing_enabled.enabled()) { + if (GRPC_TRACE_FLAG_ENABLED(tsi_tracing_enabled)) { gpr_log(GPR_INFO, "%s is done.", impl->is_client ? "Client" : "Server"); } impl->result = TSI_OK; diff --git a/src/core/tsi/ssl_transport_security.cc b/src/core/tsi/ssl_transport_security.cc index cbdb4227b31..25ae2cee285 100644 --- a/src/core/tsi/ssl_transport_security.cc +++ b/src/core/tsi/ssl_transport_security.cc @@ -213,7 +213,7 @@ static const char* ssl_error_string(int error) { /* TODO(jboeuf): Remove when we are past the debugging phase with this code. */ static void ssl_log_where_info(const SSL* ssl, int where, int flag, const char* msg) { - if ((where & flag) && tsi_tracing_enabled.enabled()) { + if ((where & flag) && GRPC_TRACE_FLAG_ENABLED(tsi_tracing_enabled)) { gpr_log(GPR_INFO, "%20.20s - %30.30s - %5.10s", msg, SSL_state_string_long(ssl), SSL_state_string(ssl)); } diff --git a/src/cpp/client/channel_cc.cc b/src/cpp/client/channel_cc.cc index 2d5e74163a9..f0aa8e4017a 100644 --- a/src/cpp/client/channel_cc.cc +++ b/src/cpp/client/channel_cc.cc @@ -42,14 +42,17 @@ #include "src/core/lib/gpr/string.h" #include "src/core/lib/surface/completion_queue.h" -namespace grpc { - -static internal::GrpcLibraryInitializer g_gli_initializer; -Channel::Channel( - const grpc::string& host, grpc_channel* channel, - std::vector< - std::unique_ptr> - interceptor_creators) +void ::grpc::experimental::ChannelResetConnectionBackoff(Channel* channel) { + grpc_impl::experimental::ChannelResetConnectionBackoff(channel); +} + +namespace grpc_impl { + +static ::grpc::internal::GrpcLibraryInitializer g_gli_initializer; +Channel::Channel(const grpc::string& host, grpc_channel* channel, + std::vector> + interceptor_creators) : host_(host), c_channel_(channel) { interceptor_creators_ = std::move(interceptor_creators); g_gli_initializer.summon(); @@ -65,7 +68,8 @@ Channel::~Channel() { namespace { inline grpc_slice SliceFromArray(const char* arr, size_t len) { - return g_core_codegen_interface->grpc_slice_from_copied_buffer(arr, len); + return ::grpc::g_core_codegen_interface->grpc_slice_from_copied_buffer(arr, + len); } grpc::string GetChannelInfoField(grpc_channel* channel, @@ -103,10 +107,9 @@ void ChannelResetConnectionBackoff(Channel* channel) { } // namespace experimental -internal::Call Channel::CreateCallInternal(const internal::RpcMethod& method, - ClientContext* context, - CompletionQueue* cq, - size_t interceptor_pos) { +::grpc::internal::Call Channel::CreateCallInternal( + const ::grpc::internal::RpcMethod& method, ::grpc::ClientContext* context, + ::grpc::CompletionQueue* cq, size_t interceptor_pos) { const bool kRegistered = method.channel_tag() && context->authority().empty(); grpc_call* c_call = nullptr; if (kRegistered) { @@ -115,7 +118,7 @@ internal::Call Channel::CreateCallInternal(const internal::RpcMethod& method, context->propagation_options_.c_bitmask(), cq->cq(), method.channel_tag(), context->raw_deadline(), nullptr); } else { - const string* host_str = nullptr; + const ::grpc::string* host_str = nullptr; if (!context->authority_.empty()) { host_str = &context->authority_; } else if (!host_.empty()) { @@ -125,7 +128,7 @@ internal::Call Channel::CreateCallInternal(const internal::RpcMethod& method, SliceFromArray(method.name(), strlen(method.name())); grpc_slice host_slice; if (host_str != nullptr) { - host_slice = SliceFromCopiedString(*host_str); + host_slice = ::grpc::SliceFromCopiedString(*host_str); } c_call = grpc_channel_create_call( c_channel_, context->propagate_from_call_, @@ -147,17 +150,17 @@ internal::Call Channel::CreateCallInternal(const internal::RpcMethod& method, interceptor_creators_, interceptor_pos); context->set_call(c_call, shared_from_this()); - return internal::Call(c_call, this, cq, info); + return ::grpc::internal::Call(c_call, this, cq, info); } -internal::Call Channel::CreateCall(const internal::RpcMethod& method, - ClientContext* context, - CompletionQueue* cq) { +::grpc::internal::Call Channel::CreateCall( + const ::grpc::internal::RpcMethod& method, ::grpc::ClientContext* context, + CompletionQueue* cq) { return CreateCallInternal(method, context, cq, 0); } -void Channel::PerformOpsOnCall(internal::CallOpSetInterface* ops, - internal::Call* call) { +void Channel::PerformOpsOnCall(::grpc::internal::CallOpSetInterface* ops, + ::grpc::internal::Call* call) { ops->FillOps( call); // Make a copy of call. It's fine since Call just has pointers } @@ -173,7 +176,7 @@ grpc_connectivity_state Channel::GetState(bool try_to_connect) { namespace { -class TagSaver final : public internal::CompletionQueueTag { +class TagSaver final : public ::grpc::internal::CompletionQueueTag { public: explicit TagSaver(void* tag) : tag_(tag) {} ~TagSaver() override {} @@ -191,7 +194,7 @@ class TagSaver final : public internal::CompletionQueueTag { void Channel::NotifyOnStateChangeImpl(grpc_connectivity_state last_observed, gpr_timespec deadline, - CompletionQueue* cq, void* tag) { + ::grpc::CompletionQueue* cq, void* tag) { TagSaver* tag_saver = new TagSaver(tag); grpc_channel_watch_connectivity_state(c_channel_, last_observed, deadline, cq->cq(), tag_saver); @@ -199,7 +202,7 @@ void Channel::NotifyOnStateChangeImpl(grpc_connectivity_state last_observed, bool Channel::WaitForStateChangeImpl(grpc_connectivity_state last_observed, gpr_timespec deadline) { - CompletionQueue cq; + ::grpc::CompletionQueue cq; bool ok = false; void* tag = nullptr; NotifyOnStateChangeImpl(last_observed, deadline, &cq, nullptr); @@ -214,7 +217,7 @@ class ShutdownCallback : public grpc_experimental_completion_queue_functor { ShutdownCallback() { functor_run = &ShutdownCallback::Run; } // TakeCQ takes ownership of the cq into the shutdown callback // so that the shutdown callback will be responsible for destroying it - void TakeCQ(CompletionQueue* cq) { cq_ = cq; } + void TakeCQ(::grpc::CompletionQueue* cq) { cq_ = cq; } // The Run function will get invoked by the completion queue library // when the shutdown is actually complete @@ -225,17 +228,17 @@ class ShutdownCallback : public grpc_experimental_completion_queue_functor { } private: - CompletionQueue* cq_ = nullptr; + ::grpc::CompletionQueue* cq_ = nullptr; }; } // namespace -CompletionQueue* Channel::CallbackCQ() { +::grpc::CompletionQueue* Channel::CallbackCQ() { // TODO(vjpai): Consider using a single global CQ for the default CQ // if there is no explicit per-channel CQ registered grpc::internal::MutexLock l(&mu_); if (callback_cq_ == nullptr) { auto* shutdown_callback = new ShutdownCallback; - callback_cq_ = new CompletionQueue(grpc_completion_queue_attributes{ + callback_cq_ = new ::grpc::CompletionQueue(grpc_completion_queue_attributes{ GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING, shutdown_callback}); @@ -245,4 +248,4 @@ CompletionQueue* Channel::CallbackCQ() { return callback_cq_; } -} // namespace grpc +} // namespace grpc_impl diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc index b4fce79b99a..0ae1ecbf4ba 100644 --- a/src/cpp/client/client_context.cc +++ b/src/cpp/client/client_context.cc @@ -31,6 +31,11 @@ #include #include +namespace grpc_impl { + +class Channel; +} + namespace grpc { class DefaultGlobalClientCallbacks final @@ -83,8 +88,8 @@ void ClientContext::AddMetadata(const grpc::string& meta_key, send_initial_metadata_.insert(std::make_pair(meta_key, meta_value)); } -void ClientContext::set_call(grpc_call* call, - const std::shared_ptr& channel) { +void ClientContext::set_call( + grpc_call* call, const std::shared_ptr<::grpc_impl::Channel>& channel) { grpc::internal::MutexLock lock(&mu_); GPR_ASSERT(call_ == nullptr); call_ = call; diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc index e1dca5f1a12..ca7038b8893 100644 --- a/src/cpp/client/create_channel.cc +++ b/src/cpp/client/create_channel.cc @@ -19,30 +19,27 @@ #include #include -#include +#include #include +#include #include #include "src/cpp/client/create_channel_internal.h" -namespace grpc { - -class ChannelArguments; -} namespace grpc_impl { -std::shared_ptr CreateChannel( +std::shared_ptr CreateChannelImpl( const grpc::string& target, const std::shared_ptr& creds) { - return CreateCustomChannel(target, creds, grpc::ChannelArguments()); + return CreateCustomChannelImpl(target, creds, grpc::ChannelArguments()); } -std::shared_ptr CreateCustomChannel( +std::shared_ptr CreateCustomChannelImpl( const grpc::string& target, const std::shared_ptr& creds, const grpc::ChannelArguments& args) { grpc::GrpcLibraryCodegen init_lib; // We need to call init in case of a bad creds. - return creds ? creds->CreateChannel(target, args) + return creds ? creds->CreateChannelImpl(target, args) : grpc::CreateChannelInternal( "", grpc_lame_client_channel_create( diff --git a/src/cpp/client/create_channel_internal.cc b/src/cpp/client/create_channel_internal.cc index a0efb97f7ef..63e1d14eb34 100644 --- a/src/cpp/client/create_channel_internal.cc +++ b/src/cpp/client/create_channel_internal.cc @@ -26,10 +26,11 @@ namespace grpc { std::shared_ptr CreateChannelInternal( const grpc::string& host, grpc_channel* c_channel, - std::vector< - std::unique_ptr> + std::vector> interceptor_creators) { return std::shared_ptr( new Channel(host, c_channel, std::move(interceptor_creators))); } + } // namespace grpc diff --git a/src/cpp/client/create_channel_internal.h b/src/cpp/client/create_channel_internal.h index a90c92c518d..3b201afb5a7 100644 --- a/src/cpp/client/create_channel_internal.h +++ b/src/cpp/client/create_channel_internal.h @@ -27,12 +27,11 @@ struct grpc_channel; namespace grpc { -class Channel; std::shared_ptr CreateChannelInternal( const grpc::string& host, grpc_channel* c_channel, - std::vector< - std::unique_ptr> + std::vector> interceptor_creators); } // namespace grpc diff --git a/src/cpp/client/create_channel_posix.cc b/src/cpp/client/create_channel_posix.cc index 6de373577eb..ca26c3f0a9f 100644 --- a/src/cpp/client/create_channel_posix.cc +++ b/src/cpp/client/create_channel_posix.cc @@ -19,20 +19,22 @@ #include #include #include -#include #include +#include #include "src/cpp/client/create_channel_internal.h" namespace grpc_impl { +class ChannelArguments; + #ifdef GPR_SUPPORT_CHANNELS_FROM_FD std::shared_ptr CreateInsecureChannelFromFd( const grpc::string& target, int fd) { grpc::internal::GrpcLibrary init_lib; init_lib.init(); - return grpc::CreateChannelInternal( + return ::grpc::CreateChannelInternal( "", grpc_insecure_channel_create_from_fd(target.c_str(), fd, nullptr), std::vector>()); @@ -44,7 +46,7 @@ std::shared_ptr CreateCustomInsecureChannelFromFd( init_lib.init(); grpc_channel_args channel_args; args.SetChannelArgs(&channel_args); - return grpc::CreateChannelInternal( + return ::grpc::CreateChannelInternal( "", grpc_insecure_channel_create_from_fd(target.c_str(), fd, &channel_args), std::vector #include -namespace grpc { +namespace grpc_impl { -static internal::GrpcLibraryInitializer g_gli_initializer; +static grpc::internal::GrpcLibraryInitializer g_gli_initializer; ChannelCredentials::ChannelCredentials() { g_gli_initializer.summon(); } ChannelCredentials::~ChannelCredentials() {} @@ -30,4 +30,4 @@ CallCredentials::CallCredentials() { g_gli_initializer.summon(); } CallCredentials::~CallCredentials() {} -} // namespace grpc +} // namespace grpc_impl diff --git a/src/cpp/client/cronet_credentials.cc b/src/cpp/client/cronet_credentials.cc index b2801764f20..f4ead14cde8 100644 --- a/src/cpp/client/cronet_credentials.cc +++ b/src/cpp/client/cronet_credentials.cc @@ -29,7 +29,7 @@ class CronetChannelCredentialsImpl final : public ChannelCredentials { public: CronetChannelCredentialsImpl(void* engine) : engine_(engine) {} - std::shared_ptr CreateChannel( + std::shared_ptr CreateChannelImpl( const string& target, const grpc::ChannelArguments& args) override { return CreateChannelWithInterceptors( target, args, @@ -55,10 +55,10 @@ class CronetChannelCredentialsImpl final : public ChannelCredentials { } void* engine_; }; - +} // namespace grpc +namespace grpc_impl { std::shared_ptr CronetChannelCredentials(void* engine) { return std::shared_ptr( - new CronetChannelCredentialsImpl(engine)); + new grpc::CronetChannelCredentialsImpl(engine)); } - -} // namespace grpc +} // namespace grpc_impl diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc index 241ce918034..dcbb56dccda 100644 --- a/src/cpp/client/insecure_credentials.cc +++ b/src/cpp/client/insecure_credentials.cc @@ -21,31 +21,32 @@ #include #include #include +#include #include #include #include "src/cpp/client/create_channel_internal.h" -namespace grpc { +namespace grpc_impl { namespace { class InsecureChannelCredentialsImpl final : public ChannelCredentials { public: - std::shared_ptr CreateChannel( - const string& target, const grpc::ChannelArguments& args) override { + std::shared_ptr<::grpc::Channel> CreateChannelImpl( + const grpc::string& target, const grpc::ChannelArguments& args) override { return CreateChannelWithInterceptors( target, args, std::vector>()); + grpc::experimental::ClientInterceptorFactoryInterface>>()); } - std::shared_ptr CreateChannelWithInterceptors( - const string& target, const grpc::ChannelArguments& args, - std::vector< - std::unique_ptr> + std::shared_ptr<::grpc::Channel> CreateChannelWithInterceptors( + const grpc::string& target, const grpc::ChannelArguments& args, + std::vector> interceptor_creators) override { grpc_channel_args channel_args; args.SetChannelArgs(&channel_args); - return CreateChannelInternal( + return ::grpc::CreateChannelInternal( "", grpc_insecure_channel_create(target.c_str(), &channel_args, nullptr), std::move(interceptor_creators)); @@ -60,4 +61,4 @@ std::shared_ptr InsecureChannelCredentials() { new InsecureChannelCredentialsImpl()); } -} // namespace grpc +} // namespace grpc_impl diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc index 4d0ed355aba..724a43a9709 100644 --- a/src/cpp/client/secure_credentials.cc +++ b/src/cpp/client/secure_credentials.cc @@ -25,32 +25,32 @@ #include "src/cpp/client/create_channel_internal.h" #include "src/cpp/common/secure_auth_context.h" -namespace grpc { +namespace grpc_impl { -static internal::GrpcLibraryInitializer g_gli_initializer; +static grpc::internal::GrpcLibraryInitializer g_gli_initializer; SecureChannelCredentials::SecureChannelCredentials( grpc_channel_credentials* c_creds) : c_creds_(c_creds) { g_gli_initializer.summon(); } -std::shared_ptr SecureChannelCredentials::CreateChannel( - const string& target, const grpc::ChannelArguments& args) { +std::shared_ptr SecureChannelCredentials::CreateChannelImpl( + const grpc::string& target, const grpc::ChannelArguments& args) { return CreateChannelWithInterceptors( target, args, - std::vector< - std::unique_ptr>()); + std::vector>()); } std::shared_ptr SecureChannelCredentials::CreateChannelWithInterceptors( - const string& target, const grpc::ChannelArguments& args, + const grpc::string& target, const grpc::ChannelArguments& args, std::vector< - std::unique_ptr> + std::unique_ptr> interceptor_creators) { grpc_channel_args channel_args; args.SetChannelArgs(&channel_args); - return CreateChannelInternal( + return ::grpc::CreateChannelInternal( args.GetSslTargetNameOverride(), grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args, nullptr), @@ -83,14 +83,14 @@ std::shared_ptr WrapCallCredentials( } // namespace std::shared_ptr GoogleDefaultCredentials() { - GrpcLibraryCodegen init; // To call grpc_init(). + grpc::GrpcLibraryCodegen init; // To call grpc_init(). return WrapChannelCredentials(grpc_google_default_credentials_create()); } // Builds SSL Credentials given SSL specific options std::shared_ptr SslCredentials( const SslCredentialsOptions& options) { - GrpcLibraryCodegen init; // To call grpc_init(). + grpc::GrpcLibraryCodegen init; // To call grpc_init(). grpc_ssl_pem_key_cert_pair pem_key_cert_pair = { options.pem_private_key.c_str(), options.pem_cert_chain.c_str()}; @@ -106,7 +106,7 @@ namespace experimental { // Builds ALTS Credentials given ALTS specific options std::shared_ptr AltsCredentials( const AltsCredentialsOptions& options) { - GrpcLibraryCodegen init; // To call grpc_init(). + grpc::GrpcLibraryCodegen init; // To call grpc_init(). grpc_alts_credentials_options* c_options = grpc_alts_credentials_client_options_create(); for (auto service_account = options.target_service_accounts.begin(); @@ -123,7 +123,7 @@ std::shared_ptr AltsCredentials( // Builds Local Credentials std::shared_ptr LocalCredentials( grpc_local_connect_type type) { - GrpcLibraryCodegen init; // To call grpc_init(). + grpc::GrpcLibraryCodegen init; // To call grpc_init(). return WrapChannelCredentials(grpc_local_credentials_create(type)); } @@ -131,7 +131,7 @@ std::shared_ptr LocalCredentials( // Builds credentials for use when running in GCE std::shared_ptr GoogleComputeEngineCredentials() { - GrpcLibraryCodegen init; // To call grpc_init(). + grpc::GrpcLibraryCodegen init; // To call grpc_init(). return WrapCallCredentials( grpc_google_compute_engine_credentials_create(nullptr)); } @@ -139,7 +139,7 @@ std::shared_ptr GoogleComputeEngineCredentials() { // Builds JWT credentials. std::shared_ptr ServiceAccountJWTAccessCredentials( const grpc::string& json_key, long token_lifetime_seconds) { - GrpcLibraryCodegen init; // To call grpc_init(). + grpc::GrpcLibraryCodegen init; // To call grpc_init(). if (token_lifetime_seconds <= 0) { gpr_log(GPR_ERROR, "Trying to create JWTCredentials with non-positive lifetime"); @@ -154,7 +154,7 @@ std::shared_ptr ServiceAccountJWTAccessCredentials( // Builds refresh token credentials. std::shared_ptr GoogleRefreshTokenCredentials( const grpc::string& json_refresh_token) { - GrpcLibraryCodegen init; // To call grpc_init(). + grpc::GrpcLibraryCodegen init; // To call grpc_init(). return WrapCallCredentials(grpc_google_refresh_token_credentials_create( json_refresh_token.c_str(), nullptr)); } @@ -162,7 +162,7 @@ std::shared_ptr GoogleRefreshTokenCredentials( // Builds access token credentials. std::shared_ptr AccessTokenCredentials( const grpc::string& access_token) { - GrpcLibraryCodegen init; // To call grpc_init(). + grpc::GrpcLibraryCodegen init; // To call grpc_init(). return WrapCallCredentials( grpc_access_token_credentials_create(access_token.c_str(), nullptr)); } @@ -171,7 +171,7 @@ std::shared_ptr AccessTokenCredentials( std::shared_ptr GoogleIAMCredentials( const grpc::string& authorization_token, const grpc::string& authority_selector) { - GrpcLibraryCodegen init; // To call grpc_init(). + grpc::GrpcLibraryCodegen init; // To call grpc_init(). return WrapCallCredentials(grpc_google_iam_credentials_create( authorization_token.c_str(), authority_selector.c_str(), nullptr)); } @@ -207,6 +207,23 @@ std::shared_ptr CompositeCallCredentials( return nullptr; } +std::shared_ptr MetadataCredentialsFromPlugin( + std::unique_ptr plugin) { + grpc::GrpcLibraryCodegen init; // To call grpc_init(). + const char* type = plugin->GetType(); + grpc::MetadataCredentialsPluginWrapper* wrapper = + new grpc::MetadataCredentialsPluginWrapper(std::move(plugin)); + grpc_metadata_credentials_plugin c_plugin = { + grpc::MetadataCredentialsPluginWrapper::GetMetadata, + grpc::MetadataCredentialsPluginWrapper::Destroy, wrapper, type}; + return WrapCallCredentials( + grpc_metadata_credentials_create_from_plugin(c_plugin, nullptr)); +} + +} // namespace grpc_impl + +namespace grpc { + void MetadataCredentialsPluginWrapper::Destroy(void* wrapper) { if (wrapper == nullptr) return; MetadataCredentialsPluginWrapper* w = @@ -308,17 +325,4 @@ MetadataCredentialsPluginWrapper::MetadataCredentialsPluginWrapper( std::unique_ptr plugin) : thread_pool_(CreateDefaultThreadPool()), plugin_(std::move(plugin)) {} -std::shared_ptr MetadataCredentialsFromPlugin( - std::unique_ptr plugin) { - GrpcLibraryCodegen init; // To call grpc_init(). - const char* type = plugin->GetType(); - MetadataCredentialsPluginWrapper* wrapper = - new MetadataCredentialsPluginWrapper(std::move(plugin)); - grpc_metadata_credentials_plugin c_plugin = { - MetadataCredentialsPluginWrapper::GetMetadata, - MetadataCredentialsPluginWrapper::Destroy, wrapper, type}; - return WrapCallCredentials( - grpc_metadata_credentials_create_from_plugin(c_plugin, nullptr)); -} - } // namespace grpc diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h index 4918bd5a4d7..c4eef6c746d 100644 --- a/src/cpp/client/secure_credentials.h +++ b/src/cpp/client/secure_credentials.h @@ -27,7 +27,9 @@ #include "src/core/lib/security/credentials/credentials.h" #include "src/cpp/server/thread_pool_interface.h" -namespace grpc { +namespace grpc_impl { + +class Channel; class SecureChannelCredentials final : public ChannelCredentials { public: @@ -37,16 +39,16 @@ class SecureChannelCredentials final : public ChannelCredentials { } grpc_channel_credentials* GetRawCreds() { return c_creds_; } - std::shared_ptr CreateChannel( - const string& target, const grpc::ChannelArguments& args) override; + std::shared_ptr<::grpc::Channel> CreateChannelImpl( + const grpc::string& target, const grpc::ChannelArguments& args) override; SecureChannelCredentials* AsSecureCredentials() override { return this; } private: - std::shared_ptr CreateChannelWithInterceptors( - const string& target, const grpc::ChannelArguments& args, - std::vector< - std::unique_ptr> + std::shared_ptr<::grpc::Channel> CreateChannelWithInterceptors( + const grpc::string& target, const grpc::ChannelArguments& args, + std::vector> interceptor_creators) override; grpc_channel_credentials* const c_creds_; }; @@ -66,6 +68,10 @@ class SecureCallCredentials final : public CallCredentials { grpc_call_credentials* const c_creds_; }; +} // namespace grpc_impl + +namespace grpc { + class MetadataCredentialsPluginWrapper final : private GrpcLibraryCodegen { public: static void Destroy(void* wrapper); diff --git a/src/cpp/common/channel_arguments.cc b/src/cpp/common/channel_arguments.cc index c3d75054b9b..932139890fe 100644 --- a/src/cpp/common/channel_arguments.cc +++ b/src/cpp/common/channel_arguments.cc @@ -27,11 +27,11 @@ #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/iomgr/socket_mutator.h" -namespace grpc { +namespace grpc_impl { ChannelArguments::ChannelArguments() { // This will be ignored if used on the server side. - SetString(GRPC_ARG_PRIMARY_USER_AGENT_STRING, "grpc-c++/" + Version()); + SetString(GRPC_ARG_PRIMARY_USER_AGENT_STRING, "grpc-c++/" + grpc::Version()); } ChannelArguments::ChannelArguments(const ChannelArguments& other) @@ -215,4 +215,4 @@ void ChannelArguments::SetChannelArgs(grpc_channel_args* channel_args) const { } } -} // namespace grpc +} // namespace grpc_impl diff --git a/src/cpp/common/channel_filter.cc b/src/cpp/common/channel_filter.cc index 422e7bb65ee..8df6c7b98f5 100644 --- a/src/cpp/common/channel_filter.cc +++ b/src/cpp/common/channel_filter.cc @@ -30,7 +30,6 @@ namespace grpc { grpc_linked_mdelem* MetadataBatch::AddMetadata(const string& key, const string& value) { grpc_linked_mdelem* storage = new grpc_linked_mdelem; - memset(storage, 0, sizeof(grpc_linked_mdelem)); storage->md = grpc_mdelem_from_slices(SliceFromCopiedString(key), SliceFromCopiedString(value)); GRPC_LOG_IF_ERROR("MetadataBatch::AddMetadata", diff --git a/src/cpp/common/completion_queue_cc.cc b/src/cpp/common/completion_queue_cc.cc index 4bb3bcbd8b6..43c2eee96f8 100644 --- a/src/cpp/common/completion_queue_cc.cc +++ b/src/cpp/common/completion_queue_cc.cc @@ -24,9 +24,9 @@ #include #include -namespace grpc { +namespace grpc_impl { -static internal::GrpcLibraryInitializer g_gli_initializer; +static ::grpc::internal::GrpcLibraryInitializer g_gli_initializer; // 'CompletionQueue' constructor can safely call GrpcLibraryCodegen(false) here // i.e not have GrpcLibraryCodegen call grpc_init(). This is because, to create @@ -52,7 +52,8 @@ CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal( case GRPC_QUEUE_SHUTDOWN: return SHUTDOWN; case GRPC_OP_COMPLETE: - auto core_cq_tag = static_cast(ev.tag); + auto core_cq_tag = + static_cast<::grpc::internal::CompletionQueueTag*>(ev.tag); *ok = ev.success != 0; *tag = core_cq_tag; if (core_cq_tag->FinalizeResult(tag, ok)) { @@ -79,7 +80,8 @@ bool CompletionQueue::CompletionQueueTLSCache::Flush(void** tag, bool* ok) { flushed_ = true; if (grpc_completion_queue_thread_local_cache_flush(cq_->cq_, &res_tag, &res)) { - auto core_cq_tag = static_cast(res_tag); + auto core_cq_tag = + static_cast<::grpc::internal::CompletionQueueTag*>(res_tag); *ok = res == 1; if (core_cq_tag->FinalizeResult(tag, ok)) { return true; @@ -88,4 +90,4 @@ bool CompletionQueue::CompletionQueueTLSCache::Flush(void** tag, bool* ok) { return false; } -} // namespace grpc +} // namespace grpc_impl diff --git a/src/cpp/common/secure_channel_arguments.cc b/src/cpp/common/secure_channel_arguments.cc index 2fb8ea44fbc..e5d03cd2378 100644 --- a/src/cpp/common/secure_channel_arguments.cc +++ b/src/cpp/common/secure_channel_arguments.cc @@ -21,7 +21,7 @@ #include #include "src/core/lib/channel/channel_args.h" -namespace grpc { +namespace grpc_impl { void ChannelArguments::SetSslTargetNameOverride(const grpc::string& name) { SetString(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, name); @@ -36,4 +36,4 @@ grpc::string ChannelArguments::GetSslTargetNameOverride() const { return ""; } -} // namespace grpc +} // namespace grpc_impl diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc index 166c2d39b35..76e2773e938 100644 --- a/src/cpp/common/version_cc.cc +++ b/src/cpp/common/version_cc.cc @@ -22,5 +22,5 @@ #include namespace grpc { -grpc::string Version() { return "1.21.0-dev"; } +grpc::string Version() { return "1.22.0-dev"; } } // namespace grpc diff --git a/src/cpp/server/external_connection_acceptor_impl.cc b/src/cpp/server/external_connection_acceptor_impl.cc new file mode 100644 index 00000000000..afc90679398 --- /dev/null +++ b/src/cpp/server/external_connection_acceptor_impl.cc @@ -0,0 +1,96 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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/cpp/server/external_connection_acceptor_impl.h" + +#include + +#include +#include + +namespace grpc { +namespace internal { +namespace { +// The actual type to return to user. It co-owns the internal impl object with +// the server. +class AcceptorWrapper : public experimental::ExternalConnectionAcceptor { + public: + explicit AcceptorWrapper(std::shared_ptr impl) + : impl_(std::move(impl)) {} + void HandleNewConnection(NewConnectionParameters* p) override { + impl_->HandleNewConnection(p); + } + + private: + std::shared_ptr impl_; +}; +} // namespace + +ExternalConnectionAcceptorImpl::ExternalConnectionAcceptorImpl( + const grpc::string& name, + ServerBuilder::experimental_type::ExternalConnectionType type, + std::shared_ptr creds) + : name_(name), creds_(std::move(creds)) { + GPR_ASSERT(type == + ServerBuilder::experimental_type::ExternalConnectionType::FROM_FD); +} + +std::unique_ptr +ExternalConnectionAcceptorImpl::GetAcceptor() { + std::lock_guard lock(mu_); + GPR_ASSERT(!has_acceptor_); + has_acceptor_ = true; + return std::unique_ptr( + new AcceptorWrapper(shared_from_this())); +} + +void ExternalConnectionAcceptorImpl::HandleNewConnection( + experimental::ExternalConnectionAcceptor::NewConnectionParameters* p) { + std::lock_guard lock(mu_); + if (shutdown_ || !started_) { + // TODO(yangg) clean up. + gpr_log( + GPR_ERROR, + "NOT handling external connection with fd %d, started %d, shutdown %d", + p->fd, started_, shutdown_); + return; + } + if (handler_) { + handler_->Handle(p->fd, p->read_buffer.c_buffer()); + } +} + +void ExternalConnectionAcceptorImpl::Shutdown() { + std::lock_guard lock(mu_); + shutdown_ = true; +} + +void ExternalConnectionAcceptorImpl::Start() { + std::lock_guard lock(mu_); + GPR_ASSERT(!started_); + GPR_ASSERT(has_acceptor_); + GPR_ASSERT(!shutdown_); + started_ = true; +} + +void ExternalConnectionAcceptorImpl::SetToChannelArgs(ChannelArguments* args) { + args->SetPointer(name_.c_str(), &handler_); +} + +} // namespace internal +} // namespace grpc diff --git a/src/cpp/server/external_connection_acceptor_impl.h b/src/cpp/server/external_connection_acceptor_impl.h new file mode 100644 index 00000000000..b5bd935c784 --- /dev/null +++ b/src/cpp/server/external_connection_acceptor_impl.h @@ -0,0 +1,72 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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 SRC_CPP_SERVER_EXTERNAL_CONNECTION_ACCEPTOR_IMPL_H_ +#define SRC_CPP_SERVER_EXTERNAL_CONNECTION_ACCEPTOR_IMPL_H_ + +#include +#include + +#include +#include +#include +#include +#include + +#include "src/core/lib/iomgr/tcp_server.h" + +namespace grpc { +namespace internal { + +class ExternalConnectionAcceptorImpl + : public std::enable_shared_from_this { + public: + ExternalConnectionAcceptorImpl( + const grpc::string& name, + ServerBuilder::experimental_type::ExternalConnectionType type, + std::shared_ptr creds); + // Should only be called once. + std::unique_ptr GetAcceptor(); + + void HandleNewConnection( + experimental::ExternalConnectionAcceptor::NewConnectionParameters* p); + + void Shutdown(); + + void Start(); + + const char* name() { return name_.c_str(); } + + ServerCredentials* GetCredentials() { return creds_.get(); } + + void SetToChannelArgs(::grpc::ChannelArguments* args); + + private: + const grpc::string name_; + std::shared_ptr creds_; + grpc_core::TcpServerFdHandler* handler_ = nullptr; // not owned + std::mutex mu_; + bool has_acceptor_ = false; + bool started_ = false; + bool shutdown_ = false; +}; + +} // namespace internal +} // namespace grpc + +#endif // SRC_CPP_SERVER_EXTERNAL_CONNECTION_ACCEPTOR_IMPL_H_ diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc index af76ffbe9b5..1ba9ae1c9dc 100644 --- a/src/cpp/server/server_builder.cc +++ b/src/cpp/server/server_builder.cc @@ -26,7 +26,9 @@ #include +#include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/useful.h" +#include "src/cpp/server/external_connection_acceptor_impl.h" #include "src/cpp/server/thread_pool_interface.h" namespace grpc_impl { @@ -114,6 +116,19 @@ ServerBuilder& ServerBuilder::experimental_type::RegisterCallbackGenericService( return *builder_; } +std::unique_ptr +ServerBuilder::experimental_type::AddExternalConnectionAcceptor( + experimental_type::ExternalConnectionType type, + std::shared_ptr creds) { + grpc::string name_prefix("external:"); + char count_str[GPR_LTOA_MIN_BUFSIZE]; + gpr_ltoa(static_cast(builder_->acceptors_.size()), count_str); + builder_->acceptors_.emplace_back( + std::make_shared( + name_prefix.append(count_str), type, creds)); + return builder_->acceptors_.back()->GetAcceptor(); +} + ServerBuilder& ServerBuilder::SetOption( std::unique_ptr option) { options_.push_back(std::move(option)); @@ -307,8 +322,8 @@ std::unique_ptr ServerBuilder::BuildAndStart() { std::unique_ptr server(new grpc::Server( max_receive_message_size_, &args, sync_server_cqs, sync_server_settings_.min_pollers, sync_server_settings_.max_pollers, - sync_server_settings_.cq_timeout_msec, resource_quota_, - std::move(interceptor_creators_))); + sync_server_settings_.cq_timeout_msec, std::move(acceptors_), + resource_quota_, std::move(interceptor_creators_))); grpc_impl::ServerInitializer* initializer = server->initializer(); diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc index 63608cbcde6..02cfb59c0e6 100644 --- a/src/cpp/server/server_cc.cc +++ b/src/cpp/server/server_cc.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,7 @@ #include "src/core/lib/surface/call.h" #include "src/core/lib/surface/completion_queue.h" #include "src/cpp/client/create_channel_internal.h" +#include "src/cpp/server/external_connection_acceptor_impl.h" #include "src/cpp/server/health/default_health_check_service.h" #include "src/cpp/thread_manager/thread_manager.h" @@ -106,15 +108,183 @@ class UnimplementedAsyncRequestContext { } // namespace +ServerInterface::BaseAsyncRequest::BaseAsyncRequest( + ServerInterface* server, ServerContext* context, + internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, + ServerCompletionQueue* notification_cq, void* tag, bool delete_on_finalize) + : server_(server), + context_(context), + stream_(stream), + call_cq_(call_cq), + notification_cq_(notification_cq), + tag_(tag), + delete_on_finalize_(delete_on_finalize), + call_(nullptr), + done_intercepting_(false) { + /* Set up interception state partially for the receive ops. call_wrapper_ is + * not filled at this point, but it will be filled before the interceptors are + * run. */ + interceptor_methods_.SetCall(&call_wrapper_); + interceptor_methods_.SetReverse(); + call_cq_->RegisterAvalanching(); // This op will trigger more ops +} + +ServerInterface::BaseAsyncRequest::~BaseAsyncRequest() { + call_cq_->CompleteAvalanching(); +} + +bool ServerInterface::BaseAsyncRequest::FinalizeResult(void** tag, + bool* status) { + if (done_intercepting_) { + *tag = tag_; + if (delete_on_finalize_) { + delete this; + } + return true; + } + context_->set_call(call_); + context_->cq_ = call_cq_; + if (call_wrapper_.call() == nullptr) { + // Fill it since it is empty. + call_wrapper_ = internal::Call( + call_, server_, call_cq_, server_->max_receive_message_size(), nullptr); + } + + // just the pointers inside call are copied here + stream_->BindCall(&call_wrapper_); + + if (*status && call_ && call_wrapper_.server_rpc_info()) { + done_intercepting_ = true; + // Set interception point for RECV INITIAL METADATA + interceptor_methods_.AddInterceptionHookPoint( + experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA); + interceptor_methods_.SetRecvInitialMetadata(&context_->client_metadata_); + if (interceptor_methods_.RunInterceptors( + [this]() { ContinueFinalizeResultAfterInterception(); })) { + // There are no interceptors to run. Continue + } else { + // There were interceptors to be run, so + // ContinueFinalizeResultAfterInterception will be run when interceptors + // are done. + return false; + } + } + if (*status && call_) { + context_->BeginCompletionOp(&call_wrapper_, nullptr, nullptr); + } + *tag = tag_; + if (delete_on_finalize_) { + delete this; + } + return true; +} + +void ServerInterface::BaseAsyncRequest:: + ContinueFinalizeResultAfterInterception() { + context_->BeginCompletionOp(&call_wrapper_, nullptr, nullptr); + // Queue a tag which will be returned immediately + grpc_core::ExecCtx exec_ctx; + grpc_cq_begin_op(notification_cq_->cq(), this); + grpc_cq_end_op( + notification_cq_->cq(), this, GRPC_ERROR_NONE, + [](void* arg, grpc_cq_completion* completion) { delete completion; }, + nullptr, new grpc_cq_completion()); +} + +ServerInterface::RegisteredAsyncRequest::RegisteredAsyncRequest( + ServerInterface* server, ServerContext* context, + internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, + ServerCompletionQueue* notification_cq, void* tag, const char* name, + internal::RpcMethod::RpcType type) + : BaseAsyncRequest(server, context, stream, call_cq, notification_cq, tag, + true), + name_(name), + type_(type) {} + +void ServerInterface::RegisteredAsyncRequest::IssueRequest( + void* registered_method, grpc_byte_buffer** payload, + ServerCompletionQueue* notification_cq) { + GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_registered_call( + server_->server(), registered_method, &call_, + &context_->deadline_, + context_->client_metadata_.arr(), payload, + call_cq_->cq(), notification_cq->cq(), this)); +} + +ServerInterface::GenericAsyncRequest::GenericAsyncRequest( + ServerInterface* server, GenericServerContext* context, + internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, + ServerCompletionQueue* notification_cq, void* tag, bool delete_on_finalize) + : BaseAsyncRequest(server, context, stream, call_cq, notification_cq, tag, + delete_on_finalize) { + grpc_call_details_init(&call_details_); + GPR_ASSERT(notification_cq); + GPR_ASSERT(call_cq); + GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call( + server->server(), &call_, &call_details_, + context->client_metadata_.arr(), call_cq->cq(), + notification_cq->cq(), this)); +} + +bool ServerInterface::GenericAsyncRequest::FinalizeResult(void** tag, + bool* status) { + // If we are done intercepting, there is nothing more for us to do + if (done_intercepting_) { + return BaseAsyncRequest::FinalizeResult(tag, status); + } + // TODO(yangg) remove the copy here. + if (*status) { + static_cast(context_)->method_ = + StringFromCopiedSlice(call_details_.method); + static_cast(context_)->host_ = + StringFromCopiedSlice(call_details_.host); + context_->deadline_ = call_details_.deadline; + } + grpc_slice_unref(call_details_.method); + grpc_slice_unref(call_details_.host); + call_wrapper_ = internal::Call( + call_, server_, call_cq_, server_->max_receive_message_size(), + context_->set_server_rpc_info( + static_cast(context_)->method_.c_str(), + internal::RpcMethod::BIDI_STREAMING, + *server_->interceptor_creators())); + return BaseAsyncRequest::FinalizeResult(tag, status); +} + +namespace { +class ShutdownCallback : public grpc_experimental_completion_queue_functor { + public: + ShutdownCallback() { functor_run = &ShutdownCallback::Run; } + // TakeCQ takes ownership of the cq into the shutdown callback + // so that the shutdown callback will be responsible for destroying it + void TakeCQ(CompletionQueue* cq) { cq_ = cq; } + + // The Run function will get invoked by the completion queue library + // when the shutdown is actually complete + static void Run(grpc_experimental_completion_queue_functor* cb, int) { + auto* callback = static_cast(cb); + delete callback->cq_; + delete callback; + } + + private: + CompletionQueue* cq_ = nullptr; +}; +} // namespace + +} // namespace grpc + +namespace grpc_impl { + /// Use private inheritance rather than composition only to establish order /// of construction, since the public base class should be constructed after the /// elements belonging to the private base class are constructed. This is not /// possible using true composition. class Server::UnimplementedAsyncRequest final - : private UnimplementedAsyncRequestContext, + : private grpc::UnimplementedAsyncRequestContext, public GenericAsyncRequest { public: - UnimplementedAsyncRequest(Server* server, ServerCompletionQueue* cq) + UnimplementedAsyncRequest(Server* server, grpc::ServerCompletionQueue* cq) : GenericAsyncRequest(server, &server_context_, &generic_stream_, cq, cq, nullptr, false), server_(server), @@ -122,27 +292,29 @@ class Server::UnimplementedAsyncRequest final bool FinalizeResult(void** tag, bool* status) override; - ServerContext* context() { return &server_context_; } - GenericServerAsyncReaderWriter* stream() { return &generic_stream_; } + grpc::ServerContext* context() { return &server_context_; } + grpc::GenericServerAsyncReaderWriter* stream() { return &generic_stream_; } private: Server* const server_; - ServerCompletionQueue* const cq_; + grpc::ServerCompletionQueue* const cq_; }; /// UnimplementedAsyncResponse should not post user-visible completions to the /// C++ completion queue, but is generated as a CQ event by the core class Server::UnimplementedAsyncResponse final - : public internal::CallOpSet { + : public grpc::internal::CallOpSet< + grpc::internal::CallOpSendInitialMetadata, + grpc::internal::CallOpServerSendStatus> { public: UnimplementedAsyncResponse(UnimplementedAsyncRequest* request); ~UnimplementedAsyncResponse() { delete request_; } bool FinalizeResult(void** tag, bool* status) override { - if (internal::CallOpSet< - internal::CallOpSendInitialMetadata, - internal::CallOpServerSendStatus>::FinalizeResult(tag, status)) { + if (grpc::internal::CallOpSet< + grpc::internal::CallOpSendInitialMetadata, + grpc::internal::CallOpServerSendStatus>::FinalizeResult(tag, + status)) { delete this; } else { // The tag was swallowed due to interception. We will see it again. @@ -154,15 +326,16 @@ class Server::UnimplementedAsyncResponse final UnimplementedAsyncRequest* const request_; }; -class Server::SyncRequest final : public internal::CompletionQueueTag { +class Server::SyncRequest final : public grpc::internal::CompletionQueueTag { public: - SyncRequest(internal::RpcServiceMethod* method, void* method_tag) + SyncRequest(grpc::internal::RpcServiceMethod* method, void* method_tag) : method_(method), method_tag_(method_tag), in_flight_(false), - has_request_payload_( - method->method_type() == internal::RpcMethod::NORMAL_RPC || - method->method_type() == internal::RpcMethod::SERVER_STREAMING), + has_request_payload_(method->method_type() == + grpc::internal::RpcMethod::NORMAL_RPC || + method->method_type() == + grpc::internal::RpcMethod::SERVER_STREAMING), call_details_(nullptr), cq_(nullptr) { grpc_metadata_array_init(&request_metadata_); @@ -273,7 +446,8 @@ class Server::SyncRequest final : public internal::CompletionQueueTag { interceptor_methods_.SetReverse(); // Set interception point for RECV INITIAL METADATA interceptor_methods_.AddInterceptionHookPoint( - experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA); + grpc::experimental::InterceptionHookPoints:: + POST_RECV_INITIAL_METADATA); interceptor_methods_.SetRecvInitialMetadata(&ctx_.client_metadata_); if (has_request_payload_) { @@ -285,7 +459,7 @@ class Server::SyncRequest final : public internal::CompletionQueueTag { request_payload_ = nullptr; interceptor_methods_.AddInterceptionHookPoint( - experimental::InterceptionHookPoints::POST_RECV_MESSAGE); + grpc::experimental::InterceptionHookPoints::POST_RECV_MESSAGE); interceptor_methods_.SetRecvMessage(request_, nullptr); } @@ -304,40 +478,40 @@ class Server::SyncRequest final : public internal::CompletionQueueTag { global_callbacks_->PreSynchronousRequest(&ctx_); auto* handler = resources_ ? method_->handler() : server_->resource_exhausted_handler_.get(); - handler->RunHandler(internal::MethodHandler::HandlerParameter( + handler->RunHandler(grpc::internal::MethodHandler::HandlerParameter( &call_, &ctx_, request_, request_status_, nullptr, nullptr)); request_ = nullptr; global_callbacks_->PostSynchronousRequest(&ctx_); cq_.Shutdown(); - internal::CompletionQueueTag* op_tag = ctx_.GetCompletionOpTag(); + grpc::internal::CompletionQueueTag* op_tag = ctx_.GetCompletionOpTag(); cq_.TryPluck(op_tag, gpr_inf_future(GPR_CLOCK_REALTIME)); /* Ensure the cq_ is shutdown */ - DummyTag ignored_tag; + grpc::DummyTag ignored_tag; GPR_ASSERT(cq_.Pluck(&ignored_tag) == false); } delete this; } private: - CompletionQueue cq_; - ServerContext ctx_; + grpc::CompletionQueue cq_; + grpc::ServerContext ctx_; const bool has_request_payload_; grpc_byte_buffer* request_payload_; void* request_; - Status request_status_; - internal::RpcServiceMethod* const method_; - internal::Call call_; + grpc::Status request_status_; + grpc::internal::RpcServiceMethod* const method_; + grpc::internal::Call call_; Server* server_; std::shared_ptr global_callbacks_; bool resources_; - internal::InterceptorBatchMethodsImpl interceptor_methods_; + grpc::internal::InterceptorBatchMethodsImpl interceptor_methods_; }; private: - internal::RpcServiceMethod* const method_; + grpc::internal::RpcServiceMethod* const method_; void* const method_tag_; bool in_flight_; const bool has_request_payload_; @@ -349,7 +523,7 @@ class Server::SyncRequest final : public internal::CompletionQueueTag { grpc_completion_queue* cq_; }; -class Server::CallbackRequestBase : public internal::CompletionQueueTag { +class Server::CallbackRequestBase : public grpc::internal::CompletionQueueTag { public: virtual ~CallbackRequestBase() {} virtual bool Request() = 0; @@ -358,7 +532,7 @@ class Server::CallbackRequestBase : public internal::CompletionQueueTag { template class Server::CallbackRequest final : public Server::CallbackRequestBase { public: - static_assert(std::is_base_of::value, + static_assert(std::is_base_of::value, "ServerContextType must be derived from ServerContext"); // The constructor needs to know the server for this callback request and its @@ -368,15 +542,16 @@ class Server::CallbackRequest final : public Server::CallbackRequestBase { // requested. For generic services, method and method_tag are nullptr since // these services don't have pre-defined methods or method registration tags. CallbackRequest(Server* server, size_t method_idx, - internal::RpcServiceMethod* method, void* method_tag) + grpc::internal::RpcServiceMethod* method, void* method_tag) : server_(server), method_index_(method_idx), method_(method), method_tag_(method_tag), has_request_payload_( method_ != nullptr && - (method->method_type() == internal::RpcMethod::NORMAL_RPC || - method->method_type() == internal::RpcMethod::SERVER_STREAMING)), + (method->method_type() == grpc::internal::RpcMethod::NORMAL_RPC || + method->method_type() == + grpc::internal::RpcMethod::SERVER_STREAMING)), cq_(server->CallbackCQ()), tag_(this) { server_->callback_reqs_outstanding_++; @@ -440,7 +615,7 @@ class Server::CallbackRequest final : public Server::CallbackRequestBase { private: Server::CallbackRequest* req_; - internal::Call* call_; + grpc::internal::Call* call_; static void StaticRun(grpc_experimental_completion_queue_functor* cb, int ok) { @@ -491,21 +666,24 @@ class Server::CallbackRequest final : public Server::CallbackRequestBase { req_->request_metadata_.count = 0; // Create a C++ Call to control the underlying core call - call_ = new (grpc_call_arena_alloc(req_->call_, sizeof(internal::Call))) - internal::Call(req_->call_, req_->server_, req_->cq_, - req_->server_->max_receive_message_size(), - req_->ctx_.set_server_rpc_info( - req_->method_name(), - (req_->method_ != nullptr) - ? req_->method_->method_type() - : internal::RpcMethod::BIDI_STREAMING, - req_->server_->interceptor_creators_)); + call_ = + new (grpc_call_arena_alloc(req_->call_, sizeof(grpc::internal::Call))) + grpc::internal::Call( + req_->call_, req_->server_, req_->cq_, + req_->server_->max_receive_message_size(), + req_->ctx_.set_server_rpc_info( + req_->method_name(), + (req_->method_ != nullptr) + ? req_->method_->method_type() + : grpc::internal::RpcMethod::BIDI_STREAMING, + req_->server_->interceptor_creators_)); req_->interceptor_methods_.SetCall(call_); req_->interceptor_methods_.SetReverse(); // Set interception point for RECV INITIAL METADATA req_->interceptor_methods_.AddInterceptionHookPoint( - experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA); + grpc::experimental::InterceptionHookPoints:: + POST_RECV_INITIAL_METADATA); req_->interceptor_methods_.SetRecvInitialMetadata( &req_->ctx_.client_metadata_); @@ -516,7 +694,7 @@ class Server::CallbackRequest final : public Server::CallbackRequestBase { &req_->handler_data_); req_->request_payload_ = nullptr; req_->interceptor_methods_.AddInterceptionHookPoint( - experimental::InterceptionHookPoints::POST_RECV_MESSAGE); + grpc::experimental::InterceptionHookPoints::POST_RECV_MESSAGE); req_->interceptor_methods_.SetRecvMessage(req_->request_, nullptr); } @@ -532,7 +710,7 @@ class Server::CallbackRequest final : public Server::CallbackRequestBase { auto* handler = (req_->method_ != nullptr) ? req_->method_->handler() : req_->server_->generic_handler_.get(); - handler->RunHandler(internal::MethodHandler::HandlerParameter( + handler->RunHandler(grpc::internal::MethodHandler::HandlerParameter( call_, &req_->ctx_, req_->request_, req_->request_status_, req_->handler_data_, [this] { // Recycle this request if there aren't too many outstanding. @@ -580,41 +758,41 @@ class Server::CallbackRequest final : public Server::CallbackRequestBase { request_payload_ = nullptr; request_ = nullptr; handler_data_ = nullptr; - request_status_ = Status(); + request_status_ = grpc::Status(); } Server* const server_; const size_t method_index_; - internal::RpcServiceMethod* const method_; + grpc::internal::RpcServiceMethod* const method_; void* const method_tag_; const bool has_request_payload_; grpc_byte_buffer* request_payload_; void* request_; void* handler_data_; - Status request_status_; + grpc::Status request_status_; grpc_call_details* call_details_ = nullptr; grpc_call* call_; gpr_timespec deadline_; grpc_metadata_array request_metadata_; - CompletionQueue* cq_; + grpc::CompletionQueue* cq_; CallbackCallTag tag_; ServerContextType ctx_; - internal::InterceptorBatchMethodsImpl interceptor_methods_; + grpc::internal::InterceptorBatchMethodsImpl interceptor_methods_; }; template <> -bool Server::CallbackRequest::FinalizeResult(void** tag, - bool* status) { +bool Server::CallbackRequest::FinalizeResult( + void** tag, bool* status) { return false; } template <> -bool Server::CallbackRequest::FinalizeResult( +bool Server::CallbackRequest::FinalizeResult( void** tag, bool* status) { if (*status) { // TODO(yangg) remove the copy here - ctx_.method_ = StringFromCopiedSlice(call_details_->method); - ctx_.host_ = StringFromCopiedSlice(call_details_->host); + ctx_.method_ = grpc::StringFromCopiedSlice(call_details_->method); + ctx_.host_ = grpc::StringFromCopiedSlice(call_details_->host); } grpc_slice_unref(call_details_->method); grpc_slice_unref(call_details_->host); @@ -622,21 +800,22 @@ bool Server::CallbackRequest::FinalizeResult( } template <> -const char* Server::CallbackRequest::method_name() const { +const char* Server::CallbackRequest::method_name() const { return method_->name(); } template <> -const char* Server::CallbackRequest::method_name() const { +const char* Server::CallbackRequest::method_name() + const { return ctx_.method().c_str(); } // Implementation of ThreadManager. Each instance of SyncRequestThreadManager // manages a pool of threads that poll for incoming Sync RPCs and call the // appropriate RPC handlers -class Server::SyncRequestThreadManager : public ThreadManager { +class Server::SyncRequestThreadManager : public grpc::ThreadManager { public: - SyncRequestThreadManager(Server* server, CompletionQueue* server_cq, + SyncRequestThreadManager(Server* server, grpc::CompletionQueue* server_cq, std::shared_ptr global_callbacks, grpc_resource_quota* rq, int min_pollers, int max_pollers, int cq_timeout_msec) @@ -655,11 +834,11 @@ class Server::SyncRequestThreadManager : public ThreadManager { gpr_time_from_millis(cq_timeout_msec_, GPR_TIMESPAN)); switch (server_cq_->AsyncNext(tag, ok, deadline)) { - case CompletionQueue::TIMEOUT: + case grpc::CompletionQueue::TIMEOUT: return TIMEOUT; - case CompletionQueue::SHUTDOWN: + case grpc::CompletionQueue::SHUTDOWN: return SHUTDOWN; - case CompletionQueue::GOT_EVENT: + case grpc::CompletionQueue::GOT_EVENT: return WORK_FOUND; } @@ -694,15 +873,15 @@ class Server::SyncRequestThreadManager : public ThreadManager { // object } - void AddSyncMethod(internal::RpcServiceMethod* method, void* tag) { + void AddSyncMethod(grpc::internal::RpcServiceMethod* method, void* tag) { sync_requests_.emplace_back(new SyncRequest(method, tag)); } void AddUnknownSyncMethod() { if (!sync_requests_.empty()) { - unknown_method_.reset(new internal::RpcServiceMethod( - "unknown", internal::RpcMethod::BIDI_STREAMING, - new internal::UnknownMethodHandler)); + unknown_method_.reset(new grpc::internal::RpcServiceMethod( + "unknown", grpc::internal::RpcMethod::BIDI_STREAMING, + new grpc::internal::UnknownMethodHandler)); sync_requests_.emplace_back( new SyncRequest(unknown_method_.get(), nullptr)); } @@ -746,24 +925,27 @@ class Server::SyncRequestThreadManager : public ThreadManager { private: Server* server_; - CompletionQueue* server_cq_; + grpc::CompletionQueue* server_cq_; int cq_timeout_msec_; std::vector> sync_requests_; - std::unique_ptr unknown_method_; + std::unique_ptr unknown_method_; std::shared_ptr global_callbacks_; }; -static internal::GrpcLibraryInitializer g_gli_initializer; +static grpc::internal::GrpcLibraryInitializer g_gli_initializer; Server::Server( - int max_receive_message_size, ChannelArguments* args, - std::shared_ptr>> + int max_receive_message_size, grpc::ChannelArguments* args, + std::shared_ptr>> sync_server_cqs, int min_pollers, int max_pollers, int sync_cq_timeout_msec, + std::vector> + acceptors, grpc_resource_quota* server_rq, std::vector< - std::unique_ptr> + std::unique_ptr> interceptor_creators) - : interceptor_creators_(std::move(interceptor_creators)), + : acceptors_(std::move(acceptors)), + interceptor_creators_(std::move(interceptor_creators)), max_receive_message_size_(max_receive_message_size), sync_server_cqs_(std::move(sync_server_cqs)), started_(false), @@ -773,8 +955,8 @@ Server::Server( server_initializer_(new grpc_impl::ServerInitializer(this)), health_check_service_disabled_(false) { g_gli_initializer.summon(); - gpr_once_init(&g_once_init_callbacks, InitGlobalCallbacks); - global_callbacks_ = g_callbacks; + gpr_once_init(&grpc::g_once_init_callbacks, grpc::InitGlobalCallbacks); + global_callbacks_ = grpc::g_callbacks; global_callbacks_->UpdateArguments(args); if (sync_server_cqs_ != nullptr) { @@ -797,17 +979,22 @@ Server::Server( } } + for (auto& acceptor : acceptors_) { + acceptor->SetToChannelArgs(args); + } + grpc_channel_args channel_args; args->SetChannelArgs(&channel_args); for (size_t i = 0; i < channel_args.num_args; i++) { - if (0 == - strcmp(channel_args.args[i].key, kHealthCheckServiceInterfaceArg)) { + if (0 == strcmp(channel_args.args[i].key, + grpc::kHealthCheckServiceInterfaceArg)) { if (channel_args.args[i].value.pointer.p == nullptr) { health_check_service_disabled_ = true; } else { - health_check_service_.reset(static_cast( - channel_args.args[i].value.pointer.p)); + health_check_service_.reset( + static_cast( + channel_args.args[i].value.pointer.p)); } break; } @@ -844,49 +1031,49 @@ Server::~Server() { } void Server::SetGlobalCallbacks(GlobalCallbacks* callbacks) { - GPR_ASSERT(!g_callbacks); + GPR_ASSERT(!grpc::g_callbacks); GPR_ASSERT(callbacks); - g_callbacks.reset(callbacks); + grpc::g_callbacks.reset(callbacks); } grpc_server* Server::c_server() { return server_; } -std::shared_ptr Server::InProcessChannel( - const ChannelArguments& args) { +std::shared_ptr Server::InProcessChannel( + const grpc::ChannelArguments& args) { grpc_channel_args channel_args = args.c_channel_args(); - return CreateChannelInternal( + return grpc::CreateChannelInternal( "inproc", grpc_inproc_channel_create(server_, &channel_args, nullptr), - std::vector< - std::unique_ptr>()); + std::vector>()); } -std::shared_ptr +std::shared_ptr Server::experimental_type::InProcessChannelWithInterceptors( - const ChannelArguments& args, + const grpc::ChannelArguments& args, std::vector< - std::unique_ptr> + std::unique_ptr> interceptor_creators) { grpc_channel_args channel_args = args.c_channel_args(); - return CreateChannelInternal( + return grpc::CreateChannelInternal( "inproc", grpc_inproc_channel_create(server_->server_, &channel_args, nullptr), std::move(interceptor_creators)); } static grpc_server_register_method_payload_handling PayloadHandlingForMethod( - internal::RpcServiceMethod* method) { + grpc::internal::RpcServiceMethod* method) { switch (method->method_type()) { - case internal::RpcMethod::NORMAL_RPC: - case internal::RpcMethod::SERVER_STREAMING: + case grpc::internal::RpcMethod::NORMAL_RPC: + case grpc::internal::RpcMethod::SERVER_STREAMING: return GRPC_SRM_PAYLOAD_READ_INITIAL_BYTE_BUFFER; - case internal::RpcMethod::CLIENT_STREAMING: - case internal::RpcMethod::BIDI_STREAMING: + case grpc::internal::RpcMethod::CLIENT_STREAMING: + case grpc::internal::RpcMethod::BIDI_STREAMING: return GRPC_SRM_PAYLOAD_NONE; } GPR_UNREACHABLE_CODE(return GRPC_SRM_PAYLOAD_NONE;); } -bool Server::RegisterService(const grpc::string* host, Service* service) { +bool Server::RegisterService(const grpc::string* host, grpc::Service* service) { bool has_async_methods = service->has_async_methods(); if (has_async_methods) { GPR_ASSERT(service->server_ == nullptr && @@ -902,7 +1089,7 @@ bool Server::RegisterService(const grpc::string* host, Service* service) { continue; } - internal::RpcServiceMethod* method = it->get(); + grpc::internal::RpcServiceMethod* method = it->get(); void* method_registration_tag = grpc_server_register_method( server_, method->name(), host ? host->c_str() : nullptr, PayloadHandlingForMethod(method), 0); @@ -915,7 +1102,7 @@ bool Server::RegisterService(const grpc::string* host, Service* service) { if (method->handler() == nullptr) { // Async method without handler method->set_server_tag(method_registration_tag); } else if (method->api_type() == - internal::RpcServiceMethod::ApiType::SYNC) { + grpc::internal::RpcServiceMethod::ApiType::SYNC) { for (auto it = sync_req_mgrs_.begin(); it != sync_req_mgrs_.end(); it++) { (*it)->AddSyncMethod(method, method_registration_tag); } @@ -925,8 +1112,9 @@ bool Server::RegisterService(const grpc::string* host, Service* service) { auto method_index = callback_unmatched_reqs_count_.size() - 1; // TODO(vjpai): Register these dynamically based on need for (int i = 0; i < DEFAULT_CALLBACK_REQS_PER_METHOD; i++) { - callback_reqs_to_start_.push_back(new CallbackRequest( - this, method_index, method, method_registration_tag)); + callback_reqs_to_start_.push_back( + new CallbackRequest(this, method_index, method, + method_registration_tag)); } // Enqueue it so that it will be Request'ed later after all request // matchers are created at core server startup @@ -947,7 +1135,7 @@ bool Server::RegisterService(const grpc::string* host, Service* service) { return true; } -void Server::RegisterAsyncGenericService(AsyncGenericService* service) { +void Server::RegisterAsyncGenericService(grpc::AsyncGenericService* service) { GPR_ASSERT(service->server_ == nullptr && "Can only register an async generic service against one server."); service->server_ = this; @@ -955,7 +1143,7 @@ void Server::RegisterAsyncGenericService(AsyncGenericService* service) { } void Server::RegisterCallbackGenericService( - experimental::CallbackGenericService* service) { + grpc::experimental::CallbackGenericService* service) { GPR_ASSERT( service->server_ == nullptr && "Can only register a callback generic service against one server."); @@ -967,52 +1155,58 @@ void Server::RegisterCallbackGenericService( auto method_index = callback_unmatched_reqs_count_.size() - 1; // TODO(vjpai): Register these dynamically based on need for (int i = 0; i < DEFAULT_CALLBACK_REQS_PER_METHOD; i++) { - callback_reqs_to_start_.push_back(new CallbackRequest( - this, method_index, nullptr, nullptr)); + callback_reqs_to_start_.push_back( + new CallbackRequest(this, method_index, + nullptr, nullptr)); } } int Server::AddListeningPort(const grpc::string& addr, - ServerCredentials* creds) { + grpc::ServerCredentials* creds) { GPR_ASSERT(!started_); int port = creds->AddPortToServer(addr, server_); global_callbacks_->AddPort(this, addr, creds, port); return port; } -void Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) { +void Server::Start(grpc::ServerCompletionQueue** cqs, size_t num_cqs) { GPR_ASSERT(!started_); global_callbacks_->PreServerStart(this); started_ = true; // Only create default health check service when user did not provide an // explicit one. - ServerCompletionQueue* health_check_cq = nullptr; - DefaultHealthCheckService::HealthCheckServiceImpl* + grpc::ServerCompletionQueue* health_check_cq = nullptr; + grpc::DefaultHealthCheckService::HealthCheckServiceImpl* default_health_check_service_impl = nullptr; if (health_check_service_ == nullptr && !health_check_service_disabled_ && - DefaultHealthCheckServiceEnabled()) { - auto* default_hc_service = new DefaultHealthCheckService; + grpc::DefaultHealthCheckServiceEnabled()) { + auto* default_hc_service = new grpc::DefaultHealthCheckService; health_check_service_.reset(default_hc_service); // We create a non-polling CQ to avoid impacting application // performance. This ensures that we don't introduce thread hops // for application requests that wind up on this CQ, which is polled // in its own thread. - health_check_cq = - new ServerCompletionQueue(GRPC_CQ_NEXT, GRPC_CQ_NON_POLLING, nullptr); + health_check_cq = new grpc::ServerCompletionQueue( + GRPC_CQ_NEXT, GRPC_CQ_NON_POLLING, nullptr); grpc_server_register_completion_queue(server_, health_check_cq->cq(), nullptr); default_health_check_service_impl = default_hc_service->GetHealthCheckService( - std::unique_ptr(health_check_cq)); + std::unique_ptr(health_check_cq)); RegisterService(nullptr, default_health_check_service_impl); } + for (auto& acceptor : acceptors_) { + acceptor->GetCredentials()->AddPortToServer(acceptor->name(), server_); + } + // If this server uses callback methods, then create a callback generic // service to handle any unimplemented methods using the default reactor // creator if (!callback_reqs_to_start_.empty() && !has_callback_generic_service_) { - unimplemented_service_.reset(new experimental::CallbackGenericService); + unimplemented_service_.reset( + new grpc::experimental::CallbackGenericService); RegisterCallbackGenericService(unimplemented_service_.get()); } @@ -1037,7 +1231,8 @@ void Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) { // server CQs), make sure that we have a ResourceExhausted handler // to deal with the case of thread exhaustion if (sync_server_cqs_ != nullptr && !sync_server_cqs_->empty()) { - resource_exhausted_handler_.reset(new internal::ResourceExhaustedHandler); + resource_exhausted_handler_.reset( + new grpc::internal::ResourceExhaustedHandler); } for (auto it = sync_req_mgrs_.begin(); it != sync_req_mgrs_.end(); it++) { @@ -1052,6 +1247,10 @@ void Server::Start(ServerCompletionQueue** cqs, size_t num_cqs) { if (default_health_check_service_impl != nullptr) { default_health_check_service_impl->StartServingThread(); } + + for (auto& acceptor : acceptors_) { + acceptor->Start(); + } } void Server::ShutdownInternal(gpr_timespec deadline) { @@ -1062,21 +1261,25 @@ void Server::ShutdownInternal(gpr_timespec deadline) { shutdown_ = true; + for (auto& acceptor : acceptors_) { + acceptor->Shutdown(); + } + /// The completion queue to use for server shutdown completion notification - CompletionQueue shutdown_cq; - ShutdownTag shutdown_tag; // Dummy shutdown tag + grpc::CompletionQueue shutdown_cq; + grpc::ShutdownTag shutdown_tag; // Dummy shutdown tag grpc_server_shutdown_and_notify(server_, shutdown_cq.cq(), &shutdown_tag); shutdown_cq.Shutdown(); void* tag; bool ok; - CompletionQueue::NextStatus status = + grpc::CompletionQueue::NextStatus status = shutdown_cq.AsyncNext(&tag, &ok, deadline); // If this timed out, it means we are done with the grace period for a clean // shutdown. We should force a shutdown now by cancelling all inflight calls - if (status == CompletionQueue::NextStatus::TIMEOUT) { + if (status == grpc::CompletionQueue::NextStatus::TIMEOUT) { grpc_server_cancel_all_calls(server_); } // Else in case of SHUTDOWN or GOT_EVENT, it means that the server has @@ -1128,154 +1331,11 @@ void Server::Wait() { } } -void Server::PerformOpsOnCall(internal::CallOpSetInterface* ops, - internal::Call* call) { +void Server::PerformOpsOnCall(grpc::internal::CallOpSetInterface* ops, + grpc::internal::Call* call) { ops->FillOps(call); } -ServerInterface::BaseAsyncRequest::BaseAsyncRequest( - ServerInterface* server, ServerContext* context, - internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag, bool delete_on_finalize) - : server_(server), - context_(context), - stream_(stream), - call_cq_(call_cq), - notification_cq_(notification_cq), - tag_(tag), - delete_on_finalize_(delete_on_finalize), - call_(nullptr), - done_intercepting_(false) { - /* Set up interception state partially for the receive ops. call_wrapper_ is - * not filled at this point, but it will be filled before the interceptors are - * run. */ - interceptor_methods_.SetCall(&call_wrapper_); - interceptor_methods_.SetReverse(); - call_cq_->RegisterAvalanching(); // This op will trigger more ops -} - -ServerInterface::BaseAsyncRequest::~BaseAsyncRequest() { - call_cq_->CompleteAvalanching(); -} - -bool ServerInterface::BaseAsyncRequest::FinalizeResult(void** tag, - bool* status) { - if (done_intercepting_) { - *tag = tag_; - if (delete_on_finalize_) { - delete this; - } - return true; - } - context_->set_call(call_); - context_->cq_ = call_cq_; - if (call_wrapper_.call() == nullptr) { - // Fill it since it is empty. - call_wrapper_ = internal::Call( - call_, server_, call_cq_, server_->max_receive_message_size(), nullptr); - } - - // just the pointers inside call are copied here - stream_->BindCall(&call_wrapper_); - - if (*status && call_ && call_wrapper_.server_rpc_info()) { - done_intercepting_ = true; - // Set interception point for RECV INITIAL METADATA - interceptor_methods_.AddInterceptionHookPoint( - experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA); - interceptor_methods_.SetRecvInitialMetadata(&context_->client_metadata_); - if (interceptor_methods_.RunInterceptors( - [this]() { ContinueFinalizeResultAfterInterception(); })) { - // There are no interceptors to run. Continue - } else { - // There were interceptors to be run, so - // ContinueFinalizeResultAfterInterception will be run when interceptors - // are done. - return false; - } - } - if (*status && call_) { - context_->BeginCompletionOp(&call_wrapper_, nullptr, nullptr); - } - *tag = tag_; - if (delete_on_finalize_) { - delete this; - } - return true; -} - -void ServerInterface::BaseAsyncRequest:: - ContinueFinalizeResultAfterInterception() { - context_->BeginCompletionOp(&call_wrapper_, nullptr, nullptr); - // Queue a tag which will be returned immediately - grpc_core::ExecCtx exec_ctx; - grpc_cq_begin_op(notification_cq_->cq(), this); - grpc_cq_end_op( - notification_cq_->cq(), this, GRPC_ERROR_NONE, - [](void* arg, grpc_cq_completion* completion) { delete completion; }, - nullptr, new grpc_cq_completion()); -} - -ServerInterface::RegisteredAsyncRequest::RegisteredAsyncRequest( - ServerInterface* server, ServerContext* context, - internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag, const char* name, - internal::RpcMethod::RpcType type) - : BaseAsyncRequest(server, context, stream, call_cq, notification_cq, tag, - true), - name_(name), - type_(type) {} - -void ServerInterface::RegisteredAsyncRequest::IssueRequest( - void* registered_method, grpc_byte_buffer** payload, - ServerCompletionQueue* notification_cq) { - GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_registered_call( - server_->server(), registered_method, &call_, - &context_->deadline_, - context_->client_metadata_.arr(), payload, - call_cq_->cq(), notification_cq->cq(), this)); -} - -ServerInterface::GenericAsyncRequest::GenericAsyncRequest( - ServerInterface* server, GenericServerContext* context, - internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, void* tag, bool delete_on_finalize) - : BaseAsyncRequest(server, context, stream, call_cq, notification_cq, tag, - delete_on_finalize) { - grpc_call_details_init(&call_details_); - GPR_ASSERT(notification_cq); - GPR_ASSERT(call_cq); - GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call( - server->server(), &call_, &call_details_, - context->client_metadata_.arr(), call_cq->cq(), - notification_cq->cq(), this)); -} - -bool ServerInterface::GenericAsyncRequest::FinalizeResult(void** tag, - bool* status) { - // If we are done intercepting, there is nothing more for us to do - if (done_intercepting_) { - return BaseAsyncRequest::FinalizeResult(tag, status); - } - // TODO(yangg) remove the copy here. - if (*status) { - static_cast(context_)->method_ = - StringFromCopiedSlice(call_details_.method); - static_cast(context_)->host_ = - StringFromCopiedSlice(call_details_.host); - context_->deadline_ = call_details_.deadline; - } - grpc_slice_unref(call_details_.method); - grpc_slice_unref(call_details_.host); - call_wrapper_ = internal::Call( - call_, server_, call_cq_, server_->max_receive_message_size(), - context_->set_server_rpc_info( - static_cast(context_)->method_.c_str(), - internal::RpcMethod::BIDI_STREAMING, - *server_->interceptor_creators())); - return BaseAsyncRequest::FinalizeResult(tag, status); -} - bool Server::UnimplementedAsyncRequest::FinalizeResult(void** tag, bool* status) { if (GenericAsyncRequest::FinalizeResult(tag, status)) { @@ -1295,41 +1355,22 @@ bool Server::UnimplementedAsyncRequest::FinalizeResult(void** tag, Server::UnimplementedAsyncResponse::UnimplementedAsyncResponse( UnimplementedAsyncRequest* request) : request_(request) { - Status status(StatusCode::UNIMPLEMENTED, ""); - internal::UnknownMethodHandler::FillOps(request_->context(), this); + grpc::Status status(grpc::StatusCode::UNIMPLEMENTED, ""); + grpc::internal::UnknownMethodHandler::FillOps(request_->context(), this); request_->stream()->call_.PerformOps(this); } -ServerInitializer* Server::initializer() { return server_initializer_.get(); } - -namespace { -class ShutdownCallback : public grpc_experimental_completion_queue_functor { - public: - ShutdownCallback() { functor_run = &ShutdownCallback::Run; } - // TakeCQ takes ownership of the cq into the shutdown callback - // so that the shutdown callback will be responsible for destroying it - void TakeCQ(CompletionQueue* cq) { cq_ = cq; } - - // The Run function will get invoked by the completion queue library - // when the shutdown is actually complete - static void Run(grpc_experimental_completion_queue_functor* cb, int) { - auto* callback = static_cast(cb); - delete callback->cq_; - delete callback; - } - - private: - CompletionQueue* cq_ = nullptr; -}; -} // namespace +grpc::ServerInitializer* Server::initializer() { + return server_initializer_.get(); +} -CompletionQueue* Server::CallbackCQ() { +grpc::CompletionQueue* Server::CallbackCQ() { // TODO(vjpai): Consider using a single global CQ for the default CQ // if there is no explicit per-server CQ registered grpc::internal::MutexLock l(&mu_); if (callback_cq_ == nullptr) { - auto* shutdown_callback = new ShutdownCallback; - callback_cq_ = new CompletionQueue(grpc_completion_queue_attributes{ + auto* shutdown_callback = new grpc::ShutdownCallback; + callback_cq_ = new grpc::CompletionQueue(grpc_completion_queue_attributes{ GRPC_CQ_CURRENT_VERSION, GRPC_CQ_CALLBACK, GRPC_CQ_DEFAULT_POLLING, shutdown_callback}); @@ -1339,4 +1380,4 @@ CompletionQueue* Server::CallbackCQ() { return callback_cq_; } -} // namespace grpc +} // namespace grpc_impl diff --git a/src/csharp/Grpc.Core.Api/DeserializationContext.cs b/src/csharp/Grpc.Core.Api/DeserializationContext.cs index d69e0db5bdf..966bcfa8c8e 100644 --- a/src/csharp/Grpc.Core.Api/DeserializationContext.cs +++ b/src/csharp/Grpc.Core.Api/DeserializationContext.cs @@ -39,7 +39,7 @@ namespace Grpc.Core /// Also, allocating a new buffer each time can put excessive pressure on GC, especially if /// the payload is more than 86700 bytes large (which means the newly allocated buffer will be placed in LOH, /// and LOH object can only be garbage collected via a full ("stop the world") GC run). - /// NOTE: Deserializers are expected not to call this method more than once per received message + /// NOTE: Deserializers are expected not to call this method (or other payload accessor methods) more than once per received message /// (as there is no practical reason for doing so) and DeserializationContext implementations are free to assume so. /// /// byte array containing the entire payload. @@ -47,5 +47,22 @@ namespace Grpc.Core { throw new NotImplementedException(); } + +#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY + /// + /// Gets the entire payload as a ReadOnlySequence. + /// The ReadOnlySequence is only valid for the duration of the deserializer routine and the caller must not access it after the deserializer returns. + /// Using the read only sequence is the most efficient way to access the message payload. Where possible it allows directly + /// accessing the received payload without needing to perform any buffer copying or buffer allocations. + /// NOTE: This method is only available in the netstandard2.0 build of the library. + /// NOTE: Deserializers are expected not to call this method (or other payload accessor methods) more than once per received message + /// (as there is no practical reason for doing so) and DeserializationContext implementations are free to assume so. + /// + /// read only sequence containing the entire payload. + public virtual System.Buffers.ReadOnlySequence PayloadAsReadOnlySequence() + { + throw new NotImplementedException(); + } +#endif } } diff --git a/src/csharp/Grpc.Core.Api/Grpc.Core.Api.csproj b/src/csharp/Grpc.Core.Api/Grpc.Core.Api.csproj index 6c29530402c..8a32bc757df 100755 --- a/src/csharp/Grpc.Core.Api/Grpc.Core.Api.csproj +++ b/src/csharp/Grpc.Core.Api/Grpc.Core.Api.csproj @@ -19,12 +19,20 @@ true + + $(DefineConstants);GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY + + + + + + diff --git a/src/csharp/Grpc.Core/Interceptors/ClientInterceptorContext.cs b/src/csharp/Grpc.Core.Api/Interceptors/ClientInterceptorContext.cs similarity index 100% rename from src/csharp/Grpc.Core/Interceptors/ClientInterceptorContext.cs rename to src/csharp/Grpc.Core.Api/Interceptors/ClientInterceptorContext.cs diff --git a/src/csharp/Grpc.Core/Interceptors/Interceptor.cs b/src/csharp/Grpc.Core.Api/Interceptors/Interceptor.cs similarity index 100% rename from src/csharp/Grpc.Core/Interceptors/Interceptor.cs rename to src/csharp/Grpc.Core.Api/Interceptors/Interceptor.cs diff --git a/src/csharp/Grpc.Core.Api/StatusCode.cs b/src/csharp/Grpc.Core.Api/StatusCode.cs index 57fe538e815..8493f375adb 100644 --- a/src/csharp/Grpc.Core.Api/StatusCode.cs +++ b/src/csharp/Grpc.Core.Api/StatusCode.cs @@ -114,7 +114,8 @@ namespace Grpc.Core /// /// The service is currently unavailable. This is a most likely a /// transient condition and may be corrected by retrying with - /// a backoff. + /// a backoff. Note that it is not always safe to retry + /// non-idempotent operations. /// Unavailable = 14, diff --git a/src/csharp/Grpc.Core.Api/VersionInfo.cs b/src/csharp/Grpc.Core.Api/VersionInfo.cs index 1b2602e219d..fb67fe622b5 100644 --- a/src/csharp/Grpc.Core.Api/VersionInfo.cs +++ b/src/csharp/Grpc.Core.Api/VersionInfo.cs @@ -33,11 +33,11 @@ namespace Grpc.Core /// /// Current AssemblyFileVersion of gRPC C# assemblies /// - public const string CurrentAssemblyFileVersion = "1.21.0.0"; + public const string CurrentAssemblyFileVersion = "1.22.0.0"; /// /// Current version of gRPC C# /// - public const string CurrentVersion = "1.21.0-dev"; + public const string CurrentVersion = "1.22.0-dev"; } } diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj index 23e5d7f65ef..7fef2c77091 100755 --- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj +++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj @@ -8,6 +8,10 @@ true + + $(DefineConstants);GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY + + diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs index 5c7d48f786c..fd221613c04 100644 --- a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs +++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs @@ -35,6 +35,7 @@ namespace Grpc.Core.Internal.Tests Server server; FakeNativeCall fakeCall; AsyncCallServer asyncCallServer; + FakeBufferReaderManager fakeBufferReaderManager; [SetUp] public void Init() @@ -52,11 +53,13 @@ namespace Grpc.Core.Internal.Tests Marshallers.StringMarshaller.ContextualSerializer, Marshallers.StringMarshaller.ContextualDeserializer, server); asyncCallServer.InitializeForTesting(fakeCall); + fakeBufferReaderManager = new FakeBufferReaderManager(); } [TearDown] public void Cleanup() { + fakeBufferReaderManager.Dispose(); server.ShutdownAsync().Wait(); } @@ -77,7 +80,7 @@ namespace Grpc.Core.Internal.Tests var moveNextTask = requestStream.MoveNext(); fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true); - fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null); + fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse()); Assert.IsFalse(moveNextTask.Result); AssertFinished(asyncCallServer, fakeCall, finishedTask); @@ -107,7 +110,7 @@ namespace Grpc.Core.Internal.Tests // if a read completion's success==false, the request stream will silently finish // and we rely on C core cancelling the call. var moveNextTask = requestStream.MoveNext(); - fakeCall.ReceivedMessageCallback.OnReceivedMessage(false, null); + fakeCall.ReceivedMessageCallback.OnReceivedMessage(false, CreateNullResponse()); Assert.IsFalse(moveNextTask.Result); fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true); @@ -182,5 +185,10 @@ namespace Grpc.Core.Internal.Tests Assert.IsTrue(finishedTask.IsCompleted); Assert.DoesNotThrow(() => finishedTask.Wait()); } + + IBufferReader CreateNullResponse() + { + return fakeBufferReaderManager.CreateNullPayloadBufferReader(); + } } } diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs index 775849d89b6..78c7f3ad5bb 100644 --- a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs +++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs @@ -21,6 +21,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Grpc.Core.Internal; +using Grpc.Core.Utils; using NUnit.Framework; namespace Grpc.Core.Internal.Tests @@ -33,6 +34,7 @@ namespace Grpc.Core.Internal.Tests Channel channel; FakeNativeCall fakeCall; AsyncCall asyncCall; + FakeBufferReaderManager fakeBufferReaderManager; [SetUp] public void Init() @@ -43,12 +45,14 @@ namespace Grpc.Core.Internal.Tests var callDetails = new CallInvocationDetails(channel, "someMethod", null, Marshallers.StringMarshaller, Marshallers.StringMarshaller, new CallOptions()); asyncCall = new AsyncCall(callDetails, fakeCall); + fakeBufferReaderManager = new FakeBufferReaderManager(); } [TearDown] public void Cleanup() { channel.ShutdownAsync().Wait(); + fakeBufferReaderManager.Dispose(); } [Test] @@ -87,7 +91,7 @@ namespace Grpc.Core.Internal.Tests var resultTask = asyncCall.UnaryCallAsync("request1"); fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true, CreateClientSideStatus(StatusCode.InvalidArgument), - null, + CreateNullResponse(), new Metadata()); AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.InvalidArgument); @@ -168,7 +172,7 @@ namespace Grpc.Core.Internal.Tests var resultTask = asyncCall.ClientStreamingCallAsync(); fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true, CreateClientSideStatus(StatusCode.InvalidArgument), - null, + CreateNullResponse(), new Metadata()); AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.InvalidArgument); @@ -214,7 +218,7 @@ namespace Grpc.Core.Internal.Tests fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true, CreateClientSideStatus(StatusCode.Internal), - null, + CreateNullResponse(), new Metadata()); var ex = Assert.ThrowsAsync(async () => await writeTask); @@ -233,7 +237,7 @@ namespace Grpc.Core.Internal.Tests fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true, CreateClientSideStatus(StatusCode.Internal), - null, + CreateNullResponse(), new Metadata()); fakeCall.SendCompletionCallback.OnSendCompletion(false); @@ -259,7 +263,7 @@ namespace Grpc.Core.Internal.Tests fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true, CreateClientSideStatus(StatusCode.Internal), - null, + CreateNullResponse(), new Metadata()); var ex = Assert.ThrowsAsync(async () => await writeTask); @@ -357,7 +361,7 @@ namespace Grpc.Core.Internal.Tests fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true, CreateClientSideStatus(StatusCode.Cancelled), - null, + CreateNullResponse(), new Metadata()); AssertUnaryResponseError(asyncCall, fakeCall, resultTask, StatusCode.Cancelled); @@ -390,7 +394,7 @@ namespace Grpc.Core.Internal.Tests fakeCall.ReceivedResponseHeadersCallback.OnReceivedResponseHeaders(true, new Metadata()); Assert.AreEqual(0, asyncCall.ResponseHeadersAsync.Result.Count); - fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null); + fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse()); fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata())); AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask); @@ -405,7 +409,7 @@ namespace Grpc.Core.Internal.Tests // try alternative order of completions fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata())); - fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null); + fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse()); AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask); } @@ -417,7 +421,7 @@ namespace Grpc.Core.Internal.Tests var responseStream = new ClientResponseStream(asyncCall); var readTask = responseStream.MoveNext(); - fakeCall.ReceivedMessageCallback.OnReceivedMessage(false, null); // after a failed read, we rely on C core to deliver appropriate status code. + fakeCall.ReceivedMessageCallback.OnReceivedMessage(false, CreateNullResponse()); // after a failed read, we rely on C core to deliver appropriate status code. fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.Internal)); AssertStreamingResponseError(asyncCall, fakeCall, readTask, StatusCode.Internal); @@ -441,7 +445,7 @@ namespace Grpc.Core.Internal.Tests var readTask3 = responseStream.MoveNext(); fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata())); - fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null); + fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse()); AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask3); } @@ -479,7 +483,7 @@ namespace Grpc.Core.Internal.Tests Assert.DoesNotThrowAsync(async () => await writeTask1); var readTask = responseStream.MoveNext(); - fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null); + fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse()); fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata())); AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask); @@ -493,7 +497,7 @@ namespace Grpc.Core.Internal.Tests var responseStream = new ClientResponseStream(asyncCall); var readTask = responseStream.MoveNext(); - fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null); + fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse()); fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata())); AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask); @@ -511,7 +515,7 @@ namespace Grpc.Core.Internal.Tests var responseStream = new ClientResponseStream(asyncCall); var readTask = responseStream.MoveNext(); - fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null); + fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse()); fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata())); AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask); @@ -533,7 +537,7 @@ namespace Grpc.Core.Internal.Tests Assert.IsFalse(writeTask.IsCompleted); var readTask = responseStream.MoveNext(); - fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null); + fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse()); fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.PermissionDenied)); var ex = Assert.ThrowsAsync(async () => await writeTask); @@ -552,7 +556,7 @@ namespace Grpc.Core.Internal.Tests var writeTask = requestStream.WriteAsync("request1"); var readTask = responseStream.MoveNext(); - fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null); + fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse()); fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.PermissionDenied)); fakeCall.SendCompletionCallback.OnSendCompletion(false); @@ -576,7 +580,7 @@ namespace Grpc.Core.Internal.Tests Assert.ThrowsAsync(typeof(TaskCanceledException), async () => await writeTask); var readTask = responseStream.MoveNext(); - fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null); + fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse()); fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.Cancelled)); AssertStreamingResponseError(asyncCall, fakeCall, readTask, StatusCode.Cancelled); @@ -597,7 +601,7 @@ namespace Grpc.Core.Internal.Tests Assert.AreEqual("response1", responseStream.Current); var readTask2 = responseStream.MoveNext(); - fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null); + fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse()); fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.Cancelled)); AssertStreamingResponseError(asyncCall, fakeCall, readTask2, StatusCode.Cancelled); @@ -618,7 +622,7 @@ namespace Grpc.Core.Internal.Tests Assert.AreEqual("response1", responseStream.Current); var readTask2 = responseStream.MoveNext(); - fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null); + fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateNullResponse()); fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.Cancelled)); AssertStreamingResponseError(asyncCall, fakeCall, readTask2, StatusCode.Cancelled); @@ -638,9 +642,14 @@ namespace Grpc.Core.Internal.Tests return new ClientSideStatus(new Status(statusCode, ""), new Metadata()); } - byte[] CreateResponsePayload() + IBufferReader CreateResponsePayload() + { + return fakeBufferReaderManager.CreateSingleSegmentBufferReader(Marshallers.StringMarshaller.Serializer("response1")); + } + + IBufferReader CreateNullResponse() { - return Marshallers.StringMarshaller.Serializer("response1"); + return fakeBufferReaderManager.CreateNullPayloadBufferReader(); } static void AssertUnaryResponseSuccess(AsyncCall asyncCall, FakeNativeCall fakeCall, Task resultTask) diff --git a/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs b/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs index 7e4e2975c16..a0ea1cc4278 100644 --- a/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs +++ b/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs @@ -47,7 +47,6 @@ namespace Grpc.Core.Internal.Tests GrpcEnvironment.ReleaseAsync().Wait(); Assert.AreEqual(CompletionQueueEvent.CompletionType.Shutdown, ev.type); Assert.AreNotEqual(IntPtr.Zero, ev.success); - Assert.AreEqual(IntPtr.Zero, ev.tag); } } } diff --git a/src/csharp/Grpc.Core.Tests/Internal/DefaultDeserializationContextTest.cs b/src/csharp/Grpc.Core.Tests/Internal/DefaultDeserializationContextTest.cs new file mode 100644 index 00000000000..63baab31624 --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/Internal/DefaultDeserializationContextTest.cs @@ -0,0 +1,240 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// 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. + +#endregion + +using System; +using System.Collections.Generic; +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Utils; +using NUnit.Framework; + +using System.Runtime.InteropServices; + +#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY +using System.Buffers; +#endif + +namespace Grpc.Core.Internal.Tests +{ + public class DefaultDeserializationContextTest + { + FakeBufferReaderManager fakeBufferReaderManager; + + [SetUp] + public void Init() + { + fakeBufferReaderManager = new FakeBufferReaderManager(); + } + + [TearDown] + public void Cleanup() + { + fakeBufferReaderManager.Dispose(); + } + +#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY + [TestCase] + public void PayloadAsReadOnlySequence_ZeroSegmentPayload() + { + var context = new DefaultDeserializationContext(); + context.Initialize(fakeBufferReaderManager.CreateMultiSegmentBufferReader(new List {})); + + Assert.AreEqual(0, context.PayloadLength); + + var sequence = context.PayloadAsReadOnlySequence(); + + Assert.AreEqual(ReadOnlySequence.Empty, sequence); + Assert.IsTrue(sequence.IsEmpty); + Assert.IsTrue(sequence.IsSingleSegment); + } + + [TestCase(0)] + [TestCase(1)] + [TestCase(10)] + [TestCase(100)] + [TestCase(1000)] + public void PayloadAsReadOnlySequence_SingleSegmentPayload(int segmentLength) + { + var origBuffer = GetTestBuffer(segmentLength); + var context = new DefaultDeserializationContext(); + context.Initialize(fakeBufferReaderManager.CreateSingleSegmentBufferReader(origBuffer)); + + Assert.AreEqual(origBuffer.Length, context.PayloadLength); + + var sequence = context.PayloadAsReadOnlySequence(); + + Assert.AreEqual(origBuffer.Length, sequence.Length); + Assert.AreEqual(origBuffer.Length, sequence.First.Length); + Assert.IsTrue(sequence.IsSingleSegment); + CollectionAssert.AreEqual(origBuffer, sequence.First.ToArray()); + } + + [TestCase(0, 5, 10)] + [TestCase(1, 1, 1)] + [TestCase(10, 100, 1000)] + [TestCase(100, 100, 10)] + [TestCase(1000, 1000, 1000)] + public void PayloadAsReadOnlySequence_MultiSegmentPayload(int segmentLen1, int segmentLen2, int segmentLen3) + { + var origBuffer1 = GetTestBuffer(segmentLen1); + var origBuffer2 = GetTestBuffer(segmentLen2); + var origBuffer3 = GetTestBuffer(segmentLen3); + int totalLen = origBuffer1.Length + origBuffer2.Length + origBuffer3.Length; + + var context = new DefaultDeserializationContext(); + context.Initialize(fakeBufferReaderManager.CreateMultiSegmentBufferReader(new List { origBuffer1, origBuffer2, origBuffer3 })); + + Assert.AreEqual(totalLen, context.PayloadLength); + + var sequence = context.PayloadAsReadOnlySequence(); + + Assert.AreEqual(totalLen, sequence.Length); + + var segmentEnumerator = sequence.GetEnumerator(); + + Assert.IsTrue(segmentEnumerator.MoveNext()); + CollectionAssert.AreEqual(origBuffer1, segmentEnumerator.Current.ToArray()); + + Assert.IsTrue(segmentEnumerator.MoveNext()); + CollectionAssert.AreEqual(origBuffer2, segmentEnumerator.Current.ToArray()); + + Assert.IsTrue(segmentEnumerator.MoveNext()); + CollectionAssert.AreEqual(origBuffer3, segmentEnumerator.Current.ToArray()); + + Assert.IsFalse(segmentEnumerator.MoveNext()); + } +#endif + + [TestCase] + public void NullPayloadNotAllowed() + { + var context = new DefaultDeserializationContext(); + Assert.Throws(typeof(InvalidOperationException), () => context.Initialize(fakeBufferReaderManager.CreateNullPayloadBufferReader())); + } + + [TestCase] + public void PayloadAsNewByteBuffer_ZeroSegmentPayload() + { + var context = new DefaultDeserializationContext(); + context.Initialize(fakeBufferReaderManager.CreateMultiSegmentBufferReader(new List {})); + + Assert.AreEqual(0, context.PayloadLength); + + var payload = context.PayloadAsNewBuffer(); + Assert.AreEqual(0, payload.Length); + } + + [TestCase(0)] + [TestCase(1)] + [TestCase(10)] + [TestCase(100)] + [TestCase(1000)] + public void PayloadAsNewByteBuffer_SingleSegmentPayload(int segmentLength) + { + var origBuffer = GetTestBuffer(segmentLength); + var context = new DefaultDeserializationContext(); + context.Initialize(fakeBufferReaderManager.CreateSingleSegmentBufferReader(origBuffer)); + + Assert.AreEqual(origBuffer.Length, context.PayloadLength); + + var payload = context.PayloadAsNewBuffer(); + CollectionAssert.AreEqual(origBuffer, payload); + } + + [TestCase(0, 5, 10)] + [TestCase(1, 1, 1)] + [TestCase(10, 100, 1000)] + [TestCase(100, 100, 10)] + [TestCase(1000, 1000, 1000)] + public void PayloadAsNewByteBuffer_MultiSegmentPayload(int segmentLen1, int segmentLen2, int segmentLen3) + { + var origBuffer1 = GetTestBuffer(segmentLen1); + var origBuffer2 = GetTestBuffer(segmentLen2); + var origBuffer3 = GetTestBuffer(segmentLen3); + + var context = new DefaultDeserializationContext(); + context.Initialize(fakeBufferReaderManager.CreateMultiSegmentBufferReader(new List { origBuffer1, origBuffer2, origBuffer3 })); + + var payload = context.PayloadAsNewBuffer(); + + var concatenatedOrigBuffers = new List(); + concatenatedOrigBuffers.AddRange(origBuffer1); + concatenatedOrigBuffers.AddRange(origBuffer2); + concatenatedOrigBuffers.AddRange(origBuffer3); + + Assert.AreEqual(concatenatedOrigBuffers.Count, context.PayloadLength); + Assert.AreEqual(concatenatedOrigBuffers.Count, payload.Length); + CollectionAssert.AreEqual(concatenatedOrigBuffers, payload); + } + + [TestCase] + public void GetPayloadMultipleTimesIsIllegal() + { + var origBuffer = GetTestBuffer(100); + var context = new DefaultDeserializationContext(); + context.Initialize(fakeBufferReaderManager.CreateSingleSegmentBufferReader(origBuffer)); + + Assert.AreEqual(origBuffer.Length, context.PayloadLength); + + var payload = context.PayloadAsNewBuffer(); + CollectionAssert.AreEqual(origBuffer, payload); + + // Getting payload multiple times is illegal + Assert.Throws(typeof(InvalidOperationException), () => context.PayloadAsNewBuffer()); +#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY + Assert.Throws(typeof(InvalidOperationException), () => context.PayloadAsReadOnlySequence()); +#endif + } + + [TestCase] + public void ResetContextAndReinitialize() + { + var origBuffer = GetTestBuffer(100); + var context = new DefaultDeserializationContext(); + context.Initialize(fakeBufferReaderManager.CreateSingleSegmentBufferReader(origBuffer)); + + Assert.AreEqual(origBuffer.Length, context.PayloadLength); + + // Reset invalidates context + context.Reset(); + + Assert.AreEqual(0, context.PayloadLength); + Assert.Throws(typeof(NullReferenceException), () => context.PayloadAsNewBuffer()); +#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY + Assert.Throws(typeof(NullReferenceException), () => context.PayloadAsReadOnlySequence()); +#endif + + // Previously reset context can be initialized again + var origBuffer2 = GetTestBuffer(50); + context.Initialize(fakeBufferReaderManager.CreateSingleSegmentBufferReader(origBuffer2)); + + Assert.AreEqual(origBuffer2.Length, context.PayloadLength); + CollectionAssert.AreEqual(origBuffer2, context.PayloadAsNewBuffer()); + } + + private byte[] GetTestBuffer(int length) + { + var testBuffer = new byte[length]; + for (int i = 0; i < testBuffer.Length; i++) + { + testBuffer[i] = (byte) i; + } + return testBuffer; + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/Internal/FakeBufferReaderManager.cs b/src/csharp/Grpc.Core.Tests/Internal/FakeBufferReaderManager.cs new file mode 100644 index 00000000000..d8d0c0a6354 --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/Internal/FakeBufferReaderManager.cs @@ -0,0 +1,118 @@ +#region Copyright notice and license + +// Copyright 2018 The gRPC Authors +// +// 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. + +#endregion + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Threading.Tasks; + +using Grpc.Core.Internal; +using Grpc.Core.Utils; + +namespace Grpc.Core.Internal.Tests +{ + // Creates instances of fake IBufferReader. All created instances will become invalid once Dispose is called. + internal class FakeBufferReaderManager : IDisposable + { + List pinnedHandles = new List(); + bool disposed = false; + public IBufferReader CreateSingleSegmentBufferReader(byte[] data) + { + return CreateMultiSegmentBufferReader(new List { data }); + } + + public IBufferReader CreateMultiSegmentBufferReader(IEnumerable dataSegments) + { + GrpcPreconditions.CheckState(!disposed); + GrpcPreconditions.CheckNotNull(dataSegments); + var segments = new List(); + foreach (var data in dataSegments) + { + GrpcPreconditions.CheckNotNull(data); + segments.Add(GCHandle.Alloc(data, GCHandleType.Pinned)); + } + pinnedHandles.AddRange(segments); // all the allocated GCHandles will be freed on Dispose() + return new FakeBufferReader(segments); + } + + public IBufferReader CreateNullPayloadBufferReader() + { + GrpcPreconditions.CheckState(!disposed); + return new FakeBufferReader(null); + } + + public void Dispose() + { + if (!disposed) + { + disposed = true; + for (int i = 0; i < pinnedHandles.Count; i++) + { + pinnedHandles[i].Free(); + } + } + } + + private class FakeBufferReader : IBufferReader + { + readonly List bufferSegments; + readonly int? totalLength; + readonly IEnumerator segmentEnumerator; + + public FakeBufferReader(List bufferSegments) + { + this.bufferSegments = bufferSegments; + this.totalLength = ComputeTotalLength(bufferSegments); + this.segmentEnumerator = bufferSegments?.GetEnumerator(); + } + + public int? TotalLength => totalLength; + + public bool TryGetNextSlice(out Slice slice) + { + GrpcPreconditions.CheckNotNull(bufferSegments); + if (!segmentEnumerator.MoveNext()) + { + slice = default(Slice); + return false; + } + + var segment = segmentEnumerator.Current; + int sliceLen = ((byte[]) segment.Target).Length; + slice = new Slice(segment.AddrOfPinnedObject(), sliceLen); + return true; + } + + static int? ComputeTotalLength(List bufferSegments) + { + if (bufferSegments == null) + { + return null; + } + + int sum = 0; + foreach (var segment in bufferSegments) + { + var data = (byte[]) segment.Target; + sum += data.Length; + } + return sum; + } + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/Internal/FakeBufferReaderManagerTest.cs b/src/csharp/Grpc.Core.Tests/Internal/FakeBufferReaderManagerTest.cs new file mode 100644 index 00000000000..7c4ff652bd3 --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/Internal/FakeBufferReaderManagerTest.cs @@ -0,0 +1,121 @@ +#region Copyright notice and license + +// Copyright 2018 The gRPC Authors +// +// 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. + +#endregion + +using System; +using System.Collections.Generic; +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Utils; +using NUnit.Framework; + +namespace Grpc.Core.Internal.Tests +{ + public class FakeBufferReaderManagerTest + { + FakeBufferReaderManager fakeBufferReaderManager; + + [SetUp] + public void Init() + { + fakeBufferReaderManager = new FakeBufferReaderManager(); + } + + [TearDown] + public void Cleanup() + { + fakeBufferReaderManager.Dispose(); + } + + [TestCase] + public void NullPayload() + { + var fakeBufferReader = fakeBufferReaderManager.CreateNullPayloadBufferReader(); + Assert.IsFalse(fakeBufferReader.TotalLength.HasValue); + Assert.Throws(typeof(ArgumentNullException), () => fakeBufferReader.TryGetNextSlice(out Slice slice)); + } + [TestCase] + public void ZeroSegmentPayload() + { + var fakeBufferReader = fakeBufferReaderManager.CreateMultiSegmentBufferReader(new List {}); + Assert.AreEqual(0, fakeBufferReader.TotalLength.Value); + Assert.IsFalse(fakeBufferReader.TryGetNextSlice(out Slice slice)); + } + + [TestCase(0)] + [TestCase(1)] + [TestCase(10)] + [TestCase(30)] + [TestCase(100)] + [TestCase(1000)] + public void SingleSegmentPayload(int bufferLen) + { + var origBuffer = GetTestBuffer(bufferLen); + var fakeBufferReader = fakeBufferReaderManager.CreateSingleSegmentBufferReader(origBuffer); + Assert.AreEqual(origBuffer.Length, fakeBufferReader.TotalLength.Value); + + Assert.IsTrue(fakeBufferReader.TryGetNextSlice(out Slice slice)); + AssertSliceDataEqual(origBuffer, slice); + + Assert.IsFalse(fakeBufferReader.TryGetNextSlice(out Slice slice2)); + } + + [TestCase(0, 5, 10)] + [TestCase(1, 1, 1)] + [TestCase(10, 100, 1000)] + [TestCase(100, 100, 10)] + [TestCase(1000, 1000, 1000)] + public void MultiSegmentPayload(int segmentLen1, int segmentLen2, int segmentLen3) + { + var origBuffer1 = GetTestBuffer(segmentLen1); + var origBuffer2 = GetTestBuffer(segmentLen2); + var origBuffer3 = GetTestBuffer(segmentLen3); + var fakeBufferReader = fakeBufferReaderManager.CreateMultiSegmentBufferReader(new List { origBuffer1, origBuffer2, origBuffer3 }); + + Assert.AreEqual(origBuffer1.Length + origBuffer2.Length + origBuffer3.Length, fakeBufferReader.TotalLength.Value); + + Assert.IsTrue(fakeBufferReader.TryGetNextSlice(out Slice slice1)); + AssertSliceDataEqual(origBuffer1, slice1); + + Assert.IsTrue(fakeBufferReader.TryGetNextSlice(out Slice slice2)); + AssertSliceDataEqual(origBuffer2, slice2); + + Assert.IsTrue(fakeBufferReader.TryGetNextSlice(out Slice slice3)); + AssertSliceDataEqual(origBuffer3, slice3); + + Assert.IsFalse(fakeBufferReader.TryGetNextSlice(out Slice slice4)); + } + + private void AssertSliceDataEqual(byte[] expected, Slice actual) + { + var actualSliceData = new byte[actual.Length]; + actual.CopyTo(new ArraySegment(actualSliceData)); + CollectionAssert.AreEqual(expected, actualSliceData); + } + + // create a buffer of given size and fill it with some data + private byte[] GetTestBuffer(int length) + { + var testBuffer = new byte[length]; + for (int i = 0; i < testBuffer.Length; i++) + { + testBuffer[i] = (byte) i; + } + return testBuffer; + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/Internal/ReusableSliceBufferTest.cs b/src/csharp/Grpc.Core.Tests/Internal/ReusableSliceBufferTest.cs new file mode 100644 index 00000000000..7630785aef4 --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/Internal/ReusableSliceBufferTest.cs @@ -0,0 +1,151 @@ +#region Copyright notice and license + +// Copyright 2018 The gRPC Authors +// +// 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. + +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Utils; +using NUnit.Framework; + +using System.Runtime.InteropServices; + +#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY +using System.Buffers; +#endif + +namespace Grpc.Core.Internal.Tests +{ + // Converts IBufferReader into instances of ReadOnlySequence + // Objects representing the sequence segments are cached to decrease GC load. + public class ReusableSliceBufferTest + { + FakeBufferReaderManager fakeBufferReaderManager; + + [SetUp] + public void Init() + { + fakeBufferReaderManager = new FakeBufferReaderManager(); + } + + [TearDown] + public void Cleanup() + { + fakeBufferReaderManager.Dispose(); + } + +#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY + [TestCase] + public void NullPayload() + { + var sliceBuffer = new ReusableSliceBuffer(); + Assert.Throws(typeof(ArgumentNullException), () => sliceBuffer.PopulateFrom(fakeBufferReaderManager.CreateNullPayloadBufferReader())); + } + + [TestCase] + public void ZeroSegmentPayload() + { + var sliceBuffer = new ReusableSliceBuffer(); + var sequence = sliceBuffer.PopulateFrom(fakeBufferReaderManager.CreateMultiSegmentBufferReader(new List {})); + + Assert.AreEqual(ReadOnlySequence.Empty, sequence); + Assert.IsTrue(sequence.IsEmpty); + Assert.IsTrue(sequence.IsSingleSegment); + } + + [TestCase] + public void SegmentsAreCached() + { + var bufferSegments1 = Enumerable.Range(0, 100).Select((_) => GetTestBuffer(50)).ToList(); + var bufferSegments2 = Enumerable.Range(0, 100).Select((_) => GetTestBuffer(50)).ToList(); + + var sliceBuffer = new ReusableSliceBuffer(); + + var sequence1 = sliceBuffer.PopulateFrom(fakeBufferReaderManager.CreateMultiSegmentBufferReader(bufferSegments1)); + var memoryManagers1 = GetMemoryManagersForSequenceSegments(sequence1); + + sliceBuffer.Invalidate(); + + var sequence2 = sliceBuffer.PopulateFrom(fakeBufferReaderManager.CreateMultiSegmentBufferReader(bufferSegments2)); + var memoryManagers2 = GetMemoryManagersForSequenceSegments(sequence2); + + // check memory managers are identical objects (i.e. they've been reused) + CollectionAssert.AreEquivalent(memoryManagers1, memoryManagers2); + } + + [TestCase] + public void MultiSegmentPayload_LotsOfSegments() + { + var bufferSegments = Enumerable.Range(0, ReusableSliceBuffer.MaxCachedSegments + 100).Select((_) => GetTestBuffer(10)).ToList(); + + var sliceBuffer = new ReusableSliceBuffer(); + var sequence = sliceBuffer.PopulateFrom(fakeBufferReaderManager.CreateMultiSegmentBufferReader(bufferSegments)); + + int index = 0; + foreach (var memory in sequence) + { + CollectionAssert.AreEqual(bufferSegments[index], memory.ToArray()); + index ++; + } + } + + [TestCase] + public void InvalidateMakesSequenceUnusable() + { + var origBuffer = GetTestBuffer(100); + + var sliceBuffer = new ReusableSliceBuffer(); + var sequence = sliceBuffer.PopulateFrom(fakeBufferReaderManager.CreateMultiSegmentBufferReader(new List { origBuffer })); + + Assert.AreEqual(origBuffer.Length, sequence.Length); + + sliceBuffer.Invalidate(); + + // Invalidate with make the returned sequence completely unusable and broken, users must not use it beyond the deserializer functions. + Assert.Throws(typeof(ArgumentOutOfRangeException), () => { var first = sequence.First; }); + } + + private List> GetMemoryManagersForSequenceSegments(ReadOnlySequence sequence) + { + var result = new List>(); + foreach (var memory in sequence) + { + Assert.IsTrue(MemoryMarshal.TryGetMemoryManager(memory, out MemoryManager memoryManager)); + result.Add(memoryManager); + } + return result; + } +#else + [TestCase] + public void OnlySupportedOnNetCore() + { + // Test case needs to exist to make C# sanity test happy. + } +#endif + private byte[] GetTestBuffer(int length) + { + var testBuffer = new byte[length]; + for (int i = 0; i < testBuffer.Length; i++) + { + testBuffer[i] = (byte) i; + } + return testBuffer; + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/Internal/SliceTest.cs b/src/csharp/Grpc.Core.Tests/Internal/SliceTest.cs new file mode 100644 index 00000000000..eb090bbfa50 --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/Internal/SliceTest.cs @@ -0,0 +1,83 @@ +#region Copyright notice and license + +// Copyright 2018 The gRPC Authors +// +// 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. + +#endregion + +using System; +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Utils; +using NUnit.Framework; + +using System.Runtime.InteropServices; + +namespace Grpc.Core.Internal.Tests +{ + public class SliceTest + { + [TestCase(0)] + [TestCase(1)] + [TestCase(10)] + [TestCase(100)] + [TestCase(1000)] + public void SliceFromNativePtr_CopyToArraySegment(int bufferLength) + { + var origBuffer = GetTestBuffer(bufferLength); + var gcHandle = GCHandle.Alloc(origBuffer, GCHandleType.Pinned); + try + { + var slice = new Slice(gcHandle.AddrOfPinnedObject(), origBuffer.Length); + Assert.AreEqual(bufferLength, slice.Length); + + var newBuffer = new byte[bufferLength]; + slice.CopyTo(new ArraySegment(newBuffer)); + CollectionAssert.AreEqual(origBuffer, newBuffer); + } + finally + { + gcHandle.Free(); + } + } + + [TestCase] + public void SliceFromNativePtr_CopyToArraySegmentTooSmall() + { + var origBuffer = GetTestBuffer(100); + var gcHandle = GCHandle.Alloc(origBuffer, GCHandleType.Pinned); + try + { + var slice = new Slice(gcHandle.AddrOfPinnedObject(), origBuffer.Length); + var tooSmall = new byte[origBuffer.Length - 1]; + Assert.Catch(typeof(ArgumentException), () => slice.CopyTo(new ArraySegment(tooSmall))); + } + finally + { + gcHandle.Free(); + } + } + + // create a buffer of given size and fill it with some data + private byte[] GetTestBuffer(int length) + { + var testBuffer = new byte[length]; + for (int i = 0; i < testBuffer.Length; i++) + { + testBuffer[i] = (byte) i; + } + return testBuffer; + } + } +} diff --git a/src/csharp/Grpc.Core/ForwardedTypes.cs b/src/csharp/Grpc.Core/ForwardedTypes.cs index 3df44d167be..ab5f5a87c67 100644 --- a/src/csharp/Grpc.Core/ForwardedTypes.cs +++ b/src/csharp/Grpc.Core/ForwardedTypes.cs @@ -18,6 +18,7 @@ using System.Runtime.CompilerServices; using Grpc.Core; +using Grpc.Core.Interceptors; using Grpc.Core.Internal; using Grpc.Core.Utils; @@ -32,16 +33,18 @@ using Grpc.Core.Utils; [assembly:TypeForwardedToAttribute(typeof(AuthContext))] [assembly:TypeForwardedToAttribute(typeof(AsyncAuthInterceptor))] [assembly:TypeForwardedToAttribute(typeof(AuthInterceptorContext))] -[assembly: TypeForwardedToAttribute(typeof(CallCredentials))] -[assembly: TypeForwardedToAttribute(typeof(CallFlags))] -[assembly: TypeForwardedToAttribute(typeof(CallInvoker))] -[assembly: TypeForwardedToAttribute(typeof(CallOptions))] +[assembly:TypeForwardedToAttribute(typeof(CallCredentials))] +[assembly:TypeForwardedToAttribute(typeof(CallFlags))] +[assembly:TypeForwardedToAttribute(typeof(CallInvoker))] +[assembly:TypeForwardedToAttribute(typeof(CallOptions))] +[assembly:TypeForwardedToAttribute(typeof(ClientInterceptorContext<,>))] [assembly:TypeForwardedToAttribute(typeof(ContextPropagationOptions))] [assembly:TypeForwardedToAttribute(typeof(ContextPropagationToken))] [assembly:TypeForwardedToAttribute(typeof(DeserializationContext))] [assembly:TypeForwardedToAttribute(typeof(IAsyncStreamReader<>))] [assembly:TypeForwardedToAttribute(typeof(IAsyncStreamWriter<>))] [assembly:TypeForwardedToAttribute(typeof(IClientStreamWriter<>))] +[assembly:TypeForwardedToAttribute(typeof(Interceptor))] [assembly:TypeForwardedToAttribute(typeof(IServerStreamWriter<>))] [assembly:TypeForwardedToAttribute(typeof(Marshaller<>))] [assembly:TypeForwardedToAttribute(typeof(Marshallers))] diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index b7c191ea6a9..afd60e73a21 100755 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -19,6 +19,15 @@ true + + true + + + + 7.2 + $(DefineConstants);GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY + + diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index 785081c341a..a1c688140d1 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -111,7 +111,7 @@ namespace Grpc.Core.Internal { using (profiler.NewScope("AsyncCall.UnaryCall.HandleBatch")) { - HandleUnaryResponse(success, ctx.GetReceivedStatusOnClient(), ctx.GetReceivedMessage(), ctx.GetReceivedInitialMetadata()); + HandleUnaryResponse(success, ctx.GetReceivedStatusOnClient(), ctx.GetReceivedMessageReader(), ctx.GetReceivedInitialMetadata()); } } catch (Exception e) @@ -537,14 +537,14 @@ namespace Grpc.Core.Internal /// /// Handler for unary response completion. /// - private void HandleUnaryResponse(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders) + private void HandleUnaryResponse(bool success, ClientSideStatus receivedStatus, IBufferReader receivedMessageReader, Metadata responseHeaders) { // NOTE: because this event is a result of batch containing GRPC_OP_RECV_STATUS_ON_CLIENT, // success will be always set to true. TaskCompletionSource delayedStreamingWriteTcs = null; TResponse msg = default(TResponse); - var deserializeException = TryDeserialize(receivedMessage, out msg); + var deserializeException = TryDeserialize(receivedMessageReader, out msg); bool releasedResources; lock (myLock) @@ -634,9 +634,9 @@ namespace Grpc.Core.Internal IUnaryResponseClientCallback UnaryResponseClientCallback => this; - void IUnaryResponseClientCallback.OnUnaryResponseClient(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders) + void IUnaryResponseClientCallback.OnUnaryResponseClient(bool success, ClientSideStatus receivedStatus, IBufferReader receivedMessageReader, Metadata responseHeaders) { - HandleUnaryResponse(success, receivedStatus, receivedMessage, responseHeaders); + HandleUnaryResponse(success, receivedStatus, receivedMessageReader, responseHeaders); } IReceivedStatusOnClientCallback ReceivedStatusOnClientCallback => this; diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs index 39c9f7c6160..0b99aaf3e21 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs @@ -228,12 +228,12 @@ namespace Grpc.Core.Internal } } - protected Exception TryDeserialize(byte[] payload, out TRead msg) + protected Exception TryDeserialize(IBufferReader reader, out TRead msg) { DefaultDeserializationContext context = null; try { - context = DefaultDeserializationContext.GetInitializedThreadLocal(payload); + context = DefaultDeserializationContext.GetInitializedThreadLocal(reader); msg = deserializer(context); return null; } @@ -245,7 +245,6 @@ namespace Grpc.Core.Internal finally { context?.Reset(); - } } @@ -333,21 +332,21 @@ namespace Grpc.Core.Internal /// /// Handles streaming read completion. /// - protected void HandleReadFinished(bool success, byte[] receivedMessage) + protected void HandleReadFinished(bool success, IBufferReader receivedMessageReader) { - // if success == false, received message will be null. It that case we will + // if success == false, the message reader will report null payload. It that case we will // treat this completion as the last read an rely on C core to handle the failed // read (e.g. deliver approriate statusCode on the clientside). TRead msg = default(TRead); - var deserializeException = (success && receivedMessage != null) ? TryDeserialize(receivedMessage, out msg) : null; + var deserializeException = (success && receivedMessageReader.TotalLength.HasValue) ? TryDeserialize(receivedMessageReader, out msg) : null; TaskCompletionSource origTcs = null; bool releasedResources; lock (myLock) { origTcs = streamingReadTcs; - if (receivedMessage == null) + if (!receivedMessageReader.TotalLength.HasValue) { // This was the last read. readingDone = true; @@ -391,9 +390,9 @@ namespace Grpc.Core.Internal IReceivedMessageCallback ReceivedMessageCallback => this; - void IReceivedMessageCallback.OnReceivedMessage(bool success, byte[] receivedMessage) + void IReceivedMessageCallback.OnReceivedMessage(bool success, IBufferReader receivedMessageReader) { - HandleReadFinished(success, receivedMessage); + HandleReadFinished(success, receivedMessageReader); } } } diff --git a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs index 085e7faf595..50a626842dd 100644 --- a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs @@ -30,10 +30,17 @@ namespace Grpc.Core.Internal void OnComplete(bool success); } + internal interface IBufferReader + { + int? TotalLength { get; } + + bool TryGetNextSlice(out Slice slice); + } + /// /// grpcsharp_batch_context /// - internal class BatchContextSafeHandle : SafeHandleZeroIsInvalid, IOpCompletionCallback, IPooledObject + internal class BatchContextSafeHandle : SafeHandleZeroIsInvalid, IOpCompletionCallback, IPooledObject, IBufferReader { static readonly NativeMethods Native = NativeMethods.Get(); static readonly ILogger Logger = GrpcEnvironment.Logger.ForType(); @@ -93,17 +100,9 @@ namespace Grpc.Core.Internal return new ClientSideStatus(status, metadata); } - // Gets data of recv_message completion. - public byte[] GetReceivedMessage() + public IBufferReader GetReceivedMessageReader() { - IntPtr len = Native.grpcsharp_batch_context_recv_message_length(this); - if (len == new IntPtr(-1)) - { - return null; - } - byte[] data = new byte[(int)len]; - Native.grpcsharp_batch_context_recv_message_to_buffer(this, data, new UIntPtr((ulong)data.Length)); - return data; + return this; } // Gets data of receive_close_on_server completion. @@ -153,6 +152,29 @@ namespace Grpc.Core.Internal } } + int? IBufferReader.TotalLength + { + get + { + var len = Native.grpcsharp_batch_context_recv_message_length(this); + return len != new IntPtr(-1) ? (int?) len : null; + } + } + + bool IBufferReader.TryGetNextSlice(out Slice slice) + { + UIntPtr sliceLen; + IntPtr sliceDataPtr; + + if (0 == Native.grpcsharp_batch_context_recv_message_next_slice_peek(this, out sliceLen, out sliceDataPtr)) + { + slice = default(Slice); + return false; + } + slice = new Slice(sliceDataPtr, (int) sliceLen); + return true; + } + struct CompletionCallbackData { public CompletionCallbackData(BatchCompletionDelegate callback, object state) diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs index a3ef3e61ee1..858d2a69605 100644 --- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs +++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs @@ -35,11 +35,11 @@ namespace Grpc.Core.Internal // Completion handlers are pre-allocated to avoid unneccessary delegate allocations. // The "state" field is used to store the actual callback to invoke. static readonly BatchCompletionDelegate CompletionHandler_IUnaryResponseClientCallback = - (success, context, state) => ((IUnaryResponseClientCallback)state).OnUnaryResponseClient(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata()); + (success, context, state) => ((IUnaryResponseClientCallback)state).OnUnaryResponseClient(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessageReader(), context.GetReceivedInitialMetadata()); static readonly BatchCompletionDelegate CompletionHandler_IReceivedStatusOnClientCallback = (success, context, state) => ((IReceivedStatusOnClientCallback)state).OnReceivedStatusOnClient(success, context.GetReceivedStatusOnClient()); static readonly BatchCompletionDelegate CompletionHandler_IReceivedMessageCallback = - (success, context, state) => ((IReceivedMessageCallback)state).OnReceivedMessage(success, context.GetReceivedMessage()); + (success, context, state) => ((IReceivedMessageCallback)state).OnReceivedMessage(success, context.GetReceivedMessageReader()); static readonly BatchCompletionDelegate CompletionHandler_IReceivedResponseHeadersCallback = (success, context, state) => ((IReceivedResponseHeadersCallback)state).OnReceivedResponseHeaders(success, context.GetReceivedInitialMetadata()); static readonly BatchCompletionDelegate CompletionHandler_ISendCompletionCallback = diff --git a/src/csharp/Grpc.Core/Internal/DefaultDeserializationContext.cs b/src/csharp/Grpc.Core/Internal/DefaultDeserializationContext.cs index 7ace80e8d53..946c37de190 100644 --- a/src/csharp/Grpc.Core/Internal/DefaultDeserializationContext.cs +++ b/src/csharp/Grpc.Core/Internal/DefaultDeserializationContext.cs @@ -20,6 +20,10 @@ using Grpc.Core.Utils; using System; using System.Threading; +#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY +using System.Buffers; +#endif + namespace Grpc.Core.Internal { internal class DefaultDeserializationContext : DeserializationContext @@ -27,40 +31,71 @@ namespace Grpc.Core.Internal static readonly ThreadLocal threadLocalInstance = new ThreadLocal(() => new DefaultDeserializationContext(), false); - byte[] payload; - bool alreadyCalledPayloadAsNewBuffer; + IBufferReader bufferReader; + int payloadLength; +#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY + ReusableSliceBuffer cachedSliceBuffer = new ReusableSliceBuffer(); +#endif public DefaultDeserializationContext() { Reset(); } - public override int PayloadLength => payload.Length; + public override int PayloadLength => payloadLength; public override byte[] PayloadAsNewBuffer() { - GrpcPreconditions.CheckState(!alreadyCalledPayloadAsNewBuffer); - alreadyCalledPayloadAsNewBuffer = true; - return payload; + var buffer = new byte[payloadLength]; + FillContinguousBuffer(bufferReader, buffer); + return buffer; + } + +#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY + public override ReadOnlySequence PayloadAsReadOnlySequence() + { + var sequence = cachedSliceBuffer.PopulateFrom(bufferReader); + GrpcPreconditions.CheckState(sequence.Length == payloadLength); + return sequence; } +#endif - public void Initialize(byte[] payload) + public void Initialize(IBufferReader bufferReader) { - this.payload = GrpcPreconditions.CheckNotNull(payload); - this.alreadyCalledPayloadAsNewBuffer = false; + this.bufferReader = GrpcPreconditions.CheckNotNull(bufferReader); + this.payloadLength = bufferReader.TotalLength.Value; // payload must not be null } public void Reset() { - this.payload = null; - this.alreadyCalledPayloadAsNewBuffer = true; // mark payload as read + this.bufferReader = null; + this.payloadLength = 0; +#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY + this.cachedSliceBuffer.Invalidate(); +#endif } - public static DefaultDeserializationContext GetInitializedThreadLocal(byte[] payload) + public static DefaultDeserializationContext GetInitializedThreadLocal(IBufferReader bufferReader) { var instance = threadLocalInstance.Value; - instance.Initialize(payload); + instance.Initialize(bufferReader); return instance; } + + private void FillContinguousBuffer(IBufferReader reader, byte[] destination) + { +#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY + PayloadAsReadOnlySequence().CopyTo(new Span(destination)); +#else + int offset = 0; + while (reader.TryGetNextSlice(out Slice slice)) + { + slice.CopyTo(new ArraySegment(destination, offset, (int)slice.Length)); + offset += (int)slice.Length; + } + // check that we filled the entire destination + GrpcPreconditions.CheckState(offset == payloadLength); +#endif + } } } diff --git a/src/csharp/Grpc.Core/Internal/INativeCall.cs b/src/csharp/Grpc.Core/Internal/INativeCall.cs index 5c35b2ba461..98117c6988a 100644 --- a/src/csharp/Grpc.Core/Internal/INativeCall.cs +++ b/src/csharp/Grpc.Core/Internal/INativeCall.cs @@ -22,7 +22,7 @@ namespace Grpc.Core.Internal { internal interface IUnaryResponseClientCallback { - void OnUnaryResponseClient(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders); + void OnUnaryResponseClient(bool success, ClientSideStatus receivedStatus, IBufferReader receivedMessageReader, Metadata responseHeaders); } // Received status for streaming response calls. @@ -33,7 +33,7 @@ namespace Grpc.Core.Internal internal interface IReceivedMessageCallback { - void OnReceivedMessage(bool success, byte[] receivedMessage); + void OnReceivedMessage(bool success, IBufferReader receivedMessageReader); } internal interface IReceivedResponseHeadersCallback diff --git a/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs b/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs index a1387aff562..b8a60b31c40 100644 --- a/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs +++ b/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs @@ -40,7 +40,7 @@ namespace Grpc.Core.Internal public readonly Delegates.grpcsharp_batch_context_create_delegate grpcsharp_batch_context_create; public readonly Delegates.grpcsharp_batch_context_recv_initial_metadata_delegate grpcsharp_batch_context_recv_initial_metadata; public readonly Delegates.grpcsharp_batch_context_recv_message_length_delegate grpcsharp_batch_context_recv_message_length; - public readonly Delegates.grpcsharp_batch_context_recv_message_to_buffer_delegate grpcsharp_batch_context_recv_message_to_buffer; + public readonly Delegates.grpcsharp_batch_context_recv_message_next_slice_peek_delegate grpcsharp_batch_context_recv_message_next_slice_peek; public readonly Delegates.grpcsharp_batch_context_recv_status_on_client_status_delegate grpcsharp_batch_context_recv_status_on_client_status; public readonly Delegates.grpcsharp_batch_context_recv_status_on_client_details_delegate grpcsharp_batch_context_recv_status_on_client_details; public readonly Delegates.grpcsharp_batch_context_recv_status_on_client_trailing_metadata_delegate grpcsharp_batch_context_recv_status_on_client_trailing_metadata; @@ -141,7 +141,7 @@ namespace Grpc.Core.Internal this.grpcsharp_batch_context_create = GetMethodDelegate(library); this.grpcsharp_batch_context_recv_initial_metadata = GetMethodDelegate(library); this.grpcsharp_batch_context_recv_message_length = GetMethodDelegate(library); - this.grpcsharp_batch_context_recv_message_to_buffer = GetMethodDelegate(library); + this.grpcsharp_batch_context_recv_message_next_slice_peek = GetMethodDelegate(library); this.grpcsharp_batch_context_recv_status_on_client_status = GetMethodDelegate(library); this.grpcsharp_batch_context_recv_status_on_client_details = GetMethodDelegate(library); this.grpcsharp_batch_context_recv_status_on_client_trailing_metadata = GetMethodDelegate(library); @@ -241,7 +241,7 @@ namespace Grpc.Core.Internal this.grpcsharp_batch_context_create = DllImportsFromStaticLib.grpcsharp_batch_context_create; this.grpcsharp_batch_context_recv_initial_metadata = DllImportsFromStaticLib.grpcsharp_batch_context_recv_initial_metadata; this.grpcsharp_batch_context_recv_message_length = DllImportsFromStaticLib.grpcsharp_batch_context_recv_message_length; - this.grpcsharp_batch_context_recv_message_to_buffer = DllImportsFromStaticLib.grpcsharp_batch_context_recv_message_to_buffer; + this.grpcsharp_batch_context_recv_message_next_slice_peek = DllImportsFromStaticLib.grpcsharp_batch_context_recv_message_next_slice_peek; this.grpcsharp_batch_context_recv_status_on_client_status = DllImportsFromStaticLib.grpcsharp_batch_context_recv_status_on_client_status; this.grpcsharp_batch_context_recv_status_on_client_details = DllImportsFromStaticLib.grpcsharp_batch_context_recv_status_on_client_details; this.grpcsharp_batch_context_recv_status_on_client_trailing_metadata = DllImportsFromStaticLib.grpcsharp_batch_context_recv_status_on_client_trailing_metadata; @@ -341,7 +341,7 @@ namespace Grpc.Core.Internal this.grpcsharp_batch_context_create = DllImportsFromSharedLib.grpcsharp_batch_context_create; this.grpcsharp_batch_context_recv_initial_metadata = DllImportsFromSharedLib.grpcsharp_batch_context_recv_initial_metadata; this.grpcsharp_batch_context_recv_message_length = DllImportsFromSharedLib.grpcsharp_batch_context_recv_message_length; - this.grpcsharp_batch_context_recv_message_to_buffer = DllImportsFromSharedLib.grpcsharp_batch_context_recv_message_to_buffer; + this.grpcsharp_batch_context_recv_message_next_slice_peek = DllImportsFromSharedLib.grpcsharp_batch_context_recv_message_next_slice_peek; this.grpcsharp_batch_context_recv_status_on_client_status = DllImportsFromSharedLib.grpcsharp_batch_context_recv_status_on_client_status; this.grpcsharp_batch_context_recv_status_on_client_details = DllImportsFromSharedLib.grpcsharp_batch_context_recv_status_on_client_details; this.grpcsharp_batch_context_recv_status_on_client_trailing_metadata = DllImportsFromSharedLib.grpcsharp_batch_context_recv_status_on_client_trailing_metadata; @@ -444,7 +444,7 @@ namespace Grpc.Core.Internal public delegate BatchContextSafeHandle grpcsharp_batch_context_create_delegate(); public delegate IntPtr grpcsharp_batch_context_recv_initial_metadata_delegate(BatchContextSafeHandle ctx); public delegate IntPtr grpcsharp_batch_context_recv_message_length_delegate(BatchContextSafeHandle ctx); - public delegate void grpcsharp_batch_context_recv_message_to_buffer_delegate(BatchContextSafeHandle ctx, byte[] buffer, UIntPtr bufferLen); + public delegate int grpcsharp_batch_context_recv_message_next_slice_peek_delegate(BatchContextSafeHandle ctx, out UIntPtr sliceLen, out IntPtr sliceDataPtr); public delegate StatusCode grpcsharp_batch_context_recv_status_on_client_status_delegate(BatchContextSafeHandle ctx); public delegate IntPtr grpcsharp_batch_context_recv_status_on_client_details_delegate(BatchContextSafeHandle ctx, out UIntPtr detailsLength); public delegate IntPtr grpcsharp_batch_context_recv_status_on_client_trailing_metadata_delegate(BatchContextSafeHandle ctx); @@ -562,7 +562,7 @@ namespace Grpc.Core.Internal public static extern IntPtr grpcsharp_batch_context_recv_message_length(BatchContextSafeHandle ctx); [DllImport(ImportName)] - public static extern void grpcsharp_batch_context_recv_message_to_buffer(BatchContextSafeHandle ctx, byte[] buffer, UIntPtr bufferLen); + public static extern int grpcsharp_batch_context_recv_message_next_slice_peek(BatchContextSafeHandle ctx, out UIntPtr sliceLen, out IntPtr sliceDataPtr); [DllImport(ImportName)] public static extern StatusCode grpcsharp_batch_context_recv_status_on_client_status(BatchContextSafeHandle ctx); @@ -858,7 +858,7 @@ namespace Grpc.Core.Internal public static extern IntPtr grpcsharp_batch_context_recv_message_length(BatchContextSafeHandle ctx); [DllImport(ImportName)] - public static extern void grpcsharp_batch_context_recv_message_to_buffer(BatchContextSafeHandle ctx, byte[] buffer, UIntPtr bufferLen); + public static extern int grpcsharp_batch_context_recv_message_next_slice_peek(BatchContextSafeHandle ctx, out UIntPtr sliceLen, out IntPtr sliceDataPtr); [DllImport(ImportName)] public static extern StatusCode grpcsharp_batch_context_recv_status_on_client_status(BatchContextSafeHandle ctx); diff --git a/src/csharp/Grpc.Core/Internal/ReusableSliceBuffer.cs b/src/csharp/Grpc.Core/Internal/ReusableSliceBuffer.cs new file mode 100644 index 00000000000..2d38509e511 --- /dev/null +++ b/src/csharp/Grpc.Core/Internal/ReusableSliceBuffer.cs @@ -0,0 +1,148 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// 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. + +#endregion + +#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY + +using Grpc.Core.Utils; +using System; +using System.Threading; + +using System.Buffers; + +namespace Grpc.Core.Internal +{ + internal class ReusableSliceBuffer + { + public const int MaxCachedSegments = 1024; // ~4MB payload for 4K slices + + readonly SliceSegment[] cachedSegments = new SliceSegment[MaxCachedSegments]; + int populatedSegmentCount; + + public ReadOnlySequence PopulateFrom(IBufferReader bufferReader) + { + populatedSegmentCount = 0; + long offset = 0; + SliceSegment prevSegment = null; + while (bufferReader.TryGetNextSlice(out Slice slice)) + { + // Initialize cached segment if still null or just allocate a new segment if we already reached MaxCachedSegments + var current = populatedSegmentCount < cachedSegments.Length ? cachedSegments[populatedSegmentCount] : new SliceSegment(); + if (current == null) + { + current = cachedSegments[populatedSegmentCount] = new SliceSegment(); + } + + current.Reset(slice, offset); + prevSegment?.SetNext(current); + + populatedSegmentCount ++; + offset += slice.Length; + prevSegment = current; + } + + // Not necessary for ending the ReadOnlySequence, but for making sure we + // don't keep more than MaxCachedSegments alive. + prevSegment?.SetNext(null); + + if (populatedSegmentCount == 0) + { + return ReadOnlySequence.Empty; + } + + var firstSegment = cachedSegments[0]; + var lastSegment = prevSegment; + return new ReadOnlySequence(firstSegment, 0, lastSegment, lastSegment.Memory.Length); + } + + public void Invalidate() + { + if (populatedSegmentCount == 0) + { + return; + } + var segment = cachedSegments[0]; + while (segment != null) + { + segment.Reset(new Slice(IntPtr.Zero, 0), 0); + var nextSegment = (SliceSegment) segment.Next; + segment.SetNext(null); + segment = nextSegment; + } + populatedSegmentCount = 0; + } + + // Represents a segment in ReadOnlySequence + // Segment is backed by Slice and the instances are reusable. + private class SliceSegment : ReadOnlySequenceSegment + { + readonly SliceMemoryManager pointerMemoryManager = new SliceMemoryManager(); + + public void Reset(Slice slice, long runningIndex) + { + pointerMemoryManager.Reset(slice); + Memory = pointerMemoryManager.Memory; // maybe not always necessary + RunningIndex = runningIndex; + } + + public void SetNext(ReadOnlySequenceSegment next) + { + Next = next; + } + } + + // Allow creating instances of Memory from Slice. + // Represents a chunk of native memory, but doesn't manage its lifetime. + // Instances of this class are reuseable - they can be reset to point to a different memory chunk. + // That is important to make the instances cacheable (rather then creating new instances + // the old ones will be reused to reduce GC pressure). + private class SliceMemoryManager : MemoryManager + { + private Slice slice; + + public void Reset(Slice slice) + { + this.slice = slice; + } + + public void Reset() + { + Reset(new Slice(IntPtr.Zero, 0)); + } + + public override Span GetSpan() + { + return slice.ToSpanUnsafe(); + } + + public override MemoryHandle Pin(int elementIndex = 0) + { + throw new NotSupportedException(); + } + + public override void Unpin() + { + } + + protected override void Dispose(bool disposing) + { + // NOP + } + } + } +} +#endif diff --git a/src/csharp/Grpc.Core/Internal/Slice.cs b/src/csharp/Grpc.Core/Internal/Slice.cs new file mode 100644 index 00000000000..22eb9537951 --- /dev/null +++ b/src/csharp/Grpc.Core/Internal/Slice.cs @@ -0,0 +1,68 @@ +#region Copyright notice and license + +// Copyright 2019 The gRPC Authors +// +// 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. + +#endregion + +using System; +using System.Runtime.InteropServices; +using System.Threading; +using Grpc.Core.Utils; + +namespace Grpc.Core.Internal +{ + /// + /// Slice of native memory. + /// Rough equivalent of grpc_slice (but doesn't support inlined slices, just a pointer to data and length) + /// + internal struct Slice + { + private readonly IntPtr dataPtr; + private readonly int length; + + public Slice(IntPtr dataPtr, int length) + { + this.dataPtr = dataPtr; + this.length = length; + } + + public int Length => length; + + // copies data of the slice to given span. + // there needs to be enough space in the destination buffer + public void CopyTo(ArraySegment destination) + { + Marshal.Copy(dataPtr, destination.Array, destination.Offset, length); + } + +#if GRPC_CSHARP_SUPPORT_SYSTEM_MEMORY + public Span ToSpanUnsafe() + { + unsafe + { + return new Span((byte*) dataPtr, length); + } + } +#endif + + /// + /// Returns a that represents the current . + /// + public override string ToString() + { + return string.Format("[Slice: dataPtr={0}, length={1}]", dataPtr, length); + } + } +} diff --git a/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.targets b/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.targets index 1a862337c58..b1030ba1f8b 100644 --- a/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.targets +++ b/src/csharp/Grpc.Tools/build/_protobuf/Google.Protobuf.Tools.targets @@ -28,6 +28,7 @@ True $(Protobuf_OutputPath) + MSBuild:Compile diff --git a/src/csharp/README.md b/src/csharp/README.md index 291772ff939..c01cae0422d 100644 --- a/src/csharp/README.md +++ b/src/csharp/README.md @@ -40,6 +40,17 @@ See [Experimentally supported platforms](experimental) for instructions. See [Experimentally supported platforms](experimental) for instructions. +NUGET DEVELOPMENT FEED (NIGHTLY BUILDS) +-------------- + +In production, you should use officially released stable packages available on http://nuget.org, but if you want to test the newest upstream bug fixes and features early, you can can use the development nuget feed where new nuget builds are uploaded nightly. + +Feed URL (NuGet v2): https://grpc.jfrog.io/grpc/api/nuget/grpc-nuget-dev + +Feed URL (NuGet v3): https://grpc.jfrog.io/grpc/api/nuget/v3/grpc-nuget-dev + +The same development nuget packages and packages for other languages can also be found at https://packages.grpc.io/ + BUILD FROM SOURCE ----------------- diff --git a/src/csharp/build/dependencies.props b/src/csharp/build/dependencies.props index b018aac0f8e..dd5f172c27b 100644 --- a/src/csharp/build/dependencies.props +++ b/src/csharp/build/dependencies.props @@ -1,7 +1,7 @@ - 1.21.0-dev + 1.22.0-dev 3.7.0 diff --git a/src/csharp/build_unitypackage.bat b/src/csharp/build_unitypackage.bat index 8c7718f727f..2f4cd2739da 100644 --- a/src/csharp/build_unitypackage.bat +++ b/src/csharp/build_unitypackage.bat @@ -13,7 +13,7 @@ @rem limitations under the License. @rem Current package versions -set VERSION=1.21.0-dev +set VERSION=1.22.0-dev @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 91d3957dbf0..51e498bcfb8 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -59,12 +59,16 @@ typedef struct grpcsharp_batch_context { } send_status_from_server; grpc_metadata_array recv_initial_metadata; grpc_byte_buffer* recv_message; + grpc_byte_buffer_reader* recv_message_reader; struct { grpc_metadata_array trailing_metadata; grpc_status_code status; grpc_slice status_details; } recv_status_on_client; int recv_close_on_server_cancelled; + + /* reserve space for byte_buffer_reader */ + grpc_byte_buffer_reader reserved_recv_message_reader; } grpcsharp_batch_context; GPR_EXPORT grpcsharp_batch_context* GPR_CALLTYPE @@ -206,6 +210,9 @@ grpcsharp_batch_context_reset(grpcsharp_batch_context* ctx) { grpcsharp_metadata_array_destroy_metadata_only(&(ctx->recv_initial_metadata)); + if (ctx->recv_message_reader) { + grpc_byte_buffer_reader_destroy(ctx->recv_message_reader); + } grpc_byte_buffer_destroy(ctx->recv_message); grpcsharp_metadata_array_destroy_metadata_only( @@ -264,27 +271,42 @@ GPR_EXPORT intptr_t GPR_CALLTYPE grpcsharp_batch_context_recv_message_length( } /* - * Copies data from recv_message to a buffer. Fatal error occurs if - * buffer is too small. + * Gets the next slice from recv_message byte buffer. + * Returns 1 if a slice was get successfully, 0 if there are no more slices to + * read. Set slice_len to the length of the slice and the slice_data_ptr to + * point to slice's data. Caller must ensure that the byte buffer being read + * from stays alive as long as the data of the slice are being accessed + * (grpc_byte_buffer_reader_peek method is used internally) + * + * Remarks: + * Slices can only be iterated once. + * Initializes recv_message_buffer_reader if it was not initialized yet. */ -GPR_EXPORT void GPR_CALLTYPE grpcsharp_batch_context_recv_message_to_buffer( - const grpcsharp_batch_context* ctx, char* buffer, size_t buffer_len) { - grpc_byte_buffer_reader reader; - grpc_slice slice; - size_t offset = 0; +GPR_EXPORT int GPR_CALLTYPE +grpcsharp_batch_context_recv_message_next_slice_peek( + grpcsharp_batch_context* ctx, size_t* slice_len, uint8_t** slice_data_ptr) { + *slice_len = 0; + *slice_data_ptr = NULL; - GPR_ASSERT(grpc_byte_buffer_reader_init(&reader, ctx->recv_message)); + if (!ctx->recv_message) { + return 0; + } - while (grpc_byte_buffer_reader_next(&reader, &slice)) { - size_t len = GRPC_SLICE_LENGTH(slice); - GPR_ASSERT(offset + len <= buffer_len); - memcpy(buffer + offset, GRPC_SLICE_START_PTR(slice), - GRPC_SLICE_LENGTH(slice)); - offset += len; - grpc_slice_unref(slice); + if (!ctx->recv_message_reader) { + ctx->recv_message_reader = &ctx->reserved_recv_message_reader; + GPR_ASSERT(grpc_byte_buffer_reader_init(ctx->recv_message_reader, + ctx->recv_message)); } - grpc_byte_buffer_reader_destroy(&reader); + grpc_slice* slice_ptr; + if (!grpc_byte_buffer_reader_peek(ctx->recv_message_reader, &slice_ptr)) { + return 0; + } + + /* recv_message buffer must not be deleted before all the data is read */ + *slice_len = GRPC_SLICE_LENGTH(*slice_ptr); + *slice_data_ptr = GRPC_SLICE_START_PTR(*slice_ptr); + return 1; } GPR_EXPORT grpc_status_code GPR_CALLTYPE diff --git a/src/csharp/tests.json b/src/csharp/tests.json index c1e7fc1a6bf..cacdb305d2e 100644 --- a/src/csharp/tests.json +++ b/src/csharp/tests.json @@ -7,8 +7,12 @@ "Grpc.Core.Internal.Tests.ChannelArgsSafeHandleTest", "Grpc.Core.Internal.Tests.CompletionQueueEventTest", "Grpc.Core.Internal.Tests.CompletionQueueSafeHandleTest", + "Grpc.Core.Internal.Tests.DefaultDeserializationContextTest", "Grpc.Core.Internal.Tests.DefaultObjectPoolTest", + "Grpc.Core.Internal.Tests.FakeBufferReaderManagerTest", "Grpc.Core.Internal.Tests.MetadataArraySafeHandleTest", + "Grpc.Core.Internal.Tests.ReusableSliceBufferTest", + "Grpc.Core.Internal.Tests.SliceTest", "Grpc.Core.Internal.Tests.TimespecTest", "Grpc.Core.Tests.AppDomainUnloadTest", "Grpc.Core.Tests.AuthContextTest", diff --git a/src/csharp/unitypackage/unitypackage_skeleton/Plugins/Grpc.Core/runtimes/grpc_csharp_ext_dummy_stubs.c b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/Grpc.Core/runtimes/grpc_csharp_ext_dummy_stubs.c index 0e9d56f5bdf..c2f9d20333d 100644 --- a/src/csharp/unitypackage/unitypackage_skeleton/Plugins/Grpc.Core/runtimes/grpc_csharp_ext_dummy_stubs.c +++ b/src/csharp/unitypackage/unitypackage_skeleton/Plugins/Grpc.Core/runtimes/grpc_csharp_ext_dummy_stubs.c @@ -46,7 +46,7 @@ void grpcsharp_batch_context_recv_message_length() { fprintf(stderr, "Should never reach here"); abort(); } -void grpcsharp_batch_context_recv_message_to_buffer() { +void grpcsharp_batch_context_recv_message_next_slice_peek() { fprintf(stderr, "Should never reach here"); abort(); } diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec index af876287038..401540209af 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.21.0-dev' + v = '1.22.0-dev' s.version = v s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.' s.description = <<-DESC @@ -101,7 +101,7 @@ Pod::Spec.new do |s| s.preserve_paths = plugin # Restrict the protoc version to the one supported by this plugin. - s.dependency '!ProtoCompiler', '3.6.1' + s.dependency '!ProtoCompiler', '3.7.0' # For the Protobuf dependency not to complain: s.ios.deployment_target = '7.0' s.osx.deployment_target = '10.9' diff --git a/src/objective-c/!ProtoCompiler.podspec b/src/objective-c/!ProtoCompiler.podspec index 789265470c1..58d74be4d4e 100644 --- a/src/objective-c/!ProtoCompiler.podspec +++ b/src/objective-c/!ProtoCompiler.podspec @@ -36,7 +36,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' - v = '3.6.1' + v = '3.7.0' s.version = v s.summary = 'The Protobuf Compiler (protoc) generates Objective-C files from .proto files' s.description = <<-DESC diff --git a/src/objective-c/GRPCClient/GRPCCall.h b/src/objective-c/GRPCClient/GRPCCall.h index cf66531ab0c..4a1d98b7ba5 100644 --- a/src/objective-c/GRPCClient/GRPCCall.h +++ b/src/objective-c/GRPCClient/GRPCCall.h @@ -135,7 +135,8 @@ typedef NS_ENUM(NSUInteger, GRPCErrorCode) { /** * The server is currently unavailable. This is most likely a transient condition and may be - * corrected by retrying with a backoff. + * corrected by retrying with a backoff. Note that it is not always safe to retry + * non-idempotent operations. */ GRPCErrorCodeUnavailable = 14, diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m index 40aaea16e56..617208b8079 100644 --- a/src/objective-c/GRPCClient/GRPCCall.m +++ b/src/objective-c/GRPCClient/GRPCCall.m @@ -61,6 +61,15 @@ const char *kCFStreamVarName = "grpc_cfstream"; - (void)receiveNextMessages:(NSUInteger)numberOfMessages; +- (instancetype)initWithHost:(NSString *)host + path:(NSString *)path + callSafety:(GRPCCallSafety)safety + requestsWriter:(GRXWriter *)requestsWriter + callOptions:(GRPCCallOptions *)callOptions + writeDone:(void (^)(void))writeDone; + +- (void)receiveNextMessages:(NSUInteger)numberOfMessages; + @end @implementation GRPCRequestOptions @@ -235,6 +244,33 @@ const char *kCFStreamVarName = "grpc_cfstream"; } } +- (void)issueDidWriteData { + @synchronized(self) { + if (_callOptions.flowControlEnabled && [_handler respondsToSelector:@selector(didWriteData)]) { + dispatch_async(_dispatchQueue, ^{ + id copiedHandler = nil; + @synchronized(self) { + copiedHandler = self->_handler; + }; + [copiedHandler didWriteData]; + }); + } + } +} + +- (void)receiveNextMessages:(NSUInteger)numberOfMessages { + // branching based on _callOptions.flowControlEnabled is handled inside _call + GRPCCall *copiedCall = nil; + @synchronized(self) { + copiedCall = _call; + if (copiedCall == nil) { + _pendingReceiveNextMessages += numberOfMessages; + return; + } + } + [copiedCall receiveNextMessages:numberOfMessages]; +} + @end // The following methods of a C gRPC call object aren't reentrant, and thus diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m index 7557367ed4a..e6522d7a27e 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannelFactory.m @@ -61,8 +61,7 @@ NSBundle *resourceBundle = [NSBundle bundleWithURL:[[bundle resourceURL] URLByAppendingPathComponent:resourceBundlePath]]; NSString *path = [resourceBundle pathForResource:rootsPEM ofType:@"pem"]; - setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, - [path cStringUsingEncoding:NSUTF8StringEncoding], 1); + setenv("GRPC_DEFAULT_SSL_ROOTS_FILE_PATH", [path cStringUsingEncoding:NSUTF8StringEncoding], 1); }); NSData *rootsASCII = nil; diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h index fcbdfb21539..6fe0c396dd3 100644 --- a/src/objective-c/GRPCClient/private/version.h +++ b/src/objective-c/GRPCClient/private/version.h @@ -22,4 +22,4 @@ // instead. This file can be regenerated from the template by running // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.21.0-dev" +#define GRPC_OBJC_VERSION_STRING @"1.22.0-dev" diff --git a/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm b/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm index 2fac1be3d0e..0d081e4a410 100644 --- a/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm +++ b/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm @@ -37,11 +37,11 @@ #include #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/tmpfile.h" #include "src/core/lib/security/credentials/credentials.h" +#include "src/core/lib/security/security_connector/ssl_utils.h" #include "test/core/end2end/data/ssl_test_data.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" @@ -172,7 +172,7 @@ static char *roots_filename; GPR_ASSERT(roots_file != NULL); GPR_ASSERT(fwrite(test_root_cert, 1, roots_size, roots_file) == roots_size); fclose(roots_file); - gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_filename); + GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, roots_filename); grpc_init(); diff --git a/src/objective-c/tests/version.h b/src/objective-c/tests/version.h index 87516de11e8..c835c1da190 100644 --- a/src/objective-c/tests/version.h +++ b/src/objective-c/tests/version.h @@ -22,5 +22,5 @@ // instead. This file can be regenerated from the template by running // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.21.0-dev" +#define GRPC_OBJC_VERSION_STRING @"1.22.0-dev" #define GRPC_C_VERSION_STRING @"7.0.0" diff --git a/src/php/bin/run_tests.sh b/src/php/bin/run_tests.sh index 49fd84514c1..a78dd259e2f 100755 --- a/src/php/bin/run_tests.sh +++ b/src/php/bin/run_tests.sh @@ -22,16 +22,17 @@ cd src/php/bin source ./determine_extension_dir.sh # in some jenkins macos machine, somehow the PHP build script can't find libgrpc.dylib export DYLD_LIBRARY_PATH=$root/libs/$CONFIG -php $extension_dir -d max_execution_time=300 $(which phpunit) -v --debug \ +$(which php) $extension_dir -d max_execution_time=300 $(which phpunit) -v --debug \ --exclude-group persistent_list_bound_tests ../tests/unit_tests -php $extension_dir -d max_execution_time=300 $(which phpunit) -v --debug \ +$(which php) $extension_dir -d max_execution_time=300 $(which phpunit) -v --debug \ ../tests/unit_tests/PersistentChannelTests export ZEND_DONT_UNLOAD_MODULES=1 export USE_ZEND_ALLOC=0 # Detect whether valgrind is executable if [ -x "$(command -v valgrind)" ]; then - valgrind --error-exitcode=10 --leak-check=yes php $extension_dir -d max_execution_time=300 \ + $(which valgrind) --error-exitcode=10 --leak-check=yes \ + $(which php) $extension_dir -d max_execution_time=300 \ ../tests/MemoryLeakTest/MemoryLeakTest.php fi diff --git a/src/php/composer.json b/src/php/composer.json index a9d0aebffca..ca1001b6d2b 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": "Apache-2.0", - "version": "1.21.0", + "version": "1.22.0", "require": { "php": ">=5.5.0", "google/protobuf": "^v3.3.0" diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c index c06bdea7feb..860d38be34a 100644 --- a/src/php/ext/grpc/channel.c +++ b/src/php/ext/grpc/channel.c @@ -30,6 +30,7 @@ #include #include +#include #include "completion_queue.h" #include "channel_credentials.h" @@ -247,12 +248,12 @@ void create_and_add_channel_to_persistent_list( // If no channel can be deleted from the persistent map, // do not persist this one. create_channel(channel, target, args, creds); - php_printf("[Warning] The number of channel for the" + gpr_log(GPR_INFO, "[Warning] The number of channel for the" " target %s is maxed out bounded.\n", target); - php_printf("[Warning] Target upper bound: %d. Current size: %d.\n", + gpr_log(GPR_INFO, "[Warning] Target upper bound: %d. Current size: %d.\n", target_bound_status->upper_bound, target_bound_status->current_count); - php_printf("[Warning] Target %s will not be persisted.\n", target); + gpr_log(GPR_INFO, "[Warning] Target %s will not be persisted.\n", target); return; } } diff --git a/src/php/ext/grpc/php_grpc.c b/src/php/ext/grpc/php_grpc.c index 3064563d03f..f6c2f85ed47 100644 --- a/src/php/ext/grpc/php_grpc.c +++ b/src/php/ext/grpc/php_grpc.c @@ -205,11 +205,15 @@ void register_fork_handlers() { void apply_ini_settings() { if (GRPC_G(enable_fork_support)) { - setenv("GRPC_ENABLE_FORK_SUPPORT", "1", 1 /* overwrite? */); + putenv("GRPC_ENABLE_FORK_SUPPORT=1"); } if (GRPC_G(poll_strategy)) { - setenv("GRPC_POLL_STRATEGY", GRPC_G(poll_strategy), 1 /* overwrite? */); + char *poll_str = malloc(sizeof("GRPC_POLL_STRATEGY=") + + strlen(GRPC_G(poll_strategy))); + strcpy(poll_str, "GRPC_POLL_STRATEGY="); + strcat(poll_str, GRPC_G(poll_strategy)); + putenv(poll_str); } } diff --git a/src/php/ext/grpc/version.h b/src/php/ext/grpc/version.h index 43b3fa629ff..3e9f88c61d6 100644 --- a/src/php/ext/grpc/version.h +++ b/src/php/ext/grpc/version.h @@ -20,6 +20,6 @@ #ifndef VERSION_H #define VERSION_H -#define PHP_GRPC_VERSION "1.21.0dev" +#define PHP_GRPC_VERSION "1.22.0dev" #endif /* VERSION_H */ diff --git a/src/proto/grpc/channelz/BUILD b/src/proto/grpc/channelz/BUILD index b6b485e3e8d..1d80ec23af1 100644 --- a/src/proto/grpc/channelz/BUILD +++ b/src/proto/grpc/channelz/BUILD @@ -25,6 +25,11 @@ grpc_proto_library( well_known_protos = True, ) +proto_library( + name = "channelz_proto_descriptors", + srcs = ["channelz.proto"], +) + filegroup( name = "channelz_proto_file", srcs = [ diff --git a/src/proto/grpc/health/v1/BUILD b/src/proto/grpc/health/v1/BUILD index 38a7d992e06..fc58e8a1770 100644 --- a/src/proto/grpc/health/v1/BUILD +++ b/src/proto/grpc/health/v1/BUILD @@ -23,6 +23,11 @@ grpc_proto_library( srcs = ["health.proto"], ) +proto_library( + name = "health_proto_descriptor", + srcs = ["health.proto"], +) + filegroup( name = "health_proto_file", srcs = [ diff --git a/src/proto/grpc/reflection/v1alpha/BUILD b/src/proto/grpc/reflection/v1alpha/BUILD index 4d919d029ee..5424c0d867e 100644 --- a/src/proto/grpc/reflection/v1alpha/BUILD +++ b/src/proto/grpc/reflection/v1alpha/BUILD @@ -23,6 +23,11 @@ grpc_proto_library( srcs = ["reflection.proto"], ) +proto_library( + name = "reflection_proto_descriptor", + srcs = ["reflection.proto"], +) + filegroup( name = "reflection_proto_file", srcs = [ diff --git a/src/proto/grpc/testing/BUILD b/src/proto/grpc/testing/BUILD index 9876d5160a1..727c99cf99c 100644 --- a/src/proto/grpc/testing/BUILD +++ b/src/proto/grpc/testing/BUILD @@ -16,7 +16,7 @@ licenses(["notice"]) # Apache v2 load("//bazel:grpc_build_system.bzl", "grpc_proto_library", "grpc_package") load("@grpc_python_dependencies//:requirements.bzl", "requirement") -load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library") +load("//bazel:python_rules.bzl", "py_proto_library") grpc_package(name = "testing", visibility = "public") @@ -61,13 +61,14 @@ grpc_proto_library( has_services = False, ) +proto_library( + name = "empty_proto_descriptor", + srcs = ["empty.proto"], +) + py_proto_library( name = "py_empty_proto", - protos = ["empty.proto",], - with_grpc = True, - deps = [ - requirement('protobuf'), - ], + deps = [":empty_proto_descriptor"], ) grpc_proto_library( @@ -76,13 +77,14 @@ grpc_proto_library( has_services = False, ) +proto_library( + name = "messages_proto_descriptor", + srcs = ["messages.proto"], +) + py_proto_library( name = "py_messages_proto", - protos = ["messages.proto",], - with_grpc = True, - deps = [ - requirement('protobuf'), - ], + deps = [":messages_proto_descriptor"], ) grpc_proto_library( @@ -144,16 +146,50 @@ grpc_proto_library( ], ) +# Test that grpc_proto_library/cc_grpc_library can consume generated files +genrule( + name = "messages_gen_proto_file", + srcs = ["messages.proto"], + outs = ["messages_gen.proto"], + cmd = "cp $< $@", +) + +grpc_proto_library( + name = "messages_gen_proto", + srcs = ["messages_gen_proto_file"], + has_services = False, +) + +genrule( + name = "test_gen_proto_file", + srcs = ["test.proto"], + outs = ["test_gen.proto"], + cmd = "sed 's/messages.proto/messages_gen.proto/' $< > $@", +) + +# Consume generated files in srcs and in deps +grpc_proto_library( + name = "test_gen_proto", + srcs = ["test_gen_proto_file"], + deps = [ + "empty_proto", + "messages_gen_proto", + ], +) + +proto_library( + name = "test_proto_descriptor", + srcs = ["test.proto"], + deps = [ + ":empty_proto_descriptor", + ":messages_proto_descriptor", + ], +) + py_proto_library( name = "py_test_proto", - protos = ["test.proto",], - with_grpc = True, deps = [ - requirement('protobuf'), - ], - proto_deps = [ - ":py_empty_proto", - ":py_messages_proto", + ":test_proto_descriptor", ] ) diff --git a/src/proto/grpc/testing/proto2/BUILD.bazel b/src/proto/grpc/testing/proto2/BUILD.bazel index c4c4f004efb..e939c523a64 100644 --- a/src/proto/grpc/testing/proto2/BUILD.bazel +++ b/src/proto/grpc/testing/proto2/BUILD.bazel @@ -1,30 +1,32 @@ load("@grpc_python_dependencies//:requirements.bzl", "requirement") -load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library") package(default_visibility = ["//visibility:public"]) +load("//bazel:python_rules.bzl", "py_proto_library") + +proto_library( + name = "empty2_proto_descriptor", + srcs = ["empty2.proto"], +) py_proto_library( name = "empty2_proto", - protos = [ - "empty2.proto", - ], - with_grpc = True, deps = [ - requirement('protobuf'), + ":empty2_proto_descriptor", ], ) +proto_library( + name = "empty2_extensions_proto_descriptor", + srcs = ["empty2_extensions.proto"], + deps = [ + ":empty2_proto_descriptor", + ] +) + py_proto_library( name = "empty2_extensions_proto", - protos = [ - "empty2_extensions.proto", - ], - proto_deps = [ - ":empty2_proto", - ], - with_grpc = True, deps = [ - requirement('protobuf'), + ":empty2_extensions_proto_descriptor", ], ) diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py index 1272ee802bc..f566fd698ad 100644 --- a/src/python/grpcio/grpc/_channel.py +++ b/src/python/grpcio/grpc/_channel.py @@ -1000,6 +1000,11 @@ def _unsubscribe(state, callback): break +def _unsubscribe_all(state): + with state.lock: + del state.callbacks_and_connectivities[:] + + def _augment_options(base_options, compression): compression_option = _compression.create_channel_option(compression) return tuple(base_options) + compression_option + (( @@ -1067,6 +1072,7 @@ class Channel(grpc.Channel): _common.encode(method), request_serializer, response_deserializer) def _close(self): + _unsubscribe_all(self._connectivity_state) self._channel.close(cygrpc.StatusCode.cancelled, 'Channel closed!') cygrpc.fork_unregister_channel(self) _moot(self._connectivity_state) diff --git a/src/python/grpcio/grpc/_grpcio_metadata.py b/src/python/grpcio/grpc/_grpcio_metadata.py index 651f8f778f2..9f7ca9d5603 100644 --- a/src/python/grpcio/grpc/_grpcio_metadata.py +++ b/src/python/grpcio/grpc/_grpcio_metadata.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!! -__version__ = """1.21.0.dev0""" +__version__ = """1.22.0.dev0""" diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 12a47e71d7e..2619ccf9740 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -19,7 +19,6 @@ CORE_SOURCE_FILES = [ 'third_party/address_sorting/address_sorting_posix.c', 'third_party/address_sorting/address_sorting_windows.c', 'src/core/lib/gpr/alloc.cc', - 'src/core/lib/gpr/arena.cc', 'src/core/lib/gpr/atm.cc', 'src/core/lib/gpr/cpu_iphone.cc', 'src/core/lib/gpr/cpu_linux.cc', @@ -52,7 +51,9 @@ CORE_SOURCE_FILES = [ 'src/core/lib/gpr/tmpfile_posix.cc', 'src/core/lib/gpr/tmpfile_windows.cc', 'src/core/lib/gpr/wrap_memcpy.cc', + 'src/core/lib/gprpp/arena.cc', 'src/core/lib/gprpp/fork.cc', + 'src/core/lib/gprpp/global_config_env.cc', 'src/core/lib/gprpp/thd_posix.cc', 'src/core/lib/gprpp/thd_windows.cc', 'src/core/lib/profiling/basic_timers.cc', @@ -84,12 +85,15 @@ CORE_SOURCE_FILES = [ 'src/core/lib/http/parser.cc', 'src/core/lib/iomgr/buffer_list.cc', 'src/core/lib/iomgr/call_combiner.cc', + 'src/core/lib/iomgr/cfstream_handle.cc', 'src/core/lib/iomgr/combiner.cc', 'src/core/lib/iomgr/endpoint.cc', + 'src/core/lib/iomgr/endpoint_cfstream.cc', 'src/core/lib/iomgr/endpoint_pair_posix.cc', 'src/core/lib/iomgr/endpoint_pair_uv.cc', 'src/core/lib/iomgr/endpoint_pair_windows.cc', 'src/core/lib/iomgr/error.cc', + 'src/core/lib/iomgr/error_cfstream.cc', 'src/core/lib/iomgr/ev_epoll1_linux.cc', 'src/core/lib/iomgr/ev_epollex_linux.cc', 'src/core/lib/iomgr/ev_poll_posix.cc', @@ -110,6 +114,7 @@ CORE_SOURCE_FILES = [ 'src/core/lib/iomgr/iomgr_custom.cc', 'src/core/lib/iomgr/iomgr_internal.cc', 'src/core/lib/iomgr/iomgr_posix.cc', + 'src/core/lib/iomgr/iomgr_posix_cfstream.cc', 'src/core/lib/iomgr/iomgr_uv.cc', 'src/core/lib/iomgr/iomgr_windows.cc', 'src/core/lib/iomgr/is_epollexclusive_available.cc', @@ -138,6 +143,7 @@ CORE_SOURCE_FILES = [ 'src/core/lib/iomgr/socket_utils_windows.cc', 'src/core/lib/iomgr/socket_windows.cc', 'src/core/lib/iomgr/tcp_client.cc', + 'src/core/lib/iomgr/tcp_client_cfstream.cc', 'src/core/lib/iomgr/tcp_client_custom.cc', 'src/core/lib/iomgr/tcp_client_posix.cc', 'src/core/lib/iomgr/tcp_client_windows.cc', @@ -371,12 +377,15 @@ CORE_SOURCE_FILES = [ 'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc', + 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc', + 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', + 'src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc', 'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', 'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', 'src/core/ext/filters/census/grpc_context.cc', diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py index e430cc20a6d..971fd37afb6 100644 --- a/src/python/grpcio/grpc_version.py +++ b/src/python/grpcio/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!! -VERSION = '1.21.0.dev0' +VERSION = '1.22.0.dev0' diff --git a/src/python/grpcio_channelz/grpc_channelz/v1/BUILD.bazel b/src/python/grpcio_channelz/grpc_channelz/v1/BUILD.bazel index aae8cedb760..eccc166577d 100644 --- a/src/python/grpcio_channelz/grpc_channelz/v1/BUILD.bazel +++ b/src/python/grpcio_channelz/grpc_channelz/v1/BUILD.bazel @@ -1,30 +1,10 @@ -load("@grpc_python_dependencies//:requirements.bzl", "requirement") -load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library") - +load("//bazel:python_rules.bzl", "py_proto_library") package(default_visibility = ["//visibility:public"]) -genrule( - name = "mv_channelz_proto", - srcs = [ - "//src/proto/grpc/channelz:channelz_proto_file", - ], - outs = ["channelz.proto",], - cmd = "cp $< $@", -) - py_proto_library( name = "py_channelz_proto", - protos = ["mv_channelz_proto",], - imports = [ - "external/com_google_protobuf/src/", - ], - inputs = [ - "@com_google_protobuf//:well_known_protos", - ], - with_grpc = True, - deps = [ - requirement('protobuf'), - ], + well_known_protos = True, + deps = ["//src/proto/grpc/channelz:channelz_proto_descriptors"], ) py_library( diff --git a/src/python/grpcio_channelz/grpc_version.py b/src/python/grpcio_channelz/grpc_version.py index d716b953f4b..52baab4c30f 100644 --- a/src/python/grpcio_channelz/grpc_version.py +++ b/src/python/grpcio_channelz/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_channelz/grpc_version.py.template`!!! -VERSION = '1.21.0.dev0' +VERSION = '1.22.0.dev0' diff --git a/src/python/grpcio_health_checking/grpc_health/v1/BUILD.bazel b/src/python/grpcio_health_checking/grpc_health/v1/BUILD.bazel index ce3121fa90e..9e4fff34581 100644 --- a/src/python/grpcio_health_checking/grpc_health/v1/BUILD.bazel +++ b/src/python/grpcio_health_checking/grpc_health/v1/BUILD.bazel @@ -1,24 +1,9 @@ -load("@grpc_python_dependencies//:requirements.bzl", "requirement") -load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library") - +load("//bazel:python_rules.bzl", "py_proto_library") package(default_visibility = ["//visibility:public"]) -genrule( - name = "mv_health_proto", - srcs = [ - "//src/proto/grpc/health/v1:health_proto_file", - ], - outs = ["health.proto",], - cmd = "cp $< $@", -) - py_proto_library( name = "py_health_proto", - protos = [":mv_health_proto",], - with_grpc = True, - deps = [ - requirement('protobuf'), - ], + deps = ["//src/proto/grpc/health/v1:health_proto_descriptor",], ) py_library( diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py index 2bb47aaf133..be4ca841361 100644 --- a/src/python/grpcio_health_checking/grpc_version.py +++ b/src/python/grpcio_health_checking/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!! -VERSION = '1.21.0.dev0' +VERSION = '1.22.0.dev0' diff --git a/src/python/grpcio_reflection/grpc_reflection/v1alpha/BUILD.bazel b/src/python/grpcio_reflection/grpc_reflection/v1alpha/BUILD.bazel index 3a2ba263715..6aaa4dd3bdd 100644 --- a/src/python/grpcio_reflection/grpc_reflection/v1alpha/BUILD.bazel +++ b/src/python/grpcio_reflection/grpc_reflection/v1alpha/BUILD.bazel @@ -1,24 +1,11 @@ +load("//bazel:python_rules.bzl", "py_proto_library") load("@grpc_python_dependencies//:requirements.bzl", "requirement") -load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library") package(default_visibility = ["//visibility:public"]) -genrule( - name = "mv_reflection_proto", - srcs = [ - "//src/proto/grpc/reflection/v1alpha:reflection_proto_file", - ], - outs = ["reflection.proto",], - cmd = "cp $< $@", -) - py_proto_library( name = "py_reflection_proto", - protos = [":mv_reflection_proto",], - with_grpc = True, - deps = [ - requirement('protobuf'), - ], + deps = ["//src/proto/grpc/reflection/v1alpha:reflection_proto_descriptor",], ) py_library( diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py index e1c4f3df694..1efc4ee2c8d 100644 --- a/src/python/grpcio_reflection/grpc_version.py +++ b/src/python/grpcio_reflection/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!! -VERSION = '1.21.0.dev0' +VERSION = '1.22.0.dev0' diff --git a/src/python/grpcio_status/grpc_version.py b/src/python/grpcio_status/grpc_version.py index b484a7ba478..9e443087755 100644 --- a/src/python/grpcio_status/grpc_version.py +++ b/src/python/grpcio_status/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_status/grpc_version.py.template`!!! -VERSION = '1.21.0.dev0' +VERSION = '1.22.0.dev0' diff --git a/src/python/grpcio_testing/grpc_version.py b/src/python/grpcio_testing/grpc_version.py index 21981ee79d2..18d17e40464 100644 --- a/src/python/grpcio_testing/grpc_version.py +++ b/src/python/grpcio_testing/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_testing/grpc_version.py.template`!!! -VERSION = '1.21.0.dev0' +VERSION = '1.22.0.dev0' diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py index 8ce4fdb627d..401b0bd9697 100644 --- a/src/python/grpcio_tests/grpc_version.py +++ b/src/python/grpcio_tests/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!! -VERSION = '1.21.0.dev0' +VERSION = '1.22.0.dev0' diff --git a/src/python/grpcio_tests/tests/fork/_fork_interop_test.py b/src/python/grpcio_tests/tests/fork/_fork_interop_test.py index 608148dfe46..602786c5e0d 100644 --- a/src/python/grpcio_tests/tests/fork/_fork_interop_test.py +++ b/src/python/grpcio_tests/tests/fork/_fork_interop_test.py @@ -56,12 +56,12 @@ class ForkInteropTest(unittest.TestCase): import grpc from src.proto.grpc.testing import test_pb2_grpc - from tests.interop import methods as interop_methods + from tests.interop import service as interop_service from tests.unit import test_common server = test_common.test_server() test_pb2_grpc.add_TestServiceServicer_to_server( - interop_methods.TestService(), server) + interop_service.TestService(), server) port = server.add_insecure_port('[::]:0') server.start() print(port) diff --git a/src/python/grpcio_tests/tests/health_check/_health_servicer_test.py b/src/python/grpcio_tests/tests/health_check/_health_servicer_test.py index 1098d38c83e..7a332b8390f 100644 --- a/src/python/grpcio_tests/tests/health_check/_health_servicer_test.py +++ b/src/python/grpcio_tests/tests/health_check/_health_servicer_test.py @@ -246,7 +246,7 @@ class HealthServicerTest(BaseWatchTests.WatchTests): resp = self._stub.Check(request) self.assertEqual(health_pb2.HealthCheckResponse.SERVING, resp.status) - def test_check_unknown_serivce(self): + def test_check_unknown_service(self): request = health_pb2.HealthCheckRequest(service=_UNKNOWN_SERVICE) resp = self._stub.Check(request) self.assertEqual(health_pb2.HealthCheckResponse.UNKNOWN, resp.status) diff --git a/src/python/grpcio_tests/tests/interop/BUILD.bazel b/src/python/grpcio_tests/tests/interop/BUILD.bazel index 770b1f78a70..fd636556074 100644 --- a/src/python/grpcio_tests/tests/interop/BUILD.bazel +++ b/src/python/grpcio_tests/tests/interop/BUILD.bazel @@ -5,45 +5,45 @@ package(default_visibility = ["//visibility:public"]) py_library( name = "_intraop_test_case", srcs = ["_intraop_test_case.py"], + imports = ["../../"], deps = [ ":methods", ], - imports=["../../",], ) py_library( name = "client", srcs = ["client.py"], + imports = ["../../"], deps = [ - "//src/python/grpcio/grpc:grpcio", ":methods", ":resources", "//src/proto/grpc/testing:py_test_proto", - requirement('google-auth'), + "//src/python/grpcio/grpc:grpcio", + requirement("google-auth"), ], - imports=["../../",], ) py_library( name = "methods", srcs = ["methods.py"], + imports = ["../../"], deps = [ "//src/python/grpcio/grpc:grpcio", "//src/python/grpcio_tests/tests:bazel_namespace_package_hack", "//src/proto/grpc/testing:py_empty_proto", "//src/proto/grpc/testing:py_messages_proto", "//src/proto/grpc/testing:py_test_proto", - requirement('google-auth'), - requirement('requests'), - requirement('urllib3'), - requirement('chardet'), - requirement('certifi'), - requirement('idna'), + requirement("google-auth"), + requirement("requests"), + requirement("urllib3"), + requirement("chardet"), + requirement("certifi"), + requirement("idna"), ] + select({ - "//conditions:default": [requirement('enum34'),], + "//conditions:default": [requirement("enum34")], "//:python3": [], }), - imports=["../../",], ) py_library( @@ -54,51 +54,62 @@ py_library( ], ) +py_library( + name = "service", + srcs = ["service.py"], + imports = ["../../"], + deps = [ + "//src/proto/grpc/testing:py_empty_proto", + "//src/proto/grpc/testing:py_messages_proto", + "//src/proto/grpc/testing:py_test_proto", + "//src/python/grpcio/grpc:grpcio", + ], +) + py_library( name = "server", srcs = ["server.py"], + imports = ["../../"], deps = [ - "//src/python/grpcio/grpc:grpcio", - ":methods", ":resources", - "//src/python/grpcio_tests/tests/unit:test_common", + ":service", "//src/proto/grpc/testing:py_test_proto", + "//src/python/grpcio/grpc:grpcio", + "//src/python/grpcio_tests/tests/unit:test_common", ], - imports=["../../",], ) py_test( - name="_insecure_intraop_test", - size="small", - srcs=["_insecure_intraop_test.py",], - main="_insecure_intraop_test.py", - deps=[ - "//src/python/grpcio/grpc:grpcio", + name = "_insecure_intraop_test", + size = "small", + srcs = ["_insecure_intraop_test.py"], + data = [ + "//src/python/grpcio_tests/tests/unit/credentials", + ], + imports = ["../../"], + main = "_insecure_intraop_test.py", + deps = [ ":_intraop_test_case", - ":methods", ":server", - "//src/python/grpcio_tests/tests/unit:test_common", + ":service", "//src/proto/grpc/testing:py_test_proto", - ], - imports=["../../",], - data=[ - "//src/python/grpcio_tests/tests/unit/credentials", + "//src/python/grpcio/grpc:grpcio", + "//src/python/grpcio_tests/tests/unit:test_common", ], ) py_test( - name="_secure_intraop_test", - size="small", - srcs=["_secure_intraop_test.py",], - main="_secure_intraop_test.py", - deps=[ - "//src/python/grpcio/grpc:grpcio", + name = "_secure_intraop_test", + size = "small", + srcs = ["_secure_intraop_test.py"], + imports = ["../../"], + main = "_secure_intraop_test.py", + deps = [ ":_intraop_test_case", - ":methods", ":server", - "//src/python/grpcio_tests/tests/unit:test_common", + ":service", "//src/proto/grpc/testing:py_test_proto", + "//src/python/grpcio/grpc:grpcio", + "//src/python/grpcio_tests/tests/unit:test_common", ], - imports=["../../",], ) - diff --git a/src/python/grpcio_tests/tests/interop/_insecure_intraop_test.py b/src/python/grpcio_tests/tests/interop/_insecure_intraop_test.py index ace15bea585..fecf31767a7 100644 --- a/src/python/grpcio_tests/tests/interop/_insecure_intraop_test.py +++ b/src/python/grpcio_tests/tests/interop/_insecure_intraop_test.py @@ -19,7 +19,7 @@ import grpc from src.proto.grpc.testing import test_pb2_grpc from tests.interop import _intraop_test_case -from tests.interop import methods +from tests.interop import service from tests.interop import server from tests.unit import test_common @@ -29,7 +29,7 @@ class InsecureIntraopTest(_intraop_test_case.IntraopTestCase, def setUp(self): self.server = test_common.test_server() - test_pb2_grpc.add_TestServiceServicer_to_server(methods.TestService(), + test_pb2_grpc.add_TestServiceServicer_to_server(service.TestService(), self.server) port = self.server.add_insecure_port('[::]:0') self.server.start() diff --git a/src/python/grpcio_tests/tests/interop/_secure_intraop_test.py b/src/python/grpcio_tests/tests/interop/_secure_intraop_test.py index e27e551ecb0..1b5e5cfd2dd 100644 --- a/src/python/grpcio_tests/tests/interop/_secure_intraop_test.py +++ b/src/python/grpcio_tests/tests/interop/_secure_intraop_test.py @@ -19,7 +19,7 @@ import grpc from src.proto.grpc.testing import test_pb2_grpc from tests.interop import _intraop_test_case -from tests.interop import methods +from tests.interop import service from tests.interop import resources from tests.unit import test_common @@ -30,7 +30,7 @@ class SecureIntraopTest(_intraop_test_case.IntraopTestCase, unittest.TestCase): def setUp(self): self.server = test_common.test_server() - test_pb2_grpc.add_TestServiceServicer_to_server(methods.TestService(), + test_pb2_grpc.add_TestServiceServicer_to_server(service.TestService(), self.server) port = self.server.add_secure_port( '[::]:0', diff --git a/src/python/grpcio_tests/tests/interop/methods.py b/src/python/grpcio_tests/tests/interop/methods.py index 40341ca091b..250db8bb385 100644 --- a/src/python/grpcio_tests/tests/interop/methods.py +++ b/src/python/grpcio_tests/tests/interop/methods.py @@ -25,6 +25,7 @@ import enum import json import os import threading +import time from google import auth as google_auth from google.auth import environment_vars as google_auth_environment_vars @@ -34,78 +35,11 @@ import grpc from src.proto.grpc.testing import empty_pb2 from src.proto.grpc.testing import messages_pb2 -from src.proto.grpc.testing import test_pb2_grpc _INITIAL_METADATA_KEY = "x-grpc-test-echo-initial" _TRAILING_METADATA_KEY = "x-grpc-test-echo-trailing-bin" -def _maybe_echo_metadata(servicer_context): - """Copies metadata from request to response if it is present.""" - invocation_metadata = dict(servicer_context.invocation_metadata()) - if _INITIAL_METADATA_KEY in invocation_metadata: - initial_metadatum = (_INITIAL_METADATA_KEY, - invocation_metadata[_INITIAL_METADATA_KEY]) - servicer_context.send_initial_metadata((initial_metadatum,)) - if _TRAILING_METADATA_KEY in invocation_metadata: - trailing_metadatum = (_TRAILING_METADATA_KEY, - invocation_metadata[_TRAILING_METADATA_KEY]) - servicer_context.set_trailing_metadata((trailing_metadatum,)) - - -def _maybe_echo_status_and_message(request, servicer_context): - """Sets the response context code and details if the request asks for them""" - if request.HasField('response_status'): - servicer_context.set_code(request.response_status.code) - servicer_context.set_details(request.response_status.message) - - -class TestService(test_pb2_grpc.TestServiceServicer): - - def EmptyCall(self, request, context): - _maybe_echo_metadata(context) - return empty_pb2.Empty() - - def UnaryCall(self, request, context): - _maybe_echo_metadata(context) - _maybe_echo_status_and_message(request, context) - return messages_pb2.SimpleResponse( - payload=messages_pb2.Payload( - type=messages_pb2.COMPRESSABLE, - body=b'\x00' * request.response_size)) - - def StreamingOutputCall(self, request, context): - _maybe_echo_status_and_message(request, context) - for response_parameters in request.response_parameters: - yield messages_pb2.StreamingOutputCallResponse( - payload=messages_pb2.Payload( - type=request.response_type, - body=b'\x00' * response_parameters.size)) - - def StreamingInputCall(self, request_iterator, context): - aggregate_size = 0 - for request in request_iterator: - if request.payload is not None and request.payload.body: - aggregate_size += len(request.payload.body) - return messages_pb2.StreamingInputCallResponse( - aggregated_payload_size=aggregate_size) - - def FullDuplexCall(self, request_iterator, context): - _maybe_echo_metadata(context) - for request in request_iterator: - _maybe_echo_status_and_message(request, context) - for response_parameters in request.response_parameters: - yield messages_pb2.StreamingOutputCallResponse( - payload=messages_pb2.Payload( - type=request.payload.type, - body=b'\x00' * response_parameters.size)) - - # NOTE(nathaniel): Apparently this is the same as the full-duplex call? - # NOTE(atash): It isn't even called in the interop spec (Oct 22 2015)... - def HalfDuplexCall(self, request_iterator, context): - return self.FullDuplexCall(request_iterator, context) - - def _expect_status_code(call, expected_code): if call.code() != expected_code: raise ValueError('expected code %s, got %s' % (expected_code, diff --git a/src/python/grpcio_tests/tests/interop/server.py b/src/python/grpcio_tests/tests/interop/server.py index 72f88a1c989..3611ffdbb2f 100644 --- a/src/python/grpcio_tests/tests/interop/server.py +++ b/src/python/grpcio_tests/tests/interop/server.py @@ -21,7 +21,7 @@ import time import grpc from src.proto.grpc.testing import test_pb2_grpc -from tests.interop import methods +from tests.interop import service from tests.interop import resources from tests.unit import test_common @@ -42,7 +42,7 @@ def serve(): args = parser.parse_args() server = test_common.test_server() - test_pb2_grpc.add_TestServiceServicer_to_server(methods.TestService(), + test_pb2_grpc.add_TestServiceServicer_to_server(service.TestService(), server) if args.use_tls: private_key = resources.private_key() diff --git a/src/python/grpcio_tests/tests/interop/service.py b/src/python/grpcio_tests/tests/interop/service.py new file mode 100644 index 00000000000..37e4404c141 --- /dev/null +++ b/src/python/grpcio_tests/tests/interop/service.py @@ -0,0 +1,97 @@ +# Copyright 2019 The gRPC Authors +# +# 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. +"""The Python implementation of the TestServicer.""" + +import time + +import grpc + +from src.proto.grpc.testing import empty_pb2 +from src.proto.grpc.testing import messages_pb2 +from src.proto.grpc.testing import test_pb2_grpc + +_INITIAL_METADATA_KEY = "x-grpc-test-echo-initial" +_TRAILING_METADATA_KEY = "x-grpc-test-echo-trailing-bin" +_US_IN_A_SECOND = 1000 * 1000 + + +def _maybe_echo_metadata(servicer_context): + """Copies metadata from request to response if it is present.""" + invocation_metadata = dict(servicer_context.invocation_metadata()) + if _INITIAL_METADATA_KEY in invocation_metadata: + initial_metadatum = (_INITIAL_METADATA_KEY, + invocation_metadata[_INITIAL_METADATA_KEY]) + servicer_context.send_initial_metadata((initial_metadatum,)) + if _TRAILING_METADATA_KEY in invocation_metadata: + trailing_metadatum = (_TRAILING_METADATA_KEY, + invocation_metadata[_TRAILING_METADATA_KEY]) + servicer_context.set_trailing_metadata((trailing_metadatum,)) + + +def _maybe_echo_status_and_message(request, servicer_context): + """Sets the response context code and details if the request asks for them""" + if request.HasField('response_status'): + servicer_context.set_code(request.response_status.code) + servicer_context.set_details(request.response_status.message) + + +class TestService(test_pb2_grpc.TestServiceServicer): + + def EmptyCall(self, request, context): + _maybe_echo_metadata(context) + return empty_pb2.Empty() + + def UnaryCall(self, request, context): + _maybe_echo_metadata(context) + _maybe_echo_status_and_message(request, context) + return messages_pb2.SimpleResponse( + payload=messages_pb2.Payload( + type=messages_pb2.COMPRESSABLE, + body=b'\x00' * request.response_size)) + + def StreamingOutputCall(self, request, context): + _maybe_echo_status_and_message(request, context) + for response_parameters in request.response_parameters: + if response_parameters.interval_us != 0: + time.sleep(response_parameters.interval_us / _US_IN_A_SECOND) + yield messages_pb2.StreamingOutputCallResponse( + payload=messages_pb2.Payload( + type=request.response_type, + body=b'\x00' * response_parameters.size)) + + def StreamingInputCall(self, request_iterator, context): + aggregate_size = 0 + for request in request_iterator: + if request.payload is not None and request.payload.body: + aggregate_size += len(request.payload.body) + return messages_pb2.StreamingInputCallResponse( + aggregated_payload_size=aggregate_size) + + def FullDuplexCall(self, request_iterator, context): + _maybe_echo_metadata(context) + for request in request_iterator: + _maybe_echo_status_and_message(request, context) + for response_parameters in request.response_parameters: + if response_parameters.interval_us != 0: + time.sleep( + response_parameters.interval_us / _US_IN_A_SECOND) + yield messages_pb2.StreamingOutputCallResponse( + payload=messages_pb2.Payload( + type=request.payload.type, + body=b'\x00' * response_parameters.size)) + + # NOTE(nathaniel): Apparently this is the same as the full-duplex call? + # NOTE(atash): It isn't even called in the interop spec (Oct 22 2015)... + def HalfDuplexCall(self, request_iterator, context): + return self.FullDuplexCall(request_iterator, context) diff --git a/src/python/grpcio_tests/tests/reflection/BUILD.bazel b/src/python/grpcio_tests/tests/reflection/BUILD.bazel index c0efb0b7cef..b635b721631 100644 --- a/src/python/grpcio_tests/tests/reflection/BUILD.bazel +++ b/src/python/grpcio_tests/tests/reflection/BUILD.bazel @@ -14,6 +14,7 @@ py_test( "//src/python/grpcio_tests/tests/unit:test_common", "//src/proto/grpc/testing:py_empty_proto", "//src/proto/grpc/testing/proto2:empty2_extensions_proto", + "//src/proto/grpc/testing/proto2:empty2_proto", requirement('protobuf'), ], imports=["../../",], diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index 275ca6e9cbf..c25d789a95b 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -440,7 +440,7 @@ extern grpc_local_credentials_create_type grpc_local_credentials_create_import; typedef grpc_server_credentials*(*grpc_local_server_credentials_create_type)(grpc_local_connect_type type); extern grpc_local_server_credentials_create_type grpc_local_server_credentials_create_import; #define grpc_local_server_credentials_create grpc_local_server_credentials_create_import -typedef grpc_tls_credentials_options*(*grpc_tls_credentials_options_create_type)(); +typedef grpc_tls_credentials_options*(*grpc_tls_credentials_options_create_type)(void); extern grpc_tls_credentials_options_create_type grpc_tls_credentials_options_create_import; #define grpc_tls_credentials_options_create grpc_tls_credentials_options_create_import typedef int(*grpc_tls_credentials_options_set_cert_request_type_type)(grpc_tls_credentials_options* options, grpc_ssl_client_certificate_request_type type); @@ -455,7 +455,7 @@ extern grpc_tls_credentials_options_set_credential_reload_config_type grpc_tls_c typedef int(*grpc_tls_credentials_options_set_server_authorization_check_config_type)(grpc_tls_credentials_options* options, grpc_tls_server_authorization_check_config* config); extern grpc_tls_credentials_options_set_server_authorization_check_config_type grpc_tls_credentials_options_set_server_authorization_check_config_import; #define grpc_tls_credentials_options_set_server_authorization_check_config grpc_tls_credentials_options_set_server_authorization_check_config_import -typedef grpc_tls_key_materials_config*(*grpc_tls_key_materials_config_create_type)(); +typedef grpc_tls_key_materials_config*(*grpc_tls_key_materials_config_create_type)(void); extern grpc_tls_key_materials_config_create_type grpc_tls_key_materials_config_create_import; #define grpc_tls_key_materials_config_create grpc_tls_key_materials_config_create_import typedef int(*grpc_tls_key_materials_config_set_key_materials_type)(grpc_tls_key_materials_config* config, const char* pem_root_certs, const grpc_ssl_pem_key_cert_pair** pem_key_cert_pairs, size_t num_key_cert_pairs); diff --git a/src/ruby/lib/grpc/errors.rb b/src/ruby/lib/grpc/errors.rb index 0c15c2f3bac..0b27bee1b9c 100644 --- a/src/ruby/lib/grpc/errors.rb +++ b/src/ruby/lib/grpc/errors.rb @@ -42,12 +42,31 @@ module GRPC @metadata = metadata end - # Converts the exception to a GRPC::Status for use in the networking + # Converts the exception to a {Struct::Status} for use in the networking # wrapper layer. # - # @return [Status] with the same code and details + # @return [Struct::Status] with the same code and details def to_status - Struct::Status.new(code, details, @metadata) + Struct::Status.new(code, details, metadata) + end + + # Converts the exception to a deserialized {Google::Rpc::Status} object. + # Returns `nil` if the `grpc-status-details-bin` trailer could not be + # converted to a {Google::Rpc::Status} due to the server not providing + # the necessary trailers. + # + # @return [Google::Rpc::Status, nil] + def to_rpc_status + # Lazily require google_rpc_status_utils to scope + # loading protobuf_c.so to the users of this method. + require_relative './google_rpc_status_utils' + status = to_status + return if status.nil? + GoogleRpcStatusUtils.extract_google_rpc_status(status) + rescue Google::Protobuf::ParseError => parse_error + GRPC.logger.warn('parse error: to_rpc_status failed') + GRPC.logger.warn(parse_error) + nil end def self.new_status_exception(code, details = 'unknown cause', diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb index cca795b64ec..75e6191216d 100644 --- a/src/ruby/lib/grpc/version.rb +++ b/src/ruby/lib/grpc/version.rb @@ -14,5 +14,5 @@ # GRPC contains the General RPC module. module GRPC - VERSION = '1.21.0.dev' + VERSION = '1.22.0.dev' end diff --git a/src/ruby/spec/errors_spec.rb b/src/ruby/spec/errors_spec.rb new file mode 100644 index 00000000000..bf27a537405 --- /dev/null +++ b/src/ruby/spec/errors_spec.rb @@ -0,0 +1,141 @@ +# Copyright 2015 gRPC authors. +# +# 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. + +require 'spec_helper' +require 'google/protobuf/well_known_types' +require_relative '../pb/src/proto/grpc/testing/messages_pb' + +describe GRPC::BadStatus do + describe :attributes do + it 'has attributes' do + code = 1 + details = 'details' + metadata = { 'key' => 'val' } + + exception = GRPC::BadStatus.new(code, details, metadata) + + expect(exception.code).to eq code + expect(exception.details).to eq details + expect(exception.metadata).to eq metadata + end + end + + describe :new_status_exception do + let(:codes_and_classes) do + [ + [GRPC::Core::StatusCodes::OK, GRPC::Ok], + [GRPC::Core::StatusCodes::CANCELLED, GRPC::Cancelled], + [GRPC::Core::StatusCodes::UNKNOWN, GRPC::Unknown], + [GRPC::Core::StatusCodes::INVALID_ARGUMENT, GRPC::InvalidArgument], + [GRPC::Core::StatusCodes::DEADLINE_EXCEEDED, GRPC::DeadlineExceeded], + [GRPC::Core::StatusCodes::NOT_FOUND, GRPC::NotFound], + [GRPC::Core::StatusCodes::ALREADY_EXISTS, GRPC::AlreadyExists], + [GRPC::Core::StatusCodes::PERMISSION_DENIED, GRPC::PermissionDenied], + [GRPC::Core::StatusCodes::UNAUTHENTICATED, GRPC::Unauthenticated], + [GRPC::Core::StatusCodes::RESOURCE_EXHAUSTED, GRPC::ResourceExhausted], + [GRPC::Core::StatusCodes::FAILED_PRECONDITION, GRPC::FailedPrecondition], + [GRPC::Core::StatusCodes::ABORTED, GRPC::Aborted], + [GRPC::Core::StatusCodes::OUT_OF_RANGE, GRPC::OutOfRange], + [GRPC::Core::StatusCodes::UNIMPLEMENTED, GRPC::Unimplemented], + [GRPC::Core::StatusCodes::INTERNAL, GRPC::Internal], + [GRPC::Core::StatusCodes::UNAVAILABLE, GRPC::Unavailable], + [GRPC::Core::StatusCodes::DATA_LOSS, GRPC::DataLoss], + [99, GRPC::BadStatus] # Unknown codes default to BadStatus + ] + end + + it 'maps codes to the correct error class' do + codes_and_classes.each do |code, grpc_error_class| + exception = GRPC::BadStatus.new_status_exception(code) + + expect(exception).to be_a grpc_error_class + end + end + end + + describe :to_status do + it 'gets status' do + code = 1 + details = 'details' + metadata = { 'key' => 'val' } + + exception = GRPC::BadStatus.new(code, details, metadata) + status = Struct::Status.new(code, details, metadata) + + expect(exception.to_status).to eq status + end + end + + describe :to_rpc_status do + let(:simple_request_any) do + Google::Protobuf::Any.new.tap do |any| + any.pack( + Grpc::Testing::SimpleRequest.new( + payload: Grpc::Testing::Payload.new(body: 'request') + ) + ) + end + end + let(:simple_response_any) do + Google::Protobuf::Any.new.tap do |any| + any.pack( + Grpc::Testing::SimpleResponse.new( + payload: Grpc::Testing::Payload.new(body: 'response') + ) + ) + end + end + let(:payload_any) do + Google::Protobuf::Any.new.tap do |any| + any.pack(Grpc::Testing::Payload.new(body: 'payload')) + end + end + + it 'decodes proto values' do + rpc_status = Google::Rpc::Status.new( + code: 1, + message: 'matching message', + details: [simple_request_any, simple_response_any, payload_any] + ) + rpc_status_proto = Google::Rpc::Status.encode(rpc_status) + + code = 1 + details = 'details' + metadata = { 'grpc-status-details-bin' => rpc_status_proto } + + exception = GRPC::BadStatus.new(code, details, metadata) + + expect(exception.to_rpc_status).to eq rpc_status + end + + it 'does not raise when decoding a bad proto' do + code = 1 + details = 'details' + metadata = { 'grpc-status-details-bin' => 'notavalidprotostream' } + + exception = GRPC::BadStatus.new(code, details, metadata) + + expect(exception.to_rpc_status).to be nil + + error_msg = 'parse error: to_rpc_status failed' + error_desc = ' ' \ + 'Error occurred during parsing: Invalid wire type' + + # Check that the parse error was logged correctly + log_contents = @log_output.read + expect(log_contents).to include "WARN GRPC : #{error_msg}" + expect(log_contents).to include "WARN GRPC : #{error_desc}" + end + end +end diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb index 5604e215b58..fbd0041fa35 100644 --- a/src/ruby/tools/version.rb +++ b/src/ruby/tools/version.rb @@ -14,6 +14,6 @@ module GRPC module Tools - VERSION = '1.21.0.dev' + VERSION = '1.22.0.dev' end end diff --git a/templates/gRPC-C++.podspec.template b/templates/gRPC-C++.podspec.template index 43cb6db66c6..40368e422d9 100644 --- a/templates/gRPC-C++.podspec.template +++ b/templates/gRPC-C++.podspec.template @@ -140,7 +140,7 @@ s.name = 'gRPC-C++' # TODO (mxyan): use version that match gRPC version when pod is stabilized # version = '${settings.version}' - version = '${modify_podspec_version_string('0.0.8', settings.version)}' + version = '${modify_podspec_version_string('0.0.9', settings.version)}' s.version = version s.summary = 'gRPC C++ library' s.homepage = 'https://grpc.io' @@ -188,7 +188,7 @@ s.default_subspecs = 'Interface', 'Implementation' # Certificates, to be able to establish TLS connections: - s.resource_bundles = { 'gRPCCertificates' => ['etc/roots.pem'] } + s.resource_bundles = { 'gRPCCertificates-Cpp' => ['etc/roots.pem'] } s.header_mappings_dir = 'include/grpcpp' diff --git a/templates/gRPC-Core.podspec.template b/templates/gRPC-Core.podspec.template index 93939735c56..89a1e9188ff 100644 --- a/templates/gRPC-Core.podspec.template +++ b/templates/gRPC-Core.podspec.template @@ -70,14 +70,6 @@ excl = grpc_private_files(libs) return [file for file in out if not file in excl] - def cfstream_private_headers(libs): - out = grpc_lib_files(libs, ("grpc_cfstream",), ("own_headers",)) - return out - - def cfstream_private_files(libs): - out = grpc_lib_files(libs, ("grpc_cfstream",), ("own_src", "own_headers")) - return out - def ruby_multiline_list(files, indent): return (',\n' + indent*' ').join('\'%s\'' % f for f in files) %> @@ -183,9 +175,9 @@ ss.compiler_flags = '-DGRPC_SHADOW_BORINGSSL_SYMBOLS' # To save you from scrolling, this is the last part of the podspec. - ss.source_files = ${ruby_multiline_list(grpc_private_files(libs) + cfstream_private_files(filegroups), 22)} + ss.source_files = ${ruby_multiline_list(grpc_private_files(libs), 22)} - ss.private_header_files = ${ruby_multiline_list(grpc_private_headers(libs) + cfstream_private_headers(filegroups), 30)} + ss.private_header_files = ${ruby_multiline_list(grpc_private_headers(libs), 30)} end # CFStream is now default. Leaving this subspec only for compatibility purpose. diff --git a/templates/src/csharp/Grpc.Core/Internal/native_methods.include b/templates/src/csharp/Grpc.Core/Internal/native_methods.include index e8ec4c87b06..4a31171aa27 100644 --- a/templates/src/csharp/Grpc.Core/Internal/native_methods.include +++ b/templates/src/csharp/Grpc.Core/Internal/native_methods.include @@ -6,7 +6,7 @@ native_method_signatures = [ 'BatchContextSafeHandle grpcsharp_batch_context_create()', 'IntPtr grpcsharp_batch_context_recv_initial_metadata(BatchContextSafeHandle ctx)', 'IntPtr grpcsharp_batch_context_recv_message_length(BatchContextSafeHandle ctx)', - 'void grpcsharp_batch_context_recv_message_to_buffer(BatchContextSafeHandle ctx, byte[] buffer, UIntPtr bufferLen)', + 'int grpcsharp_batch_context_recv_message_next_slice_peek(BatchContextSafeHandle ctx, out UIntPtr sliceLen, out IntPtr sliceDataPtr)', 'StatusCode grpcsharp_batch_context_recv_status_on_client_status(BatchContextSafeHandle ctx)', 'IntPtr grpcsharp_batch_context_recv_status_on_client_details(BatchContextSafeHandle ctx, out UIntPtr detailsLength)', 'IntPtr grpcsharp_batch_context_recv_status_on_client_trailing_metadata(BatchContextSafeHandle ctx)', diff --git a/templates/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec.template b/templates/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec.template index 5a416eb6471..741f9b7e54d 100644 --- a/templates/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec.template +++ b/templates/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec.template @@ -103,7 +103,7 @@ s.preserve_paths = plugin # Restrict the protoc version to the one supported by this plugin. - s.dependency '!ProtoCompiler', '3.6.1' + s.dependency '!ProtoCompiler', '3.7.0' # For the Protobuf dependency not to complain: s.ios.deployment_target = '7.0' s.osx.deployment_target = '10.9' diff --git a/templates/test/core/end2end/end2end_defs.include b/templates/test/core/end2end/end2end_defs.include index d40ba2065be..91fa1d9502a 100644 --- a/templates/test/core/end2end/end2end_defs.include +++ b/templates/test/core/end2end/end2end_defs.include @@ -27,7 +27,6 @@ #include -#include "test/core/util/debugger_macros.h" static bool g_pre_init_called = false; @@ -39,7 +38,6 @@ extern void ${test}_pre_init(void); void grpc_end2end_tests_pre_init(void) { GPR_ASSERT(!g_pre_init_called); g_pre_init_called = true; - grpc_summon_debugger_macros(); % for test in tests: ${test}_pre_init(); % endfor diff --git a/templates/tools/dockerfile/debian_jessie_header.include b/templates/tools/dockerfile/debian_jessie_header.include index 11bd5f9b129..f71f98626f3 100644 --- a/templates/tools/dockerfile/debian_jessie_header.include +++ b/templates/tools/dockerfile/debian_jessie_header.include @@ -1,2 +1 @@ FROM debian:jessie -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh.template b/templates/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh.template index 05ad947e944..55ecfb30192 100644 --- a/templates/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh.template +++ b/templates/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh.template @@ -38,8 +38,5 @@ then ln -s $(pwd)/.dotnet/dotnet /usr/local/bin/dotnet fi - - ./build/get-grpc.sh - cd testassets/InteropTestsWebsite - dotnet build --configuration Debug + dotnet build --configuration Debug Grpc.AspNetCore.sln diff --git a/test/core/bad_client/bad_client.cc b/test/core/bad_client/bad_client.cc index 6b492523219..26550a2a701 100644 --- a/test/core/bad_client/bad_client.cc +++ b/test/core/bad_client/bad_client.cc @@ -257,7 +257,7 @@ bool client_connection_preface_validator(grpc_slice_buffer* incoming, return false; } grpc_slice slice = incoming->slices[0]; - /* There should be atleast a settings frame present */ + /* There should be at least one settings frame present */ if (GRPC_SLICE_LENGTH(slice) < MIN_HTTP2_FRAME_SIZE) { return false; } diff --git a/test/core/bad_connection/close_fd_test.cc b/test/core/bad_connection/close_fd_test.cc index 317526a563a..78a1a5cc9a4 100644 --- a/test/core/bad_connection/close_fd_test.cc +++ b/test/core/bad_connection/close_fd_test.cc @@ -39,7 +39,6 @@ #include #include #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/iomgr/endpoint_pair.h" #include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/completion_queue.h" @@ -328,7 +327,6 @@ static void _test_close_before_server_recv(fd_type fdtype) { */ if (event.type == GRPC_QUEUE_TIMEOUT) { GPR_ASSERT(event.success == 0); - GPR_ASSERT(event.tag == nullptr); /* status is not initialized */ GPR_ASSERT(status == GRPC_STATUS__DO_NOT_USE); } else { @@ -531,7 +529,6 @@ static void _test_close_before_server_send(fd_type fdtype) { } else { GPR_ASSERT(event.type == GRPC_QUEUE_TIMEOUT); GPR_ASSERT(event.success == 0); - GPR_ASSERT(event.tag == nullptr); /* status is not initialized */ GPR_ASSERT(status == GRPC_STATUS__DO_NOT_USE); } @@ -664,7 +661,6 @@ static void _test_close_before_client_send(fd_type fdtype) { g_ctx.cq, grpc_timeout_milliseconds_to_deadline(100), nullptr); GPR_ASSERT(event.success == 0); GPR_ASSERT(event.type == GRPC_QUEUE_TIMEOUT); - GPR_ASSERT(event.tag == nullptr); grpc_slice_unref(details); grpc_metadata_array_destroy(&initial_metadata_recv); @@ -720,13 +716,11 @@ static void _test_close_before_call_create(fd_type fdtype) { g_ctx.client_cq, grpc_timeout_milliseconds_to_deadline(100), nullptr); GPR_ASSERT(event.type == GRPC_QUEUE_TIMEOUT); GPR_ASSERT(event.success == 0); - GPR_ASSERT(event.tag == nullptr); event = grpc_completion_queue_next( g_ctx.cq, grpc_timeout_milliseconds_to_deadline(100), nullptr); GPR_ASSERT(event.type == GRPC_QUEUE_TIMEOUT); GPR_ASSERT(event.success == 0); - GPR_ASSERT(event.tag == nullptr); grpc_call_unref(call); end_test(); diff --git a/test/core/bad_ssl/bad_ssl_test.cc b/test/core/bad_ssl/bad_ssl_test.cc index 73d251eff4a..8dd55f64944 100644 --- a/test/core/bad_ssl/bad_ssl_test.cc +++ b/test/core/bad_ssl/bad_ssl_test.cc @@ -25,9 +25,9 @@ #include #include -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" +#include "src/core/lib/security/security_connector/ssl_utils.h" #include "test/core/end2end/cq_verifier.h" #include "test/core/util/port.h" #include "test/core/util/subprocess.h" @@ -133,7 +133,7 @@ int main(int argc, char** argv) { strcpy(root, "."); } if (argc == 2) { - gpr_setenv("GRPC_DEFAULT_SSL_ROOTS_FILE_PATH", argv[1]); + GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, argv[1]); } /* figure out our test name */ tmp = lunder - 1; diff --git a/test/core/client_channel/resolvers/dns_resolver_test.cc b/test/core/client_channel/resolvers/dns_resolver_test.cc index ed3b4e66472..129866b7d7f 100644 --- a/test/core/client_channel/resolvers/dns_resolver_test.cc +++ b/test/core/client_channel/resolvers/dns_resolver_test.cc @@ -21,8 +21,8 @@ #include #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" +#include "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/iomgr/combiner.h" #include "test/core/util/test_config.h" @@ -78,13 +78,13 @@ int main(int argc, char** argv) { test_succeeds(dns, "dns:10.2.1.1:1234"); test_succeeds(dns, "dns:www.google.com"); test_succeeds(dns, "dns:///www.google.com"); - char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER"); - if (resolver_env != nullptr && gpr_stricmp(resolver_env, "native") == 0) { + grpc_core::UniquePtr resolver = + GPR_GLOBAL_CONFIG_GET(grpc_dns_resolver); + if (gpr_stricmp(resolver.get(), "native") == 0) { test_fails(dns, "dns://8.8.8.8/8.8.8.8:8888"); } else { test_succeeds(dns, "dns://8.8.8.8/8.8.8.8:8888"); } - gpr_free(resolver_env); { grpc_core::ExecCtx exec_ctx; GRPC_COMBINER_UNREF(g_combiner, "test"); diff --git a/test/core/client_channel/service_config_test.cc b/test/core/client_channel/service_config_test.cc index 10cb4cd4404..919441d706a 100644 --- a/test/core/client_channel/service_config_test.cc +++ b/test/core/client_channel/service_config_test.cc @@ -21,7 +21,9 @@ #include #include +#include "src/core/ext/filters/client_channel/resolver_result_parsing.h" #include "src/core/ext/filters/client_channel/service_config.h" +#include "src/core/ext/filters/message_size/message_size_filter.h" #include "src/core/lib/gpr/string.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" @@ -29,9 +31,9 @@ namespace grpc_core { namespace testing { -class TestParsedObject1 : public ServiceConfigParsedObject { +class TestParsedConfig1 : public ServiceConfig::ParsedConfig { public: - TestParsedObject1(int value) : value_(value) {} + TestParsedConfig1(int value) : value_(value) {} int value() const { return value_; } @@ -39,9 +41,9 @@ class TestParsedObject1 : public ServiceConfigParsedObject { int value_; }; -class TestParser1 : public ServiceConfigParser { +class TestParser1 : public ServiceConfig::Parser { public: - UniquePtr ParseGlobalParams( + UniquePtr ParseGlobalParams( const grpc_json* json, grpc_error** error) override { GPR_DEBUG_ASSERT(error != nullptr); for (grpc_json* field = json->child; field != nullptr; @@ -58,8 +60,8 @@ class TestParser1 : public ServiceConfigParser { GRPC_ERROR_CREATE_FROM_STATIC_STRING(InvalidValueErrorMessage()); return nullptr; } - return UniquePtr( - New(value)); + return UniquePtr( + New(value)); } } return nullptr; @@ -74,9 +76,9 @@ class TestParser1 : public ServiceConfigParser { } }; -class TestParser2 : public ServiceConfigParser { +class TestParser2 : public ServiceConfig::Parser { public: - UniquePtr ParsePerMethodParams( + UniquePtr ParsePerMethodParams( const grpc_json* json, grpc_error** error) override { GPR_DEBUG_ASSERT(error != nullptr); for (grpc_json* field = json->child; field != nullptr; @@ -96,8 +98,8 @@ class TestParser2 : public ServiceConfigParser { GRPC_ERROR_CREATE_FROM_STATIC_STRING(InvalidValueErrorMessage()); return nullptr; } - return UniquePtr( - New(value)); + return UniquePtr( + New(value)); } } return nullptr; @@ -113,16 +115,16 @@ class TestParser2 : public ServiceConfigParser { }; // This parser always adds errors -class ErrorParser : public ServiceConfigParser { +class ErrorParser : public ServiceConfig::Parser { public: - UniquePtr ParsePerMethodParams( + UniquePtr ParsePerMethodParams( const grpc_json* json, grpc_error** error) override { GPR_DEBUG_ASSERT(error != nullptr); *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(MethodError()); return nullptr; } - UniquePtr ParseGlobalParams( + UniquePtr ParseGlobalParams( const grpc_json* json, grpc_error** error) override { GPR_DEBUG_ASSERT(error != nullptr); *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(GlobalError()); @@ -134,15 +136,22 @@ class ErrorParser : public ServiceConfigParser { static const char* GlobalError() { return "ErrorParser : globalError"; } }; +void VerifyRegexMatch(grpc_error* error, const std::regex& e) { + std::smatch match; + std::string s(grpc_error_string(error)); + EXPECT_TRUE(std::regex_search(s, match, e)); + GRPC_ERROR_UNREF(error); +} + class ServiceConfigTest : public ::testing::Test { protected: void SetUp() override { ServiceConfig::Shutdown(); ServiceConfig::Init(); EXPECT_TRUE(ServiceConfig::RegisterParser( - UniquePtr(New())) == 0); + UniquePtr(New())) == 0); EXPECT_TRUE(ServiceConfig::RegisterParser( - UniquePtr(New())) == 1); + UniquePtr(New())) == 1); } }; @@ -152,9 +161,8 @@ TEST_F(ServiceConfigTest, ErrorCheck1) { auto svc_cfg = ServiceConfig::Create(test_json, &error); gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); ASSERT_TRUE(error != GRPC_ERROR_NONE); - EXPECT_TRUE(strstr(grpc_error_string(error), - "failed to parse JSON for service config") != nullptr); - GRPC_ERROR_UNREF(error); + std::regex e(std::string("failed to parse JSON for service config")); + VerifyRegexMatch(error, e); } TEST_F(ServiceConfigTest, BasicTest1) { @@ -170,8 +178,13 @@ TEST_F(ServiceConfigTest, ErrorNoNames) { auto svc_cfg = ServiceConfig::Create(test_json, &error); gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); ASSERT_TRUE(error != GRPC_ERROR_NONE); - EXPECT_TRUE(strstr(grpc_error_string(error), "No names found") != nullptr); - GRPC_ERROR_UNREF(error); + std::regex e( + std::string("(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Method " + "Params)(.*)(referenced_errors)(.*)(No names " + "found)(.*)(methodConfig)(.*)(referenced_errors)(.*)(No " + "names specified)")); + VerifyRegexMatch(error, e); } TEST_F(ServiceConfigTest, ErrorNoNamesWithMultipleMethodConfigs) { @@ -181,8 +194,13 @@ TEST_F(ServiceConfigTest, ErrorNoNamesWithMultipleMethodConfigs) { auto svc_cfg = ServiceConfig::Create(test_json, &error); gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); ASSERT_TRUE(error != GRPC_ERROR_NONE); - EXPECT_TRUE(strstr(grpc_error_string(error), "No names found") != nullptr); - GRPC_ERROR_UNREF(error); + std::regex e( + std::string("(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Method " + "Params)(.*)(referenced_errors)(.*)(No names " + "found)(.*)(methodConfig)(.*)(referenced_errors)(.*)(No " + "names specified)")); + VerifyRegexMatch(error, e); } TEST_F(ServiceConfigTest, ValidMethodConfig) { @@ -198,9 +216,12 @@ TEST_F(ServiceConfigTest, Parser1BasicTest1) { grpc_error* error = GRPC_ERROR_NONE; auto svc_cfg = ServiceConfig::Create(test_json, &error); ASSERT_TRUE(error == GRPC_ERROR_NONE); - EXPECT_TRUE((static_cast( - svc_cfg->GetParsedGlobalServiceConfigObject(0))) - ->value() == 5); + EXPECT_TRUE( + (static_cast(svc_cfg->GetGlobalParsedConfig(0))) + ->value() == 5); + EXPECT_TRUE(svc_cfg->GetMethodParsedConfigVector( + grpc_slice_from_static_string("/TestServ/TestMethod")) == + nullptr); } TEST_F(ServiceConfigTest, Parser1BasicTest2) { @@ -208,9 +229,9 @@ TEST_F(ServiceConfigTest, Parser1BasicTest2) { grpc_error* error = GRPC_ERROR_NONE; auto svc_cfg = ServiceConfig::Create(test_json, &error); ASSERT_TRUE(error == GRPC_ERROR_NONE); - EXPECT_TRUE((static_cast( - svc_cfg->GetParsedGlobalServiceConfigObject(0))) - ->value() == 1000); + EXPECT_TRUE( + (static_cast(svc_cfg->GetGlobalParsedConfig(0))) + ->value() == 1000); } TEST_F(ServiceConfigTest, Parser1ErrorInvalidType) { @@ -221,12 +242,9 @@ TEST_F(ServiceConfigTest, Parser1ErrorInvalidType) { ASSERT_TRUE(error != GRPC_ERROR_NONE); std::regex e(std::string("(Service config parsing " "error)(.*)(referenced_errors)(.*)(Global " - "Params)(.*)(referenced_errors)()(.*)") + + "Params)(.*)(referenced_errors)(.*)") + TestParser1::InvalidTypeErrorMessage()); - std::smatch match; - std::string s(grpc_error_string(error)); - EXPECT_TRUE(std::regex_search(s, match, e)); - GRPC_ERROR_UNREF(error); + VerifyRegexMatch(error, e); } TEST_F(ServiceConfigTest, Parser1ErrorInvalidValue) { @@ -237,12 +255,9 @@ TEST_F(ServiceConfigTest, Parser1ErrorInvalidValue) { ASSERT_TRUE(error != GRPC_ERROR_NONE); std::regex e(std::string("(Service config parsing " "error)(.*)(referenced_errors)(.*)(Global " - "Params)(.*)(referenced_errors)()(.*)") + + "Params)(.*)(referenced_errors)(.*)") + TestParser1::InvalidValueErrorMessage()); - std::smatch match; - std::string s(grpc_error_string(error)); - EXPECT_TRUE(std::regex_search(s, match, e)); - GRPC_ERROR_UNREF(error); + VerifyRegexMatch(error, e); } TEST_F(ServiceConfigTest, Parser2BasicTest) { @@ -252,12 +267,11 @@ TEST_F(ServiceConfigTest, Parser2BasicTest) { grpc_error* error = GRPC_ERROR_NONE; auto svc_cfg = ServiceConfig::Create(test_json, &error); ASSERT_TRUE(error == GRPC_ERROR_NONE); - const auto* const* vector_ptr = svc_cfg->GetMethodServiceConfigObjectsVector( + const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector( grpc_slice_from_static_string("/TestServ/TestMethod")); EXPECT_TRUE(vector_ptr != nullptr); - const auto* vector = *vector_ptr; - auto parsed_object = ((*vector)[1]).get(); - EXPECT_TRUE(static_cast(parsed_object)->value() == 5); + auto parsed_config = ((*vector_ptr)[1]).get(); + EXPECT_TRUE(static_cast(parsed_config)->value() == 5); } TEST_F(ServiceConfigTest, Parser2ErrorInvalidType) { @@ -270,13 +284,10 @@ TEST_F(ServiceConfigTest, Parser2ErrorInvalidType) { gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); std::regex e(std::string("(Service config parsing " "error)(.*)(referenced_errors\":\\[)(.*)(Method " - "Params)(.*)(referenced_errors)()(.*)(methodConfig)(" + "Params)(.*)(referenced_errors)(.*)(methodConfig)(" ".*)(referenced_errors)(.*)") + TestParser2::InvalidTypeErrorMessage()); - std::smatch match; - std::string s(grpc_error_string(error)); - EXPECT_TRUE(std::regex_search(s, match, e)); - GRPC_ERROR_UNREF(error); + VerifyRegexMatch(error, e); } TEST_F(ServiceConfigTest, Parser2ErrorInvalidValue) { @@ -292,10 +303,7 @@ TEST_F(ServiceConfigTest, Parser2ErrorInvalidValue) { "Params)(.*)(referenced_errors)()(.*)(methodConfig)(" ".*)(referenced_errors)(.*)") + TestParser2::InvalidValueErrorMessage()); - std::smatch match; - std::string s(grpc_error_string(error)); - EXPECT_TRUE(std::regex_search(s, match, e)); - GRPC_ERROR_UNREF(error); + VerifyRegexMatch(error, e); } // Test parsing with ErrorParsers which always add errors @@ -305,9 +313,9 @@ class ErroredParsersScopingTest : public ::testing::Test { ServiceConfig::Shutdown(); ServiceConfig::Init(); EXPECT_TRUE(ServiceConfig::RegisterParser( - UniquePtr(New())) == 0); + UniquePtr(New())) == 0); EXPECT_TRUE(ServiceConfig::RegisterParser( - UniquePtr(New())) == 1); + UniquePtr(New())) == 1); } }; @@ -322,10 +330,7 @@ TEST_F(ErroredParsersScopingTest, GlobalParams) { "Params)(.*)(referenced_errors)()(.*)") + ErrorParser::GlobalError() + std::string("(.*)") + ErrorParser::GlobalError()); - std::smatch match; - std::string s(grpc_error_string(error)); - EXPECT_TRUE(std::regex_search(s, match, e)); - GRPC_ERROR_UNREF(error); + VerifyRegexMatch(error, e); } TEST_F(ErroredParsersScopingTest, MethodParams) { @@ -346,12 +351,687 @@ TEST_F(ErroredParsersScopingTest, MethodParams) { "found)(.*)(methodConfig)(.*)(referenced_errors)(.*)") + ErrorParser::MethodError() + std::string("(.*)") + ErrorParser::MethodError() + std::string("(.*)(No names specified)")); + VerifyRegexMatch(error, e); +} + +class ClientChannelParserTest : public ::testing::Test { + protected: + void SetUp() override { + ServiceConfig::Shutdown(); + ServiceConfig::Init(); + EXPECT_TRUE( + ServiceConfig::RegisterParser(UniquePtr( + New())) == + 0); + } +}; + +TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigPickFirst) { + const char* test_json = "{\"loadBalancingConfig\": [{\"pick_first\":{}}]}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + ASSERT_TRUE(error == GRPC_ERROR_NONE); + const auto* parsed_config = + static_cast( + svc_cfg->GetGlobalParsedConfig(0)); + auto lb_config = parsed_config->parsed_lb_config(); + EXPECT_TRUE(strcmp(lb_config->name(), "pick_first") == 0); +} + +TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigRoundRobin) { + const char* test_json = + "{\"loadBalancingConfig\": [{\"round_robin\":{}}, {}]}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + ASSERT_TRUE(error == GRPC_ERROR_NONE); + auto parsed_config = + static_cast( + svc_cfg->GetGlobalParsedConfig(0)); + auto lb_config = parsed_config->parsed_lb_config(); + EXPECT_TRUE(strcmp(lb_config->name(), "round_robin") == 0); +} + +TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigGrpclb) { + const char* test_json = + "{\"loadBalancingConfig\": " + "[{\"grpclb\":{\"childPolicy\":[{\"pick_first\":{}}]}}]}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + ASSERT_TRUE(error == GRPC_ERROR_NONE); + const auto* parsed_config = + static_cast( + svc_cfg->GetGlobalParsedConfig(0)); + auto lb_config = parsed_config->parsed_lb_config(); + EXPECT_TRUE(strcmp(lb_config->name(), "grpclb") == 0); +} + +TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigXds) { + const char* test_json = + "{\n" + " \"loadBalancingConfig\":[\n" + " { \"does_not_exist\":{} },\n" + " { \"xds_experimental\":{ \"balancerName\": \"fake:///lb\" } }\n" + " ]\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error == GRPC_ERROR_NONE); + const auto* parsed_config = + static_cast( + svc_cfg->GetGlobalParsedConfig(0)); + auto lb_config = parsed_config->parsed_lb_config(); + EXPECT_TRUE(strcmp(lb_config->name(), "xds_experimental") == 0); +} + +TEST_F(ClientChannelParserTest, UnknownLoadBalancingConfig) { + const char* test_json = "{\"loadBalancingConfig\": [{\"unknown\":{}}]}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error != GRPC_ERROR_NONE); + std::regex e( + std::string("(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Global " + "Params)(.*)(referenced_errors)(.*)(Client channel global " + "parser)(.*)(referenced_errors)(.*)(field:" + "loadBalancingConfig error:No known policy)")); + VerifyRegexMatch(error, e); +} + +TEST_F(ClientChannelParserTest, InvalidGrpclbLoadBalancingConfig) { + const char* test_json = + "{\"loadBalancingConfig\": " + "[{\"grpclb\":{\"childPolicy\":[{\"unknown\":{}}]}}]}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error != GRPC_ERROR_NONE); + std::regex e( + std::string("(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Global " + "Params)(.*)(referenced_errors)(.*)(Client channel global " + "parser)(.*)(referenced_errors)(.*)(GrpcLb " + "Parser)(.*)(referenced_errors)(.*)(field:childPolicy " + "error:No known policy)")); + VerifyRegexMatch(error, e); +} + +TEST_F(ClientChannelParserTest, InalidLoadBalancingConfigXds) { + const char* test_json = + "{\n" + " \"loadBalancingConfig\":[\n" + " { \"does_not_exist\":{} },\n" + " { \"xds_experimental\":{} }\n" + " ]\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error != GRPC_ERROR_NONE); + std::regex e( + std::string("(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Global " + "Params)(.*)(referenced_errors)(.*)(Client channel global " + "parser)(.*)(referenced_errors)(.*)(Xds " + "Parser)(.*)(referenced_errors)(.*)(field:balancerName " + "error:not found)")); + VerifyRegexMatch(error, e); +} + +TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicy) { + const char* test_json = "{\"loadBalancingPolicy\":\"pick_first\"}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + ASSERT_TRUE(error == GRPC_ERROR_NONE); + const auto* parsed_config = + static_cast( + svc_cfg->GetGlobalParsedConfig(0)); + const auto* lb_policy = parsed_config->parsed_deprecated_lb_policy(); + ASSERT_TRUE(lb_policy != nullptr); + EXPECT_TRUE(strcmp(lb_policy, "pick_first") == 0); +} + +TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicyAllCaps) { + const char* test_json = "{\"loadBalancingPolicy\":\"PICK_FIRST\"}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error == GRPC_ERROR_NONE); + const auto* parsed_config = + static_cast( + svc_cfg->GetGlobalParsedConfig(0)); + const auto* lb_policy = parsed_config->parsed_deprecated_lb_policy(); + ASSERT_TRUE(lb_policy != nullptr); + EXPECT_TRUE(strcmp(lb_policy, "pick_first") == 0); +} + +TEST_F(ClientChannelParserTest, UnknownLoadBalancingPolicy) { + const char* test_json = "{\"loadBalancingPolicy\":\"unknown\"}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error != GRPC_ERROR_NONE); + std::regex e( + std::string("(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Global " + "Params)(.*)(referenced_errors)(.*)(Client channel global " + "parser)(.*)(referenced_errors)(.*)(field:" + "loadBalancingPolicy error:Unknown lb policy)")); + VerifyRegexMatch(error, e); +} + +TEST_F(ClientChannelParserTest, LoadBalancingPolicyXdsNotAllowed) { + const char* test_json = "{\"loadBalancingPolicy\":\"xds_experimental\"}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error != GRPC_ERROR_NONE); + std::regex e( + std::string("(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Global " + "Params)(.*)(referenced_errors)(.*)(Client channel global " + "parser)(.*)(referenced_errors)(.*)(field:" + "loadBalancingPolicy error:xds_experimental requires a " + "config. Please use loadBalancingConfig instead.)")); + VerifyRegexMatch(error, e); +} + +TEST_F(ClientChannelParserTest, ValidRetryThrottling) { + const char* test_json = + "{\n" + " \"retryThrottling\": {\n" + " \"maxTokens\": 2,\n" + " \"tokenRatio\": 1.0\n" + " }\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error == GRPC_ERROR_NONE); + const auto* parsed_config = + static_cast( + svc_cfg->GetGlobalParsedConfig(0)); + const auto retryThrottling = parsed_config->retry_throttling(); + ASSERT_TRUE(retryThrottling.has_value()); + EXPECT_EQ(retryThrottling.value().max_milli_tokens, 2000); + EXPECT_EQ(retryThrottling.value().milli_token_ratio, 1000); +} + +TEST_F(ClientChannelParserTest, RetryThrottlingMissingFields) { + const char* test_json = + "{\n" + " \"retryThrottling\": {\n" + " }\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error != GRPC_ERROR_NONE); + std::regex e( + std::string("(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Global " + "Params)(.*)(referenced_errors)(.*)(Client channel global " + "parser)(.*)(referenced_errors)(.*)(field:retryThrottling " + "field:maxTokens error:Not found)(.*)(field:retryThrottling " + "field:tokenRatio error:Not found)")); + VerifyRegexMatch(error, e); +} + +TEST_F(ClientChannelParserTest, InvalidRetryThrottlingNegativeMaxTokens) { + const char* test_json = + "{\n" + " \"retryThrottling\": {\n" + " \"maxTokens\": -2,\n" + " \"tokenRatio\": 1.0\n" + " }\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error != GRPC_ERROR_NONE); + std::regex e( + std::string("(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Global " + "Params)(.*)(referenced_errors)(.*)(Client channel global " + "parser)(.*)(referenced_errors)(.*)(field:retryThrottling " + "field:maxTokens error:should be greater than zero)")); + VerifyRegexMatch(error, e); +} + +TEST_F(ClientChannelParserTest, InvalidRetryThrottlingInvalidTokenRatio) { + const char* test_json = + "{\n" + " \"retryThrottling\": {\n" + " \"maxTokens\": 2,\n" + " \"tokenRatio\": -1\n" + " }\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error != GRPC_ERROR_NONE); + std::regex e( + std::string("(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Global " + "Params)(.*)(referenced_errors)(.*)(Client channel global " + "parser)(.*)(referenced_errors)(.*)(field:retryThrottling " + "field:tokenRatio error:Failed parsing)")); + VerifyRegexMatch(error, e); +} + +TEST_F(ClientChannelParserTest, ValidTimeout) { + const char* test_json = + "{\n" + " \"methodConfig\": [ {\n" + " \"name\": [\n" + " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" + " ],\n" + " \"timeout\": \"5s\"\n" + " } ]\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + ASSERT_TRUE(error == GRPC_ERROR_NONE); + const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector( + grpc_slice_from_static_string("/TestServ/TestMethod")); + EXPECT_TRUE(vector_ptr != nullptr); + auto parsed_config = ((*vector_ptr)[0]).get(); + EXPECT_EQ((static_cast( + parsed_config)) + ->timeout(), + 5000); +} + +TEST_F(ClientChannelParserTest, InvalidTimeout) { + const char* test_json = + "{\n" + " \"methodConfig\": [ {\n" + " \"name\": [\n" + " { \"service\": \"service\", \"method\": \"method\" }\n" + " ],\n" + " \"timeout\": \"5sec\"\n" + " } ]\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error != GRPC_ERROR_NONE); + std::regex e( + std::string("(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Method " + "Params)(.*)(referenced_errors)(.*)(methodConfig)(.*)(" + "referenced_errors)(.*)(Client channel " + "parser)(.*)(referenced_errors)(.*)(field:timeout " + "error:Failed parsing)")); + VerifyRegexMatch(error, e); +} + +TEST_F(ClientChannelParserTest, ValidWaitForReady) { + const char* test_json = + "{\n" + " \"methodConfig\": [ {\n" + " \"name\": [\n" + " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" + " ],\n" + " \"waitForReady\": true\n" + " } ]\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + ASSERT_TRUE(error == GRPC_ERROR_NONE); + const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector( + grpc_slice_from_static_string("/TestServ/TestMethod")); + EXPECT_TRUE(vector_ptr != nullptr); + auto parsed_config = ((*vector_ptr)[0]).get(); + EXPECT_TRUE( + (static_cast( + parsed_config)) + ->wait_for_ready() + .has_value()); + EXPECT_TRUE( + (static_cast( + parsed_config)) + ->wait_for_ready() + .value()); +} + +TEST_F(ClientChannelParserTest, InvalidWaitForReady) { + const char* test_json = + "{\n" + " \"methodConfig\": [ {\n" + " \"name\": [\n" + " { \"service\": \"service\", \"method\": \"method\" }\n" + " ],\n" + " \"waitForReady\": \"true\"\n" + " } ]\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error != GRPC_ERROR_NONE); + std::regex e( + std::string("(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Method " + "Params)(.*)(referenced_errors)(.*)(methodConfig)(.*)(" + "referenced_errors)(.*)(Client channel " + "parser)(.*)(referenced_errors)(.*)(field:waitForReady " + "error:Type should be true/false)")); + VerifyRegexMatch(error, e); +} + +TEST_F(ClientChannelParserTest, ValidRetryPolicy) { + const char* test_json = + "{\n" + " \"methodConfig\": [ {\n" + " \"name\": [\n" + " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" + " ],\n" + " \"retryPolicy\": {\n" + " \"maxAttempts\": 3,\n" + " \"initialBackoff\": \"1s\",\n" + " \"maxBackoff\": \"120s\",\n" + " \"backoffMultiplier\": 1.6,\n" + " \"retryableStatusCodes\": [ \"ABORTED\" ]\n" + " }\n" + " } ]\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error == GRPC_ERROR_NONE); + const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector( + grpc_slice_from_static_string("/TestServ/TestMethod")); + EXPECT_TRUE(vector_ptr != nullptr); + const auto* parsed_config = + static_cast( + ((*vector_ptr)[0]).get()); + EXPECT_TRUE(parsed_config->retry_policy() != nullptr); + EXPECT_EQ(parsed_config->retry_policy()->max_attempts, 3); + EXPECT_EQ(parsed_config->retry_policy()->initial_backoff, 1000); + EXPECT_EQ(parsed_config->retry_policy()->max_backoff, 120000); + EXPECT_EQ(parsed_config->retry_policy()->backoff_multiplier, 1.6f); + EXPECT_TRUE(parsed_config->retry_policy()->retryable_status_codes.Contains( + GRPC_STATUS_ABORTED)); +} + +TEST_F(ClientChannelParserTest, InvalidRetryPolicyMaxAttempts) { + const char* test_json = + "{\n" + " \"methodConfig\": [ {\n" + " \"name\": [\n" + " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" + " ],\n" + " \"retryPolicy\": {\n" + " \"maxAttempts\": 1,\n" + " \"initialBackoff\": \"1s\",\n" + " \"maxBackoff\": \"120s\",\n" + " \"backoffMultiplier\": 1.6,\n" + " \"retryableStatusCodes\": [ \"ABORTED\" ]\n" + " }\n" + " } ]\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error != GRPC_ERROR_NONE); + std::regex e(std::string( + "(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Method " + "Params)(.*)(referenced_errors)(.*)(methodConfig)(.*)(referenced_errors)(" + ".*)(Client channel " + "parser)(.*)(referenced_errors)(.*)(retryPolicy)(.*)(referenced_errors)(." + "*)(field:maxAttempts error:should be at least 2)")); + VerifyRegexMatch(error, e); +} + +TEST_F(ClientChannelParserTest, InvalidRetryPolicyInitialBackoff) { + const char* test_json = + "{\n" + " \"methodConfig\": [ {\n" + " \"name\": [\n" + " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" + " ],\n" + " \"retryPolicy\": {\n" + " \"maxAttempts\": 1,\n" + " \"initialBackoff\": \"1sec\",\n" + " \"maxBackoff\": \"120s\",\n" + " \"backoffMultiplier\": 1.6,\n" + " \"retryableStatusCodes\": [ \"ABORTED\" ]\n" + " }\n" + " } ]\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error != GRPC_ERROR_NONE); + std::regex e(std::string( + "(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Method " + "Params)(.*)(referenced_errors)(.*)(methodConfig)(.*)(referenced_errors)(" + ".*)(Client channel " + "parser)(.*)(referenced_errors)(.*)(retryPolicy)(.*)(referenced_errors)(." + "*)(field:initialBackoff error:Failed to parse)")); + VerifyRegexMatch(error, e); +} + +TEST_F(ClientChannelParserTest, InvalidRetryPolicyMaxBackoff) { + const char* test_json = + "{\n" + " \"methodConfig\": [ {\n" + " \"name\": [\n" + " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" + " ],\n" + " \"retryPolicy\": {\n" + " \"maxAttempts\": 1,\n" + " \"initialBackoff\": \"1s\",\n" + " \"maxBackoff\": \"120sec\",\n" + " \"backoffMultiplier\": 1.6,\n" + " \"retryableStatusCodes\": [ \"ABORTED\" ]\n" + " }\n" + " } ]\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error != GRPC_ERROR_NONE); + std::regex e(std::string( + "(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Method " + "Params)(.*)(referenced_errors)(.*)(methodConfig)(.*)(referenced_errors)(" + ".*)(Client channel " + "parser)(.*)(referenced_errors)(.*)(retryPolicy)(.*)(referenced_errors)(." + "*)(field:maxBackoff error:failed to parse)")); + VerifyRegexMatch(error, e); +} + +TEST_F(ClientChannelParserTest, InvalidRetryPolicyBackoffMultiplier) { + const char* test_json = + "{\n" + " \"methodConfig\": [ {\n" + " \"name\": [\n" + " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" + " ],\n" + " \"retryPolicy\": {\n" + " \"maxAttempts\": 1,\n" + " \"initialBackoff\": \"1s\",\n" + " \"maxBackoff\": \"120s\",\n" + " \"backoffMultiplier\": \"1.6\",\n" + " \"retryableStatusCodes\": [ \"ABORTED\" ]\n" + " }\n" + " } ]\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error != GRPC_ERROR_NONE); + std::regex e(std::string( + "(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Method " + "Params)(.*)(referenced_errors)(.*)(methodConfig)(.*)(referenced_errors)(" + ".*)(Client channel " + "parser)(.*)(referenced_errors)(.*)(retryPolicy)(.*)(referenced_errors)(." + "*)(field:backoffMultiplier error:should be of type number)")); + VerifyRegexMatch(error, e); +} + +TEST_F(ClientChannelParserTest, InvalidRetryPolicyRetryableStatusCodes) { + const char* test_json = + "{\n" + " \"methodConfig\": [ {\n" + " \"name\": [\n" + " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" + " ],\n" + " \"retryPolicy\": {\n" + " \"maxAttempts\": 1,\n" + " \"initialBackoff\": \"1s\",\n" + " \"maxBackoff\": \"120s\",\n" + " \"backoffMultiplier\": \"1.6\",\n" + " \"retryableStatusCodes\": []\n" + " }\n" + " } ]\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error != GRPC_ERROR_NONE); + std::regex e(std::string( + "(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Method " + "Params)(.*)(referenced_errors)(.*)(methodConfig)(.*)(referenced_errors)(" + ".*)(Client channel " + "parser)(.*)(referenced_errors)(.*)(retryPolicy)(.*)(referenced_errors)(." + "*)(field:retryableStatusCodes error:should be non-empty)")); + VerifyRegexMatch(error, e); +} + +TEST_F(ClientChannelParserTest, ValidHealthCheck) { + const char* test_json = + "{\n" + " \"healthCheckConfig\": {\n" + " \"serviceName\": \"health_check_service_name\"\n" + " }\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + ASSERT_TRUE(error == GRPC_ERROR_NONE); + const auto* parsed_config = + static_cast( + svc_cfg->GetGlobalParsedConfig(0)); + ASSERT_TRUE(parsed_config != nullptr); + EXPECT_EQ(strcmp(parsed_config->health_check_service_name(), + "health_check_service_name"), + 0); +} + +TEST_F(ClientChannelParserTest, InvalidHealthCheckMultipleEntries) { + const char* test_json = + "{\n" + " \"healthCheckConfig\": {\n" + " \"serviceName\": \"health_check_service_name\"\n" + " },\n" + " \"healthCheckConfig\": {\n" + " \"serviceName\": \"health_check_service_name1\"\n" + " }\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error != GRPC_ERROR_NONE); + std::regex e( + std::string("(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Global " + "Params)(.*)(referenced_errors)(.*)(field:healthCheckConfig " + "error:Duplicate entry)")); std::smatch match; std::string s(grpc_error_string(error)); EXPECT_TRUE(std::regex_search(s, match, e)); GRPC_ERROR_UNREF(error); } +class MessageSizeParserTest : public ::testing::Test { + protected: + void SetUp() override { + ServiceConfig::Shutdown(); + ServiceConfig::Init(); + EXPECT_TRUE(ServiceConfig::RegisterParser(UniquePtr( + New())) == 0); + } +}; + +TEST_F(MessageSizeParserTest, Valid) { + const char* test_json = + "{\n" + " \"methodConfig\": [ {\n" + " \"name\": [\n" + " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" + " ],\n" + " \"maxRequestMessageBytes\": 1024,\n" + " \"maxResponseMessageBytes\": 1024\n" + " } ]\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error == GRPC_ERROR_NONE); + const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector( + grpc_slice_from_static_string("/TestServ/TestMethod")); + EXPECT_TRUE(vector_ptr != nullptr); + auto parsed_config = + static_cast(((*vector_ptr)[0]).get()); + ASSERT_TRUE(parsed_config != nullptr); + EXPECT_EQ(parsed_config->limits().max_send_size, 1024); + EXPECT_EQ(parsed_config->limits().max_recv_size, 1024); +} + +TEST_F(MessageSizeParserTest, InvalidMaxRequestMessageBytes) { + const char* test_json = + "{\n" + " \"methodConfig\": [ {\n" + " \"name\": [\n" + " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" + " ],\n" + " \"maxRequestMessageBytes\": -1024\n" + " } ]\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error != GRPC_ERROR_NONE); + std::regex e( + std::string("(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Method " + "Params)(.*)(referenced_errors)(.*)(methodConfig)(.*)(" + "referenced_errors)(.*)(Message size " + "parser)(.*)(referenced_errors)(.*)(field:" + "maxRequestMessageBytes error:should be non-negative)")); + VerifyRegexMatch(error, e); +} + +TEST_F(MessageSizeParserTest, InvalidMaxResponseMessageBytes) { + const char* test_json = + "{\n" + " \"methodConfig\": [ {\n" + " \"name\": [\n" + " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" + " ],\n" + " \"maxResponseMessageBytes\": {}\n" + " } ]\n" + "}"; + grpc_error* error = GRPC_ERROR_NONE; + auto svc_cfg = ServiceConfig::Create(test_json, &error); + gpr_log(GPR_ERROR, "%s", grpc_error_string(error)); + ASSERT_TRUE(error != GRPC_ERROR_NONE); + std::regex e( + std::string("(Service config parsing " + "error)(.*)(referenced_errors)(.*)(Method " + "Params)(.*)(referenced_errors)(.*)(methodConfig)(.*)(" + "referenced_errors)(.*)(Message size " + "parser)(.*)(referenced_errors)(.*)(field:" + "maxResponseMessageBytes error:should be of type number)")); + VerifyRegexMatch(error, e); +} + } // namespace testing } // namespace grpc_core diff --git a/test/core/end2end/bad_server_response_test.cc b/test/core/end2end/bad_server_response_test.cc index 3701a938a3d..2d74b6b77b3 100644 --- a/test/core/end2end/bad_server_response_test.cc +++ b/test/core/end2end/bad_server_response_test.cc @@ -250,7 +250,7 @@ static void actually_poll_server(void* arg) { if (done || gpr_time_cmp(time_left, gpr_time_0(GPR_TIMESPAN)) < 0) { break; } - test_tcp_server_poll(pa->server, 1); + test_tcp_server_poll(pa->server, 1000); } gpr_event_set(pa->signal_when_done, (void*)1); gpr_free(pa); diff --git a/test/core/end2end/end2end_nosec_tests.cc b/test/core/end2end/end2end_nosec_tests.cc index 3ab55527da6..e01e6ad0104 100644 --- a/test/core/end2end/end2end_nosec_tests.cc +++ b/test/core/end2end/end2end_nosec_tests.cc @@ -26,7 +26,6 @@ #include -#include "test/core/util/debugger_macros.h" static bool g_pre_init_called = false; @@ -188,7 +187,6 @@ extern void write_buffering_at_end_pre_init(void); void grpc_end2end_tests_pre_init(void) { GPR_ASSERT(!g_pre_init_called); g_pre_init_called = true; - grpc_summon_debugger_macros(); authority_not_supported_pre_init(); bad_hostname_pre_init(); bad_ping_pre_init(); diff --git a/test/core/end2end/end2end_tests.cc b/test/core/end2end/end2end_tests.cc index b680da4433f..76fb046b367 100644 --- a/test/core/end2end/end2end_tests.cc +++ b/test/core/end2end/end2end_tests.cc @@ -26,7 +26,6 @@ #include -#include "test/core/util/debugger_macros.h" static bool g_pre_init_called = false; @@ -190,7 +189,6 @@ extern void write_buffering_at_end_pre_init(void); void grpc_end2end_tests_pre_init(void) { GPR_ASSERT(!g_pre_init_called); g_pre_init_called = true; - grpc_summon_debugger_macros(); authority_not_supported_pre_init(); bad_hostname_pre_init(); bad_ping_pre_init(); diff --git a/test/core/end2end/fixtures/h2_full+trace.cc b/test/core/end2end/fixtures/h2_full+trace.cc index ce8f6bf13a5..b8dbe261183 100644 --- a/test/core/end2end/fixtures/h2_full+trace.cc +++ b/test/core/end2end/fixtures/h2_full+trace.cc @@ -33,7 +33,7 @@ #include "src/core/ext/filters/http/server/http_server_filter.h" #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include "src/core/lib/channel/connected_channel.h" -#include "src/core/lib/gpr/env.h" +#include "src/core/lib/debug/trace.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/server.h" @@ -105,7 +105,7 @@ int main(int argc, char** argv) { /* force tracing on, with a value to force many code paths in trace.c to be taken */ - gpr_setenv("GRPC_TRACE", "doesnt-exist,http,all"); + GPR_GLOBAL_CONFIG_SET(grpc_trace, "doesnt-exist,http,all"); #ifdef GRPC_POSIX_SOCKET g_fixture_slowdown_factor = isatty(STDOUT_FILENO) ? 10 : 1; diff --git a/test/core/end2end/fixtures/h2_sockpair+trace.cc b/test/core/end2end/fixtures/h2_sockpair+trace.cc index 4494d5c4746..7954bc1ddfc 100644 --- a/test/core/end2end/fixtures/h2_sockpair+trace.cc +++ b/test/core/end2end/fixtures/h2_sockpair+trace.cc @@ -35,7 +35,7 @@ #include "src/core/ext/filters/http/server/http_server_filter.h" #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include "src/core/lib/channel/connected_channel.h" -#include "src/core/lib/gpr/env.h" +#include "src/core/lib/debug/trace.h" #include "src/core/lib/iomgr/endpoint_pair.h" #include "src/core/lib/iomgr/iomgr.h" #include "src/core/lib/surface/channel.h" @@ -133,7 +133,8 @@ int main(int argc, char** argv) { /* force tracing on, with a value to force many code paths in trace.c to be taken */ - gpr_setenv("GRPC_TRACE", "doesnt-exist,http,all"); + GPR_GLOBAL_CONFIG_SET(grpc_trace, "doesnt-exist,http,all"); + #ifdef GRPC_POSIX_SOCKET g_fixture_slowdown_factor = isatty(STDOUT_FILENO) ? 10 : 1; #else diff --git a/test/core/end2end/fixtures/h2_spiffe.cc b/test/core/end2end/fixtures/h2_spiffe.cc index 9ab796ea429..cdf091bac10 100644 --- a/test/core/end2end/fixtures/h2_spiffe.cc +++ b/test/core/end2end/fixtures/h2_spiffe.cc @@ -35,6 +35,7 @@ #include "src/core/lib/gprpp/thd.h" #include "src/core/lib/security/credentials/credentials.h" #include "src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h" +#include "src/core/lib/security/security_connector/ssl_utils.h" #include "test/core/end2end/data/ssl_test_data.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" @@ -277,7 +278,7 @@ int main(int argc, char** argv) { GPR_ASSERT(roots_file != nullptr); GPR_ASSERT(fwrite(test_root_cert, 1, roots_size, roots_file) == roots_size); fclose(roots_file); - gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_filename); + GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, roots_filename); grpc_init(); for (size_t ind = 0; ind < sizeof(configs) / sizeof(*configs); ind++) { grpc_end2end_tests(argc, argv, configs[ind]); diff --git a/test/core/end2end/fixtures/h2_ssl.cc b/test/core/end2end/fixtures/h2_ssl.cc index 1fcd785e251..3fc9bc7f329 100644 --- a/test/core/end2end/fixtures/h2_ssl.cc +++ b/test/core/end2end/fixtures/h2_ssl.cc @@ -25,11 +25,11 @@ #include #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/tmpfile.h" #include "src/core/lib/security/credentials/credentials.h" +#include "src/core/lib/security/security_connector/ssl_utils.h" #include "test/core/end2end/data/ssl_test_data.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" @@ -167,7 +167,7 @@ int main(int argc, char** argv) { GPR_ASSERT(roots_file != nullptr); GPR_ASSERT(fwrite(test_root_cert, 1, roots_size, roots_file) == roots_size); fclose(roots_file); - gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_filename); + GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, roots_filename); grpc_init(); diff --git a/test/core/end2end/fixtures/h2_ssl_cred_reload.cc b/test/core/end2end/fixtures/h2_ssl_cred_reload.cc index 04d876ce3cd..1d54a431364 100644 --- a/test/core/end2end/fixtures/h2_ssl_cred_reload.cc +++ b/test/core/end2end/fixtures/h2_ssl_cred_reload.cc @@ -25,11 +25,11 @@ #include #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/tmpfile.h" #include "src/core/lib/security/credentials/credentials.h" +#include "src/core/lib/security/security_connector/ssl_utils.h" #include "test/core/end2end/data/ssl_test_data.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" @@ -190,7 +190,7 @@ int main(int argc, char** argv) { GPR_ASSERT(roots_file != nullptr); GPR_ASSERT(fwrite(test_root_cert, 1, roots_size, roots_file) == roots_size); fclose(roots_file); - gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_filename); + GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, roots_filename); grpc_init(); diff --git a/test/core/end2end/fixtures/h2_ssl_proxy.cc b/test/core/end2end/fixtures/h2_ssl_proxy.cc index f1858079426..d5f695b1575 100644 --- a/test/core/end2end/fixtures/h2_ssl_proxy.cc +++ b/test/core/end2end/fixtures/h2_ssl_proxy.cc @@ -25,11 +25,11 @@ #include #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/tmpfile.h" #include "src/core/lib/security/credentials/credentials.h" +#include "src/core/lib/security/security_connector/ssl_utils.h" #include "test/core/end2end/data/ssl_test_data.h" #include "test/core/end2end/fixtures/proxy.h" #include "test/core/util/port.h" @@ -208,7 +208,7 @@ int main(int argc, char** argv) { GPR_ASSERT(roots_file != nullptr); GPR_ASSERT(fwrite(test_root_cert, 1, roots_size, roots_file) == roots_size); fclose(roots_file); - gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_filename); + GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, roots_filename); grpc_init(); diff --git a/test/core/end2end/h2_ssl_cert_test.cc b/test/core/end2end/h2_ssl_cert_test.cc index cb0800bf899..e9285778a2d 100644 --- a/test/core/end2end/h2_ssl_cert_test.cc +++ b/test/core/end2end/h2_ssl_cert_test.cc @@ -25,11 +25,11 @@ #include #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/tmpfile.h" #include "src/core/lib/security/credentials/credentials.h" +#include "src/core/lib/security/security_connector/ssl_utils.h" #include "test/core/end2end/cq_verifier.h" #include "test/core/end2end/data/ssl_test_data.h" #include "test/core/util/port.h" @@ -366,7 +366,7 @@ int main(int argc, char** argv) { GPR_ASSERT(roots_file != nullptr); GPR_ASSERT(fwrite(test_root_cert, 1, roots_size, roots_file) == roots_size); fclose(roots_file); - gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_filename); + GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, roots_filename); grpc_init(); ::testing::InitGoogleTest(&argc, argv); diff --git a/test/core/end2end/h2_ssl_session_reuse_test.cc b/test/core/end2end/h2_ssl_session_reuse_test.cc index fbcdcc4b3f3..b2d0a5e1133 100644 --- a/test/core/end2end/h2_ssl_session_reuse_test.cc +++ b/test/core/end2end/h2_ssl_session_reuse_test.cc @@ -25,11 +25,11 @@ #include #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/tmpfile.h" #include "src/core/lib/security/credentials/credentials.h" +#include "src/core/lib/security/security_connector/ssl_utils.h" #include "test/core/end2end/cq_verifier.h" #include "test/core/end2end/data/ssl_test_data.h" #include "test/core/util/port.h" @@ -265,7 +265,7 @@ int main(int argc, char** argv) { GPR_ASSERT(roots_file != nullptr); GPR_ASSERT(fwrite(test_root_cert, 1, roots_size, roots_file) == roots_size); fclose(roots_file); - gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_filename); + GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, roots_filename); grpc_init(); ::testing::InitGoogleTest(&argc, argv); diff --git a/test/core/end2end/tests/keepalive_timeout.cc b/test/core/end2end/tests/keepalive_timeout.cc index 3c33f0419ad..1750f6fe5ee 100644 --- a/test/core/end2end/tests/keepalive_timeout.cc +++ b/test/core/end2end/tests/keepalive_timeout.cc @@ -28,11 +28,15 @@ #include "src/core/ext/transport/chttp2/transport/frame_ping.h" #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/useful.h" #include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/iomgr/iomgr.h" #include "test/core/end2end/cq_verifier.h" +#ifdef GRPC_POSIX_SOCKET +#include "src/core/lib/iomgr/ev_posix.h" +#endif // GRPC_POSIX_SOCKET + static void* tag(intptr_t t) { return (void*)t; } static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config, @@ -225,13 +229,13 @@ static void test_keepalive_timeout(grpc_end2end_test_config config) { * 200ms. In the success case, each ping ack should reset the keepalive timer so * that the keepalive ping is never sent. */ static void test_read_delays_keepalive(grpc_end2end_test_config config) { - char* poller = gpr_getenv("GRPC_POLL_STRATEGY"); +#ifdef GRPC_POSIX_SOCKET + grpc_core::UniquePtr poller = GPR_GLOBAL_CONFIG_GET(grpc_poll_strategy); /* It is hard to get the timing right for the polling engine poll. */ - if (poller != nullptr && (0 == strcmp(poller, "poll"))) { - gpr_free(poller); + if ((0 == strcmp(poller.get(), "poll"))) { return; } - gpr_free(poller); +#endif // GRPC_POSIX_SOCKET const int kPingIntervalMS = 100; grpc_arg keepalive_arg_elems[3]; keepalive_arg_elems[0].type = GRPC_ARG_INTEGER; diff --git a/test/core/end2end/tests/retry_throttled.cc b/test/core/end2end/tests/retry_throttled.cc index f5b28def0ad..0e286c3d17c 100644 --- a/test/core/end2end/tests/retry_throttled.cc +++ b/test/core/end2end/tests/retry_throttled.cc @@ -141,7 +141,7 @@ static void test_retry_throttled(grpc_end2end_test_config config) { // purposes of this test.) " \"retryThrottling\": {\n" " \"maxTokens\": 2,\n" - " \"tokenRatio\": 1.0,\n" + " \"tokenRatio\": 1.0\n" " }\n" "}"); grpc_channel_args client_args = {1, &arg}; diff --git a/test/core/gpr/arena_test.cc b/test/core/gpr/arena_test.cc index de4bd9804eb..1df1052ab95 100644 --- a/test/core/gpr/arena_test.cc +++ b/test/core/gpr/arena_test.cc @@ -16,7 +16,7 @@ * */ -#include "src/core/lib/gpr/arena.h" +#include "src/core/lib/gprpp/arena.h" #include #include @@ -31,7 +31,9 @@ #include "src/core/lib/gprpp/thd.h" #include "test/core/util/test_config.h" -static void test_noop(void) { gpr_arena_destroy(gpr_arena_create(1)); } +using grpc_core::Arena; + +static void test_noop(void) { Arena::Create(1)->Destroy(); } static void test(const char* name, size_t init_size, const size_t* allocs, size_t nallocs) { @@ -50,10 +52,10 @@ static void test(const char* name, size_t init_size, const size_t* allocs, gpr_log(GPR_INFO, "%s", s); gpr_free(s); - gpr_arena* a = gpr_arena_create(init_size); + Arena* a = Arena::Create(init_size); void** ps = static_cast(gpr_zalloc(sizeof(*ps) * nallocs)); for (size_t i = 0; i < nallocs; i++) { - ps[i] = gpr_arena_alloc(a, allocs[i]); + ps[i] = a->Alloc(allocs[i]); // ensure the returned address is aligned GPR_ASSERT(((intptr_t)ps[i] & 0xf) == 0); // ensure no duplicate results @@ -63,7 +65,7 @@ static void test(const char* name, size_t init_size, const size_t* allocs, // ensure writable memset(ps[i], 1, allocs[i]); } - gpr_arena_destroy(a); + a->Destroy(); gpr_free(ps); } @@ -80,14 +82,14 @@ size_t concurrent_test_iterations() { typedef struct { gpr_event ev_start; - gpr_arena* arena; + Arena* arena; } concurrent_test_args; static void concurrent_test_body(void* arg) { concurrent_test_args* a = static_cast(arg); gpr_event_wait(&a->ev_start, gpr_inf_future(GPR_CLOCK_REALTIME)); for (size_t i = 0; i < concurrent_test_iterations(); i++) { - *static_cast(gpr_arena_alloc(a->arena, 1)) = static_cast(i); + *static_cast(a->arena->Alloc(1)) = static_cast(i); } } @@ -96,7 +98,7 @@ static void concurrent_test(void) { concurrent_test_args args; gpr_event_init(&args.ev_start); - args.arena = gpr_arena_create(1024); + args.arena = Arena::Create(1024); grpc_core::Thread thds[CONCURRENT_TEST_THREADS]; @@ -112,7 +114,7 @@ static void concurrent_test(void) { th.Join(); } - gpr_arena_destroy(args.arena); + args.arena->Destroy(); } int main(int argc, char* argv[]) { diff --git a/test/core/gpr/env_test.cc b/test/core/gpr/env_test.cc index a8206bd3cfd..3883a5df997 100644 --- a/test/core/gpr/env_test.cc +++ b/test/core/gpr/env_test.cc @@ -42,8 +42,22 @@ static void test_setenv_getenv(void) { gpr_free(retrieved_value); } +static void test_unsetenv(void) { + const char* name = "FOO"; + const char* value = "BAR"; + char* retrieved_value; + + LOG_TEST_NAME("test_unsetenv"); + + gpr_setenv(name, value); + gpr_unsetenv(name); + retrieved_value = gpr_getenv(name); + GPR_ASSERT(retrieved_value == nullptr); +} + int main(int argc, char** argv) { grpc::testing::TestEnvironment env(argc, argv); test_setenv_getenv(); + test_unsetenv(); return 0; } diff --git a/test/core/gpr/log_test.cc b/test/core/gpr/log_test.cc index f96257738b2..e320daa33a7 100644 --- a/test/core/gpr/log_test.cc +++ b/test/core/gpr/log_test.cc @@ -21,9 +21,14 @@ #include #include -#include "src/core/lib/gpr/env.h" +#include "src/core/lib/gprpp/global_config.h" #include "test/core/util/test_config.h" +// Config declaration is supposed to be located at log.h but +// log.h doesn't include global_config headers because it has to +// be a strict C so declaration statement gets to be here. +GPR_GLOBAL_CONFIG_DECLARE_STRING(grpc_verbosity); + static bool log_func_reached = false; static void test_callback(gpr_log_func_args* args) { @@ -67,7 +72,7 @@ int main(int argc, char** argv) { /* gpr_log_verbosity_init() will be effective only once, and only before * gpr_set_log_verbosity() is called */ - gpr_setenv("GRPC_VERBOSITY", "ERROR"); + GPR_GLOBAL_CONFIG_SET(grpc_verbosity, "ERROR"); gpr_log_verbosity_init(); test_log_function_reached(GPR_ERROR); @@ -75,7 +80,7 @@ int main(int argc, char** argv) { test_log_function_unreached(GPR_DEBUG); /* gpr_log_verbosity_init() should not be effective */ - gpr_setenv("GRPC_VERBOSITY", "DEBUG"); + GPR_GLOBAL_CONFIG_SET(grpc_verbosity, "DEBUG"); gpr_log_verbosity_init(); test_log_function_reached(GPR_ERROR); test_log_function_unreached(GPR_INFO); @@ -97,7 +102,7 @@ int main(int argc, char** argv) { test_log_function_unreached(GPR_DEBUG); /* gpr_log_verbosity_init() should not be effective */ - gpr_setenv("GRPC_VERBOSITY", "DEBUG"); + GPR_GLOBAL_CONFIG_SET(grpc_verbosity, "DEBUG"); gpr_log_verbosity_init(); test_log_function_reached(GPR_ERROR); test_log_function_unreached(GPR_INFO); diff --git a/test/core/gpr/string_test.cc b/test/core/gpr/string_test.cc index 7da7b18778b..5e3ed9d5dfd 100644 --- a/test/core/gpr/string_test.cc +++ b/test/core/gpr/string_test.cc @@ -279,19 +279,20 @@ static void test_memrchr(void) { GPR_ASSERT(0 == strcmp((const char*)gpr_memrchr("hello", 'l', 5), "lo")); } -static void test_is_true(void) { - LOG_TEST_NAME("test_is_true"); - - GPR_ASSERT(true == gpr_is_true("True")); - GPR_ASSERT(true == gpr_is_true("true")); - GPR_ASSERT(true == gpr_is_true("TRUE")); - GPR_ASSERT(true == gpr_is_true("Yes")); - GPR_ASSERT(true == gpr_is_true("yes")); - GPR_ASSERT(true == gpr_is_true("YES")); - GPR_ASSERT(true == gpr_is_true("1")); - GPR_ASSERT(false == gpr_is_true(nullptr)); - GPR_ASSERT(false == gpr_is_true("")); - GPR_ASSERT(false == gpr_is_true("0")); +static void test_parse_bool_value(void) { + LOG_TEST_NAME("test_parse_bool_value"); + + bool ret; + GPR_ASSERT(true == gpr_parse_bool_value("truE", &ret) && true == ret); + GPR_ASSERT(true == gpr_parse_bool_value("falsE", &ret) && false == ret); + GPR_ASSERT(true == gpr_parse_bool_value("1", &ret) && true == ret); + GPR_ASSERT(true == gpr_parse_bool_value("0", &ret) && false == ret); + GPR_ASSERT(true == gpr_parse_bool_value("Yes", &ret) && true == ret); + GPR_ASSERT(true == gpr_parse_bool_value("No", &ret) && false == ret); + GPR_ASSERT(true == gpr_parse_bool_value("Y", &ret) && true == ret); + GPR_ASSERT(true == gpr_parse_bool_value("N", &ret) && false == ret); + GPR_ASSERT(false == gpr_parse_bool_value(nullptr, &ret)); + GPR_ASSERT(false == gpr_parse_bool_value("", &ret)); } int main(int argc, char** argv) { @@ -307,6 +308,6 @@ int main(int argc, char** argv) { test_leftpad(); test_stricmp(); test_memrchr(); - test_is_true(); + test_parse_bool_value(); return 0; } diff --git a/test/core/gprpp/BUILD b/test/core/gprpp/BUILD index 4665827e10f..cd3232addfd 100644 --- a/test/core/gprpp/BUILD +++ b/test/core/gprpp/BUILD @@ -28,6 +28,32 @@ grpc_cc_test( ], ) +grpc_cc_test( + name = "global_config_test", + srcs = ["global_config_test.cc"], + external_deps = [ + "gtest", + ], + language = "C++", + deps = [ + "//:gpr", + "//test/core/util:grpc_test_util", + ], +) + +grpc_cc_test( + name = "global_config_env_test", + srcs = ["global_config_env_test.cc"], + external_deps = [ + "gtest", + ], + language = "C++", + deps = [ + "//:gpr", + "//test/core/util:grpc_test_util", + ], +) + grpc_cc_test( name = "manual_constructor_test", srcs = ["manual_constructor_test.cc"], diff --git a/test/core/gprpp/global_config_env_test.cc b/test/core/gprpp/global_config_env_test.cc new file mode 100644 index 00000000000..74905d3b07c --- /dev/null +++ b/test/core/gprpp/global_config_env_test.cc @@ -0,0 +1,130 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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 +#include + +#include + +#include +#include + +#include "src/core/lib/gpr/env.h" +#include "src/core/lib/gprpp/global_config_env.h" +#include "src/core/lib/gprpp/memory.h" + +namespace { + +bool g_config_error_function_called; + +void ClearConfigErrorCalled() { g_config_error_function_called = false; } + +bool IsConfigErrorCalled() { return g_config_error_function_called; } + +// This function is for preventing the program from invoking +// an error handler due to configuration error and +// make test routines know whether there is error. +void FakeConfigErrorFunction(const char* error_message) { + g_config_error_function_called = true; +} + +class GlobalConfigEnvTest : public ::testing::Test { + protected: + void SetUp() override { ClearConfigErrorCalled(); } + void TearDown() override { EXPECT_FALSE(IsConfigErrorCalled()); } +}; + +} // namespace + +GPR_GLOBAL_CONFIG_DEFINE_BOOL(bool_var, true, ""); +GPR_GLOBAL_CONFIG_DEFINE_INT32(int32_var, 1234, ""); +GPR_GLOBAL_CONFIG_DEFINE_STRING(string_var, "Apple", ""); + +TEST_F(GlobalConfigEnvTest, BoolWithEnvTest) { + const char* bool_var_name = "BOOL_VAR"; + + gpr_unsetenv(bool_var_name); + EXPECT_TRUE(GPR_GLOBAL_CONFIG_GET(bool_var)); + + gpr_setenv(bool_var_name, "true"); + EXPECT_TRUE(GPR_GLOBAL_CONFIG_GET(bool_var)); + + gpr_setenv(bool_var_name, "false"); + EXPECT_FALSE(GPR_GLOBAL_CONFIG_GET(bool_var)); + + EXPECT_FALSE(IsConfigErrorCalled()); + + gpr_setenv(bool_var_name, ""); + GPR_GLOBAL_CONFIG_GET(bool_var); + EXPECT_TRUE(IsConfigErrorCalled()); + ClearConfigErrorCalled(); + + gpr_setenv(bool_var_name, "!"); + GPR_GLOBAL_CONFIG_GET(bool_var); + EXPECT_TRUE(IsConfigErrorCalled()); + ClearConfigErrorCalled(); +} + +TEST_F(GlobalConfigEnvTest, Int32WithEnvTest) { + const char* int32_var_name = "INT32_VAR"; + + gpr_unsetenv(int32_var_name); + EXPECT_EQ(1234, GPR_GLOBAL_CONFIG_GET(int32_var)); + + gpr_setenv(int32_var_name, "0"); + EXPECT_EQ(0, GPR_GLOBAL_CONFIG_GET(int32_var)); + + gpr_setenv(int32_var_name, "-123456789"); + EXPECT_EQ(-123456789, GPR_GLOBAL_CONFIG_GET(int32_var)); + + gpr_setenv(int32_var_name, "123456789"); + EXPECT_EQ(123456789, GPR_GLOBAL_CONFIG_GET(int32_var)); + + EXPECT_FALSE(IsConfigErrorCalled()); + + gpr_setenv(int32_var_name, "-1AB"); + GPR_GLOBAL_CONFIG_GET(int32_var); + EXPECT_TRUE(IsConfigErrorCalled()); + ClearConfigErrorCalled(); +} + +TEST_F(GlobalConfigEnvTest, StringWithEnvTest) { + const char* string_var_name = "STRING_VAR"; + grpc_core::UniquePtr value; + + gpr_unsetenv(string_var_name); + value = GPR_GLOBAL_CONFIG_GET(string_var); + EXPECT_EQ(0, strcmp(value.get(), "Apple")); + + gpr_setenv(string_var_name, "Banana"); + value = GPR_GLOBAL_CONFIG_GET(string_var); + EXPECT_EQ(0, strcmp(value.get(), "Banana")); + + gpr_setenv(string_var_name, ""); + value = GPR_GLOBAL_CONFIG_GET(string_var); + EXPECT_EQ(0, strcmp(value.get(), "")); +} + +int main(int argc, char** argv) { + // Not to abort the test when parsing error happens. + grpc_core::SetGlobalConfigEnvErrorFunction(&FakeConfigErrorFunction); + + ::testing::InitGoogleTest(&argc, argv); + int ret = RUN_ALL_TESTS(); + return ret; +} diff --git a/test/core/gprpp/global_config_test.cc b/test/core/gprpp/global_config_test.cc new file mode 100644 index 00000000000..7da78b690b1 --- /dev/null +++ b/test/core/gprpp/global_config_test.cc @@ -0,0 +1,65 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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 +#include + +#include + +#include +#include + +#include "src/core/lib/gpr/env.h" +#include "src/core/lib/gprpp/global_config.h" +#include "src/core/lib/gprpp/memory.h" + +GPR_GLOBAL_CONFIG_DECLARE_BOOL(bool_var); + +GPR_GLOBAL_CONFIG_DEFINE_BOOL(bool_var, false, ""); +GPR_GLOBAL_CONFIG_DEFINE_INT32(int32_var, 0, ""); +GPR_GLOBAL_CONFIG_DEFINE_STRING(string_var, "", ""); + +TEST(GlobalConfigTest, BoolTest) { + EXPECT_FALSE(GPR_GLOBAL_CONFIG_GET(bool_var)); + GPR_GLOBAL_CONFIG_SET(bool_var, true); + EXPECT_TRUE(GPR_GLOBAL_CONFIG_GET(bool_var)); +} + +TEST(GlobalConfigTest, Int32Test) { + EXPECT_EQ(0, GPR_GLOBAL_CONFIG_GET(int32_var)); + GPR_GLOBAL_CONFIG_SET(int32_var, 1024); + EXPECT_EQ(1024, GPR_GLOBAL_CONFIG_GET(int32_var)); +} + +TEST(GlobalConfigTest, StringTest) { + grpc_core::UniquePtr value; + + value = GPR_GLOBAL_CONFIG_GET(string_var); + EXPECT_EQ(0, strcmp(value.get(), "")); + + GPR_GLOBAL_CONFIG_SET(string_var, "Test"); + + value = GPR_GLOBAL_CONFIG_GET(string_var); + EXPECT_EQ(0, strcmp(value.get(), "Test")); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + int ret = RUN_ALL_TESTS(); + return ret; +} diff --git a/test/core/http/httpscli_test.cc b/test/core/http/httpscli_test.cc index 326b0e95e25..e7250c206d8 100644 --- a/test/core/http/httpscli_test.cc +++ b/test/core/http/httpscli_test.cc @@ -29,6 +29,7 @@ #include "src/core/lib/gpr/env.h" #include "src/core/lib/iomgr/iomgr.h" +#include "src/core/lib/security/security_connector/ssl_utils.h" #include "test/core/util/port.h" #include "test/core/util/subprocess.h" #include "test/core/util/test_config.h" @@ -184,7 +185,7 @@ int main(int argc, char** argv) { /* Set the environment variable for the SSL certificate file */ char* pem_file; gpr_asprintf(&pem_file, "%s/src/core/tsi/test_creds/ca.pem", root); - gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, pem_file); + GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, pem_file); gpr_free(pem_file); /* start the server */ diff --git a/test/core/iomgr/resolve_address_posix_test.cc b/test/core/iomgr/resolve_address_posix_test.cc index 826c7e1fafa..112d7c2791b 100644 --- a/test/core/iomgr/resolve_address_posix_test.cc +++ b/test/core/iomgr/resolve_address_posix_test.cc @@ -29,6 +29,7 @@ #include #include +#include "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h" #include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/useful.h" @@ -224,15 +225,16 @@ int main(int argc, char** argv) { // --resolver will always be the first one, so only parse the first argument // (other arguments may be unknown to cl) gpr_cmdline_parse(cl, argc > 2 ? 2 : argc, argv); - const char* cur_resolver = gpr_getenv("GRPC_DNS_RESOLVER"); - if (cur_resolver != nullptr && strlen(cur_resolver) != 0) { + grpc_core::UniquePtr resolver = + GPR_GLOBAL_CONFIG_GET(grpc_dns_resolver); + if (strlen(resolver.get()) != 0) { gpr_log(GPR_INFO, "Warning: overriding resolver setting of %s", - cur_resolver); + resolver.get()); } if (gpr_stricmp(resolver_type, "native") == 0) { - gpr_setenv("GRPC_DNS_RESOLVER", "native"); + GPR_GLOBAL_CONFIG_SET(grpc_dns_resolver, "native"); } else if (gpr_stricmp(resolver_type, "ares") == 0) { - gpr_setenv("GRPC_DNS_RESOLVER", "ares"); + GPR_GLOBAL_CONFIG_SET(grpc_dns_resolver, "ares"); } else { gpr_log(GPR_ERROR, "--resolver_type was not set to ares or native"); abort(); @@ -246,12 +248,12 @@ int main(int argc, char** argv) { // c-ares resolver doesn't support UDS (ability for native DNS resolver // to handle this is only expected to be used by servers, which // unconditionally use the native DNS resolver). - char* resolver_env = gpr_getenv("GRPC_DNS_RESOLVER"); - if (resolver_env == nullptr || gpr_stricmp(resolver_env, "native") == 0) { + grpc_core::UniquePtr resolver = + GPR_GLOBAL_CONFIG_GET(grpc_dns_resolver); + if (gpr_stricmp(resolver.get(), "native") == 0) { test_unix_socket(); test_unix_socket_path_name_too_long(); } - gpr_free(resolver_env); } gpr_cmdline_destroy(cl); diff --git a/test/core/iomgr/resolve_address_test.cc b/test/core/iomgr/resolve_address_test.cc index f59a992416d..cbc03485d7f 100644 --- a/test/core/iomgr/resolve_address_test.cc +++ b/test/core/iomgr/resolve_address_test.cc @@ -27,7 +27,7 @@ #include -#include "src/core/lib/gpr/env.h" +#include "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/iomgr/executor.h" #include "src/core/lib/iomgr/iomgr.h" @@ -83,7 +83,9 @@ static grpc_millis n_sec_deadline(int seconds) { static void poll_pollset_until_request_done(args_struct* args) { grpc_core::ExecCtx exec_ctx; - grpc_millis deadline = n_sec_deadline(10); + // Try to give enough time for c-ares to run through its retries + // a few times if needed. + grpc_millis deadline = n_sec_deadline(90); while (true) { bool done = gpr_atm_acq_load(&args->done_atm) != 0; if (done) { @@ -345,16 +347,17 @@ int main(int argc, char** argv) { // --resolver will always be the first one, so only parse the first argument // (other arguments may be unknown to cl) gpr_cmdline_parse(cl, argc > 2 ? 2 : argc, argv); - const char* cur_resolver = gpr_getenv("GRPC_DNS_RESOLVER"); - if (cur_resolver != nullptr && strlen(cur_resolver) != 0) { + grpc_core::UniquePtr resolver = + GPR_GLOBAL_CONFIG_GET(grpc_dns_resolver); + if (strlen(resolver.get()) != 0) { gpr_log(GPR_INFO, "Warning: overriding resolver setting of %s", - cur_resolver); + resolver.get()); } if (gpr_stricmp(resolver_type, "native") == 0) { - gpr_setenv("GRPC_DNS_RESOLVER", "native"); + GPR_GLOBAL_CONFIG_SET(grpc_dns_resolver, "native"); } else if (gpr_stricmp(resolver_type, "ares") == 0) { #ifndef GRPC_UV - gpr_setenv("GRPC_DNS_RESOLVER", "ares"); + GPR_GLOBAL_CONFIG_SET(grpc_dns_resolver, "ares"); #endif } else { gpr_log(GPR_ERROR, "--resolver_type was not set to ares or native"); @@ -371,15 +374,10 @@ int main(int argc, char** argv) { test_missing_default_port(); test_ipv6_with_port(); test_ipv6_without_port(); - if (gpr_stricmp(resolver_type, "ares") != 0) { - // These tests can trigger DNS queries to the nearby nameserver - // that need to come back in order for the test to succeed. - // c-ares is prone to not using the local system caches that the - // native getaddrinfo implementations take advantage of, so running - // these unit tests under c-ares risks flakiness. - test_invalid_ip_addresses(); - test_unparseable_hostports(); - } else { + test_invalid_ip_addresses(); + test_unparseable_hostports(); + if (gpr_stricmp(resolver_type, "ares") == 0) { + // This behavior expectation is specific to c-ares. test_localhost_result_has_ipv6_first(); } grpc_core::Executor::ShutdownAll(); diff --git a/test/core/security/credentials_test.cc b/test/core/security/credentials_test.cc index 11cfc8cc905..141346bca94 100644 --- a/test/core/security/credentials_test.cc +++ b/test/core/security/credentials_test.cc @@ -1161,7 +1161,7 @@ static void test_get_well_known_google_credentials_file_path(void) { GPR_ASSERT(path != nullptr); gpr_free(path); #if defined(GPR_POSIX_ENV) || defined(GPR_LINUX_ENV) - unsetenv("HOME"); + gpr_unsetenv("HOME"); path = grpc_get_well_known_google_credentials_file_path(); GPR_ASSERT(path == nullptr); gpr_setenv("HOME", home); diff --git a/test/core/security/security_connector_test.cc b/test/core/security/security_connector_test.cc index 496f064439c..c888c90c646 100644 --- a/test/core/security/security_connector_test.cc +++ b/test/core/security/security_connector_test.cc @@ -24,7 +24,6 @@ #include #include -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/tmpfile.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" @@ -394,7 +393,7 @@ static void test_default_ssl_roots(void) { /* First let's get the root through the override: set the env to an invalid value. */ - gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, ""); + GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, ""); grpc_set_ssl_roots_override_callback(override_roots_success); grpc_slice roots = grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting(); @@ -405,7 +404,8 @@ static void test_default_ssl_roots(void) { /* Now let's set the env var: We should get the contents pointed value instead. */ - gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_env_var_file_path); + GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, + roots_env_var_file_path); roots = grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting(); roots_contents = grpc_slice_to_c_string(roots); grpc_slice_unref(roots); @@ -414,7 +414,7 @@ static void test_default_ssl_roots(void) { /* Now reset the env var. We should fall back to the value overridden using the api. */ - gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, ""); + GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, ""); roots = grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting(); roots_contents = grpc_slice_to_c_string(roots); grpc_slice_unref(roots); @@ -423,7 +423,7 @@ static void test_default_ssl_roots(void) { /* Now setup a permanent failure for the overridden roots and we should get an empty slice. */ - gpr_setenv("GRPC_NOT_USE_SYSTEM_SSL_ROOTS", "true"); + GPR_GLOBAL_CONFIG_SET(grpc_not_use_system_ssl_roots, true); grpc_set_ssl_roots_override_callback(override_roots_permanent_failure); roots = grpc_core::TestDefaultSslRootStore::ComputePemRootCertsForTesting(); GPR_ASSERT(GRPC_SLICE_IS_EMPTY(roots)); diff --git a/test/core/slice/slice_buffer_test.cc b/test/core/slice/slice_buffer_test.cc index b53e3312df1..7d4acfed003 100644 --- a/test/core/slice/slice_buffer_test.cc +++ b/test/core/slice/slice_buffer_test.cc @@ -19,6 +19,7 @@ #include #include #include +#include "src/core/lib/slice/slice_internal.h" #include "test/core/util/test_config.h" void test_slice_buffer_add() { @@ -105,12 +106,54 @@ void test_slice_buffer_move_first() { GPR_ASSERT(dst.length == dst_len); } +void test_slice_buffer_first() { + grpc_slice slices[3]; + slices[0] = grpc_slice_from_copied_string("aaa"); + slices[1] = grpc_slice_from_copied_string("bbbb"); + slices[2] = grpc_slice_from_copied_string("ccccc"); + + grpc_slice_buffer buf; + grpc_slice_buffer_init(&buf); + for (int idx = 0; idx < 3; ++idx) { + grpc_slice_ref(slices[idx]); + grpc_slice_buffer_add_indexed(&buf, slices[idx]); + } + + grpc_slice* first = grpc_slice_buffer_peek_first(&buf); + GPR_ASSERT(GPR_SLICE_LENGTH(*first) == GPR_SLICE_LENGTH(slices[0])); + GPR_ASSERT(buf.count == 3); + GPR_ASSERT(buf.length == 12); + + grpc_slice_buffer_sub_first(&buf, 1, 2); + first = grpc_slice_buffer_peek_first(&buf); + GPR_ASSERT(GPR_SLICE_LENGTH(*first) == 1); + GPR_ASSERT(buf.count == 3); + GPR_ASSERT(buf.length == 10); + + grpc_slice_buffer_remove_first(&buf); + first = grpc_slice_buffer_peek_first(&buf); + GPR_ASSERT(GPR_SLICE_LENGTH(*first) == GPR_SLICE_LENGTH(slices[1])); + GPR_ASSERT(buf.count == 2); + GPR_ASSERT(buf.length == 9); + + grpc_slice_buffer_remove_first(&buf); + first = grpc_slice_buffer_peek_first(&buf); + GPR_ASSERT(GPR_SLICE_LENGTH(*first) == GPR_SLICE_LENGTH(slices[2])); + GPR_ASSERT(buf.count == 1); + GPR_ASSERT(buf.length == 5); + + grpc_slice_buffer_remove_first(&buf); + GPR_ASSERT(buf.count == 0); + GPR_ASSERT(buf.length == 0); +} + int main(int argc, char** argv) { grpc::testing::TestEnvironment env(argc, argv); grpc_init(); test_slice_buffer_add(); test_slice_buffer_move_first(); + test_slice_buffer_first(); grpc_shutdown(); return 0; diff --git a/test/core/util/BUILD b/test/core/util/BUILD index 98e69c6ef34..47f814a7ad3 100644 --- a/test/core/util/BUILD +++ b/test/core/util/BUILD @@ -132,6 +132,7 @@ grpc_cc_library( deps = [ ":grpc_test_util", "//:grpc", + "//test/cpp/util:test_config", ], tags = ["no_windows"], ) diff --git a/test/core/util/debugger_macros.cc b/test/core/util/debugger_macros.cc index fed6ad97285..fde68f32178 100644 --- a/test/core/util/debugger_macros.cc +++ b/test/core/util/debugger_macros.cc @@ -21,7 +21,6 @@ * Not intended to be robust for main-line code, often cuts across abstraction * boundaries. */ - #include #include "src/core/ext/filters/client_channel/client_channel.h" @@ -29,8 +28,6 @@ #include "src/core/lib/channel/connected_channel.h" #include "src/core/lib/surface/call.h" -void grpc_summon_debugger_macros() {} - grpc_stream* grpc_transport_stream_from_call(grpc_call* call) { grpc_call_stack* cs = grpc_call_get_call_stack(call); for (;;) { diff --git a/test/core/util/debugger_macros.h b/test/core/util/debugger_macros.h index c6b3720c5ad..71228c6e875 100644 --- a/test/core/util/debugger_macros.h +++ b/test/core/util/debugger_macros.h @@ -19,6 +19,9 @@ #ifndef GRPC_TEST_CORE_UTIL_DEBUGGER_MACROS_H #define GRPC_TEST_CORE_UTIL_DEBUGGER_MACROS_H -void grpc_summon_debugger_macros(); +#include "src/core/ext/transport/chttp2/transport/internal.h" +#include "src/core/lib/surface/call.h" + +grpc_chttp2_stream* grpc_chttp2_stream_from_call(grpc_call* call); #endif /* GRPC_TEST_CORE_UTIL_DEBUGGER_MACROS_H */ diff --git a/test/core/util/fuzzer_corpus_test.cc b/test/core/util/fuzzer_corpus_test.cc index 6e3785c4f74..864533c539b 100644 --- a/test/core/util/fuzzer_corpus_test.cc +++ b/test/core/util/fuzzer_corpus_test.cc @@ -29,6 +29,7 @@ #include "src/core/lib/gpr/env.h" #include "src/core/lib/iomgr/load_file.h" #include "test/core/util/test_config.h" +#include "test/cpp/util/test_config.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); extern bool squelch; @@ -145,8 +146,8 @@ INSTANTIATE_TEST_CASE_P( int main(int argc, char** argv) { grpc::testing::TestEnvironment env(argc, argv); - ParseCommandLineFlags(&argc, &argv, true); ::testing::InitGoogleTest(&argc, argv); + grpc::testing::InitTest(&argc, &argv, true); return RUN_ALL_TESTS(); } diff --git a/test/core/util/reconnect_server.cc b/test/core/util/reconnect_server.cc index ad7cf42f71f..144ad64f095 100644 --- a/test/core/util/reconnect_server.cc +++ b/test/core/util/reconnect_server.cc @@ -109,7 +109,7 @@ void reconnect_server_start(reconnect_server* server, int port) { } void reconnect_server_poll(reconnect_server* server, int seconds) { - test_tcp_server_poll(&server->tcp_server, seconds); + test_tcp_server_poll(&server->tcp_server, 1000 * seconds); } void reconnect_server_clear_timestamps(reconnect_server* server) { diff --git a/test/core/util/test_config.cc b/test/core/util/test_config.cc index 476e424b1eb..5b248a01daa 100644 --- a/test/core/util/test_config.cc +++ b/test/core/util/test_config.cc @@ -28,7 +28,6 @@ #include #include -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/useful.h" #include "src/core/lib/surface/init.h" diff --git a/test/core/util/test_tcp_server.cc b/test/core/util/test_tcp_server.cc index 610a9918ce6..170584df2b9 100644 --- a/test/core/util/test_tcp_server.cc +++ b/test/core/util/test_tcp_server.cc @@ -77,11 +77,11 @@ void test_tcp_server_start(test_tcp_server* server, int port) { gpr_log(GPR_INFO, "test tcp server listening on 0.0.0.0:%d", port); } -void test_tcp_server_poll(test_tcp_server* server, int seconds) { +void test_tcp_server_poll(test_tcp_server* server, int milliseconds) { grpc_pollset_worker* worker = nullptr; grpc_core::ExecCtx exec_ctx; grpc_millis deadline = grpc_timespec_to_millis_round_up( - grpc_timeout_seconds_to_deadline(seconds)); + grpc_timeout_milliseconds_to_deadline(milliseconds)); gpr_mu_lock(server->mu); GRPC_LOG_IF_ERROR("pollset_work", grpc_pollset_work(server->pollset, &worker, deadline)); @@ -102,9 +102,10 @@ void test_tcp_server_destroy(test_tcp_server* server) { grpc_schedule_on_exec_ctx); shutdown_deadline = gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(5, GPR_TIMESPAN)); + grpc_core::ExecCtx::Get()->Flush(); while (!server->shutdown && gpr_time_cmp(gpr_now(GPR_CLOCK_MONOTONIC), shutdown_deadline) < 0) { - test_tcp_server_poll(server, 1); + test_tcp_server_poll(server, 1000); } grpc_pollset_shutdown(server->pollset, GRPC_CLOSURE_CREATE(finish_pollset, server->pollset, diff --git a/test/core/util/test_tcp_server.h b/test/core/util/test_tcp_server.h index 58140388da3..313a27a3334 100644 --- a/test/core/util/test_tcp_server.h +++ b/test/core/util/test_tcp_server.h @@ -35,7 +35,7 @@ typedef struct test_tcp_server { void test_tcp_server_init(test_tcp_server* server, grpc_tcp_server_cb on_connect, void* user_data); void test_tcp_server_start(test_tcp_server* server, int port); -void test_tcp_server_poll(test_tcp_server* server, int seconds); +void test_tcp_server_poll(test_tcp_server* server, int milliseconds); void test_tcp_server_destroy(test_tcp_server* server); #endif /* GRPC_TEST_CORE_UTIL_TEST_TCP_SERVER_H */ diff --git a/test/cpp/client/client_channel_stress_test.cc b/test/cpp/client/client_channel_stress_test.cc index d326b2ed37e..7b4d47276ef 100644 --- a/test/cpp/client/client_channel_stress_test.cc +++ b/test/cpp/client/client_channel_stress_test.cc @@ -268,8 +268,8 @@ class ClientChannelStressTest { response_generator_.get()); std::ostringstream uri; uri << "fake:///servername_not_used"; - channel_ = - CreateCustomChannel(uri.str(), InsecureChannelCredentials(), args); + channel_ = ::grpc::CreateCustomChannel(uri.str(), + InsecureChannelCredentials(), args); stub_ = grpc::testing::EchoTestService::NewStub(channel_); } diff --git a/test/cpp/codegen/BUILD b/test/cpp/codegen/BUILD index 558e5e7818c..90af67bd858 100644 --- a/test/cpp/codegen/BUILD +++ b/test/cpp/codegen/BUILD @@ -66,6 +66,7 @@ grpc_cc_binary( deps = [ "//:grpc++", "//test/core/util:grpc_test_util", + "//test/cpp/util:test_config", ], ) diff --git a/test/cpp/codegen/compiler_test_golden b/test/cpp/codegen/compiler_test_golden index 9e99bc7b0a2..761c3ac6106 100644 --- a/test/cpp/codegen/compiler_test_golden +++ b/test/cpp/codegen/compiler_test_golden @@ -40,14 +40,16 @@ #include #include +namespace grpc_impl { +class CompletionQueue; +class ServerCompletionQueue; +} // namespace grpc_impl + namespace grpc { namespace experimental { template class MessageAllocator; } // namespace experimental -class CompletionQueue; -class Channel; -class ServerCompletionQueue; class ServerContext; } // namespace grpc diff --git a/test/cpp/codegen/golden_file_test.cc b/test/cpp/codegen/golden_file_test.cc index bfd36494941..8951060b94e 100644 --- a/test/cpp/codegen/golden_file_test.cc +++ b/test/cpp/codegen/golden_file_test.cc @@ -22,6 +22,8 @@ #include #include +#include "test/cpp/util/test_config.h" + // In some distros, gflags is in the namespace google, and in some others, // in gflags. This hack is enabling us to find both. namespace google {} @@ -31,7 +33,7 @@ using namespace gflags; DEFINE_string( generated_file_path, "", - "path to the directory containing generated files compiler_test.grpc.pb.h" + "path to the directory containing generated files compiler_test.grpc.pb.h " "and compiler_test_mock.grpc.pb.h"); const char kGoldenFilePath[] = "test/cpp/codegen/compiler_test_golden"; @@ -67,7 +69,7 @@ TEST(GoldenMockFileTest, TestGeneratedMockFile) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); - ParseCommandLineFlags(&argc, &argv, true); + grpc::testing::InitTest(&argc, &argv, true); if (FLAGS_generated_file_path.empty()) { FLAGS_generated_file_path = "gens/src/proto/grpc/testing/"; } diff --git a/test/cpp/end2end/BUILD b/test/cpp/end2end/BUILD index e89667a9714..d229cc33034 100644 --- a/test/cpp/end2end/BUILD +++ b/test/cpp/end2end/BUILD @@ -140,6 +140,7 @@ grpc_cc_binary( "//src/proto/grpc/testing:echo_proto", "//src/proto/grpc/testing/duplicate:echo_duplicate_proto", "//test/core/util:grpc_test_util", + "//test/cpp/util:test_config", "//test/cpp/util:test_util", ], ) @@ -422,6 +423,26 @@ grpc_cc_test( ], ) +grpc_cc_test( + name = "service_config_end2end_test", + srcs = ["service_config_end2end_test.cc"], + external_deps = [ + "gmock", + "gtest", + ], + deps = [ + ":test_service_impl", + "//:gpr", + "//:grpc", + "//:grpc++", + "//src/proto/grpc/testing:echo_messages_proto", + "//src/proto/grpc/testing:echo_proto", + "//src/proto/grpc/testing/duplicate:echo_duplicate_proto", + "//test/core/util:grpc_test_util", + "//test/cpp/util:test_util", + ], +) + grpc_cc_test( name = "grpclb_end2end_test", srcs = ["grpclb_end2end_test.cc"], @@ -544,6 +565,7 @@ grpc_cc_binary( "//src/proto/grpc/testing:echo_proto", "//src/proto/grpc/testing/duplicate:echo_duplicate_proto", "//test/core/util:grpc_test_util", + "//test/cpp/util:test_config", "//test/cpp/util:test_util", ], ) @@ -695,3 +717,21 @@ grpc_cc_test( ], ) +grpc_cc_test( + name = "port_sharing_end2end_test", + srcs = ["port_sharing_end2end_test.cc"], + external_deps = [ + "gtest", + ], + deps = [ + ":test_service_impl", + "//:gpr", + "//:grpc", + "//:grpc++", + "//src/proto/grpc/testing:echo_messages_proto", + "//src/proto/grpc/testing:echo_proto", + "//test/core/util:grpc_test_util", + "//test/cpp/util:test_util", + ], +) + diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc index e09f54dcc3f..6ca0edf123e 100644 --- a/test/cpp/end2end/async_end2end_test.cc +++ b/test/cpp/end2end/async_end2end_test.cc @@ -32,7 +32,7 @@ #include #include -#include "src/core/lib/gpr/env.h" +#include "src/core/ext/filters/client_channel/backup_poller.h" #include "src/core/lib/gpr/tls.h" #include "src/core/lib/iomgr/port.h" #include "src/proto/grpc/health/v1/health.grpc.pb.h" @@ -43,6 +43,10 @@ #include "test/cpp/util/string_ref_helper.h" #include "test/cpp/util/test_credentials_provider.h" +#ifdef GRPC_POSIX_SOCKET +#include "src/core/lib/iomgr/ev_posix.h" +#endif // GRPC_POSIX_SOCKET + #include using grpc::testing::EchoRequest; @@ -294,9 +298,9 @@ class AsyncEnd2endTest : public ::testing::TestWithParam { auto channel_creds = GetCredentialsProvider()->GetChannelCredentials( GetParam().credentials_type, &args); std::shared_ptr channel = - !(GetParam().inproc) - ? CreateCustomChannel(server_address_.str(), channel_creds, args) - : server_->InProcessChannel(args); + !(GetParam().inproc) ? ::grpc::CreateCustomChannel( + server_address_.str(), channel_creds, args) + : server_->InProcessChannel(args); stub_ = grpc::testing::EchoTestService::NewStub(channel); } @@ -358,13 +362,14 @@ TEST_P(AsyncEnd2endTest, ReconnectChannel) { return; } int poller_slowdown_factor = 1; +#ifdef GRPC_POSIX_SOCKET // It needs 2 pollset_works to reconnect the channel with polling engine // "poll" - char* s = gpr_getenv("GRPC_POLL_STRATEGY"); - if (s != nullptr && 0 == strcmp(s, "poll")) { + grpc_core::UniquePtr poller = GPR_GLOBAL_CONFIG_GET(grpc_poll_strategy); + if (0 == strcmp(poller.get(), "poll")) { poller_slowdown_factor = 2; } - gpr_free(s); +#endif // GRPC_POSIX_SOCKET ResetStub(); SendRpc(1); server_->Shutdown(); @@ -1255,9 +1260,9 @@ TEST_P(AsyncEnd2endTest, UnimplementedRpc) { const auto& channel_creds = GetCredentialsProvider()->GetChannelCredentials( GetParam().credentials_type, &args); std::shared_ptr channel = - !(GetParam().inproc) - ? CreateCustomChannel(server_address_.str(), channel_creds, args) - : server_->InProcessChannel(args); + !(GetParam().inproc) ? ::grpc::CreateCustomChannel(server_address_.str(), + channel_creds, args) + : server_->InProcessChannel(args); std::unique_ptr stub; stub = grpc::testing::UnimplementedEchoService::NewStub(channel); EchoRequest send_request; @@ -1883,7 +1888,7 @@ INSTANTIATE_TEST_CASE_P(AsyncEnd2endServerTryCancel, int main(int argc, char** argv) { // Change the backup poll interval from 5s to 100ms to speed up the // ReconnectChannel test - gpr_setenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS", "100"); + GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 100); grpc::testing::TestEnvironment env(argc, argv); ::testing::InitGoogleTest(&argc, argv); int ret = RUN_ALL_TESTS(); diff --git a/test/cpp/end2end/cfstream_test.cc b/test/cpp/end2end/cfstream_test.cc index 63d76e96f8b..59cf98ffc20 100644 --- a/test/cpp/end2end/cfstream_test.cc +++ b/test/cpp/end2end/cfstream_test.cc @@ -45,6 +45,7 @@ #include "test/core/util/port.h" #include "test/core/util/test_config.h" #include "test/cpp/end2end/test_service_impl.h" +#include "test/cpp/util/test_credentials_provider.h" #ifdef GRPC_CFSTREAM using grpc::ClientAsyncResponseReader; @@ -57,13 +58,19 @@ namespace grpc { namespace testing { namespace { -class CFStreamTest : public ::testing::Test { +struct TestScenario { + TestScenario(const grpc::string& creds_type, const grpc::string& content) + : credentials_type(creds_type), message_content(content) {} + const grpc::string credentials_type; + const grpc::string message_content; +}; + +class CFStreamTest : public ::testing::TestWithParam { protected: CFStreamTest() : server_host_("grpctest"), interface_("lo0"), - ipv4_address_("10.0.0.1"), - kRequestMessage_("🖖") {} + ipv4_address_("10.0.0.1") {} void DNSUp() { std::ostringstream cmd; @@ -118,7 +125,7 @@ class CFStreamTest : public ::testing::Test { void StartServer() { port_ = grpc_pick_unused_port_or_die(); - server_.reset(new ServerData(port_)); + server_.reset(new ServerData(port_, GetParam().credentials_type)); server_->Start(server_host_); } void StopServer() { server_->Shutdown(); } @@ -131,8 +138,10 @@ class CFStreamTest : public ::testing::Test { std::shared_ptr BuildChannel() { std::ostringstream server_address; server_address << server_host_ << ":" << port_; - return CreateCustomChannel( - server_address.str(), InsecureChannelCredentials(), ChannelArguments()); + ChannelArguments args; + auto channel_creds = GetCredentialsProvider()->GetChannelCredentials( + GetParam().credentials_type, &args); + return CreateCustomChannel(server_address.str(), channel_creds, args); } void SendRpc( @@ -140,11 +149,12 @@ class CFStreamTest : public ::testing::Test { bool expect_success = false) { auto response = std::unique_ptr(new EchoResponse()); EchoRequest request; - request.set_message(kRequestMessage_); + auto& msg = GetParam().message_content; + request.set_message(msg); ClientContext context; Status status = stub->Echo(&context, request, response.get()); if (status.ok()) { - gpr_log(GPR_DEBUG, "RPC returned %s\n", response->message().c_str()); + EXPECT_EQ(msg, response->message()); } else { gpr_log(GPR_DEBUG, "RPC failed: %s", status.error_message().c_str()); } @@ -156,9 +166,7 @@ class CFStreamTest : public ::testing::Test { const std::unique_ptr& stub, RequestParams param = RequestParams()) { EchoRequest request; - auto msg = std::to_string(ctr.load()); - request.set_message(msg); - ctr++; + request.set_message(GetParam().message_content); *request.mutable_param() = std::move(param); AsyncClientCall* call = new AsyncClientCall; @@ -166,7 +174,6 @@ class CFStreamTest : public ::testing::Test { stub->PrepareAsyncEcho(&call->context, request, &cq_); call->response_reader->StartCall(); - gpr_log(GPR_DEBUG, "Sending request: %s", msg.c_str()); call->response_reader->Finish(&call->reply, &call->status, (void*)call); } @@ -206,12 +213,14 @@ class CFStreamTest : public ::testing::Test { private: struct ServerData { int port_; + const grpc::string creds_; std::unique_ptr server_; TestServiceImpl service_; std::unique_ptr thread_; bool server_ready_ = false; - explicit ServerData(int port) { port_ = port; } + ServerData(int port, const grpc::string& creds) + : port_(port), creds_(creds) {} void Start(const grpc::string& server_host) { gpr_log(GPR_INFO, "starting server on port %d", port_); @@ -230,8 +239,9 @@ class CFStreamTest : public ::testing::Test { std::ostringstream server_address; server_address << server_host << ":" << port_; ServerBuilder builder; - builder.AddListeningPort(server_address.str(), - InsecureServerCredentials()); + auto server_creds = + GetCredentialsProvider()->GetServerCredentials(creds_); + builder.AddListeningPort(server_address.str(), server_creds); builder.RegisterService(&service_); server_ = builder.BuildAndStart(); std::lock_guard lock(*mu); @@ -251,13 +261,44 @@ class CFStreamTest : public ::testing::Test { const grpc::string ipv4_address_; std::unique_ptr server_; int port_; - const grpc::string kRequestMessage_; - std::atomic_int ctr{0}; }; +std::vector CreateTestScenarios() { + std::vector scenarios; + std::vector credentials_types; + std::vector messages; + + credentials_types.push_back(kInsecureCredentialsType); + auto sec_list = GetCredentialsProvider()->GetSecureCredentialsTypeList(); + for (auto sec = sec_list.begin(); sec != sec_list.end(); sec++) { + credentials_types.push_back(*sec); + } + + messages.push_back("🖖"); + for (size_t k = 1; k < GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH / 1024; k *= 32) { + grpc::string big_msg; + for (size_t i = 0; i < k * 1024; ++i) { + char c = 'a' + (i % 26); + big_msg += c; + } + messages.push_back(big_msg); + } + for (auto cred = credentials_types.begin(); cred != credentials_types.end(); + ++cred) { + for (auto msg = messages.begin(); msg != messages.end(); msg++) { + scenarios.emplace_back(*cred, *msg); + } + } + + return scenarios; +} + +INSTANTIATE_TEST_CASE_P(CFStreamTest, CFStreamTest, + ::testing::ValuesIn(CreateTestScenarios())); + // gRPC should automatically detech network flaps (without enabling keepalives) // when CFStream is enabled -TEST_F(CFStreamTest, NetworkTransition) { +TEST_P(CFStreamTest, NetworkTransition) { auto channel = BuildChannel(); auto stub = BuildStub(channel); // Channel should be in READY state after we send an RPC @@ -293,7 +334,7 @@ TEST_F(CFStreamTest, NetworkTransition) { } // Network flaps while RPCs are in flight -TEST_F(CFStreamTest, NetworkFlapRpcsInFlight) { +TEST_P(CFStreamTest, NetworkFlapRpcsInFlight) { auto channel = BuildChannel(); auto stub = BuildStub(channel); std::atomic_int rpcs_sent{0}; @@ -318,9 +359,7 @@ TEST_F(CFStreamTest, NetworkFlapRpcsInFlight) { ++total_completions; GPR_ASSERT(ok); AsyncClientCall* call = static_cast(got_tag); - if (call->status.ok()) { - gpr_log(GPR_DEBUG, "RPC response: %s", call->reply.message().c_str()); - } else { + if (!call->status.ok()) { gpr_log(GPR_DEBUG, "RPC failed with error: %s", call->status.error_message().c_str()); // Bring network up when RPCs start failing @@ -347,7 +386,7 @@ TEST_F(CFStreamTest, NetworkFlapRpcsInFlight) { // Send a bunch of RPCs, some of which are expected to fail. // We should get back a response for all RPCs -TEST_F(CFStreamTest, ConcurrentRpc) { +TEST_P(CFStreamTest, ConcurrentRpc) { auto channel = BuildChannel(); auto stub = BuildStub(channel); std::atomic_int rpcs_sent{0}; @@ -361,9 +400,7 @@ TEST_F(CFStreamTest, ConcurrentRpc) { ++total_completions; GPR_ASSERT(ok); AsyncClientCall* call = static_cast(got_tag); - if (call->status.ok()) { - gpr_log(GPR_DEBUG, "RPC response: %s", call->reply.message().c_str()); - } else { + if (!call->status.ok()) { gpr_log(GPR_DEBUG, "RPC failed: %s", call->status.error_message().c_str()); // Bring network up when RPCs start failing diff --git a/test/cpp/end2end/channelz_service_test.cc b/test/cpp/end2end/channelz_service_test.cc index fe52a64db48..26ef59fbeb3 100644 --- a/test/cpp/end2end/channelz_service_test.cc +++ b/test/cpp/end2end/channelz_service_test.cc @@ -145,7 +145,7 @@ class ChannelzServerTest : public ::testing::Test { ChannelArguments args; args.SetInt(GRPC_ARG_ENABLE_CHANNELZ, 1); args.SetInt(GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE, 1024); - std::shared_ptr channel_to_backend = CreateCustomChannel( + std::shared_ptr channel_to_backend = ::grpc::CreateCustomChannel( backend_server_address, InsecureChannelCredentials(), args); proxy_service_.AddChannelToBackend(channel_to_backend); } @@ -157,7 +157,7 @@ class ChannelzServerTest : public ::testing::Test { // disable channelz. We only want to focus on proxy to backend outbound. args.SetInt(GRPC_ARG_ENABLE_CHANNELZ, 0); std::shared_ptr channel = - CreateCustomChannel(target, InsecureChannelCredentials(), args); + ::grpc::CreateCustomChannel(target, InsecureChannelCredentials(), args); channelz_stub_ = grpc::channelz::v1::Channelz::NewStub(channel); echo_stub_ = grpc::testing::EchoTestService::NewStub(channel); } @@ -171,7 +171,7 @@ class ChannelzServerTest : public ::testing::Test { // This ensures that gRPC will not do connection sharing. args.SetInt("salt", salt++); std::shared_ptr channel = - CreateCustomChannel(target, InsecureChannelCredentials(), args); + ::grpc::CreateCustomChannel(target, InsecureChannelCredentials(), args); return grpc::testing::EchoTestService::NewStub(channel); } diff --git a/test/cpp/end2end/client_callback_end2end_test.cc b/test/cpp/end2end/client_callback_end2end_test.cc index f0d159ba2a2..a154324216b 100644 --- a/test/cpp/end2end/client_callback_end2end_test.cc +++ b/test/cpp/end2end/client_callback_end2end_test.cc @@ -104,10 +104,6 @@ class ClientCallbackEnd2endTest // TODO(vjpai): Support testing of AuthMetadataProcessor if (GetParam().protocol == Protocol::TCP) { - if (!grpc_iomgr_run_in_background()) { - do_not_test_ = true; - return; - } picked_port_ = grpc_pick_unused_port_or_die(); server_address_ << "localhost:" << picked_port_; builder.AddListeningPort(server_address_.str(), server_creds); @@ -133,6 +129,10 @@ class ClientCallbackEnd2endTest server_ = builder.BuildAndStart(); is_server_started_ = true; + if (GetParam().protocol == Protocol::TCP && + !grpc_iomgr_run_in_background()) { + do_not_test_ = true; + } } void ResetStub() { @@ -142,8 +142,8 @@ class ClientCallbackEnd2endTest switch (GetParam().protocol) { case Protocol::TCP: if (!GetParam().use_interceptors) { - channel_ = - CreateCustomChannel(server_address_.str(), channel_creds, args); + channel_ = ::grpc::CreateCustomChannel(server_address_.str(), + channel_creds, args); } else { channel_ = CreateCustomChannelWithInterceptors( server_address_.str(), channel_creds, args, @@ -536,9 +536,9 @@ TEST_P(ClientCallbackEnd2endTest, RequestEchoServerCancel) { struct ClientCancelInfo { bool cancel{false}; int ops_before_cancel; + ClientCancelInfo() : cancel{false} {} - // Allow the single-op version to be non-explicit for ease of use - ClientCancelInfo(int ops) : cancel{true}, ops_before_cancel{ops} {} + explicit ClientCancelInfo(int ops) : cancel{true}, ops_before_cancel{ops} {} }; class WriteClient : public grpc::experimental::ClientWriteReactor { @@ -651,7 +651,7 @@ TEST_P(ClientCallbackEnd2endTest, RequestStream) { TEST_P(ClientCallbackEnd2endTest, ClientCancelsRequestStream) { MAYBE_SKIP_TEST; ResetStub(); - WriteClient test{stub_.get(), DO_NOT_CANCEL, 3, {2}}; + WriteClient test{stub_.get(), DO_NOT_CANCEL, 3, ClientCancelInfo{2}}; test.Await(); // Make sure that the server interceptors got the cancel if (GetParam().use_interceptors) { @@ -869,7 +869,7 @@ TEST_P(ClientCallbackEnd2endTest, ResponseStream) { TEST_P(ClientCallbackEnd2endTest, ClientCancelsResponseStream) { MAYBE_SKIP_TEST; ResetStub(); - ReadClient test{stub_.get(), DO_NOT_CANCEL, 2}; + ReadClient test{stub_.get(), DO_NOT_CANCEL, ClientCancelInfo{2}}; test.Await(); // Because cancel in this case races with server finish, we can't be sure that // server interceptors even see cancellation @@ -1052,7 +1052,7 @@ TEST_P(ClientCallbackEnd2endTest, ClientCancelsBidiStream) { MAYBE_SKIP_TEST; ResetStub(); BidiClient test{stub_.get(), DO_NOT_CANCEL, - kServerDefaultResponseStreamsToSend, 2}; + kServerDefaultResponseStreamsToSend, ClientCancelInfo{2}}; test.Await(); // Make sure that the server interceptors were notified of a cancel if (GetParam().use_interceptors) { @@ -1153,7 +1153,8 @@ TEST_P(ClientCallbackEnd2endTest, UnimplementedRpc) { GetParam().credentials_type, &args); std::shared_ptr channel = (GetParam().protocol == Protocol::TCP) - ? CreateCustomChannel(server_address_.str(), channel_creds, args) + ? ::grpc::CreateCustomChannel(server_address_.str(), channel_creds, + args) : server_->InProcessChannel(args); std::unique_ptr stub; stub = grpc::testing::UnimplementedEchoService::NewStub(channel); diff --git a/test/cpp/end2end/client_crash_test.cc b/test/cpp/end2end/client_crash_test.cc index 992f3c488f9..2d5c1b47b17 100644 --- a/test/cpp/end2end/client_crash_test.cc +++ b/test/cpp/end2end/client_crash_test.cc @@ -60,7 +60,7 @@ class CrashTest : public ::testing::Test { })); GPR_ASSERT(server_); return grpc::testing::EchoTestService::NewStub( - CreateChannel(addr, InsecureChannelCredentials())); + grpc::CreateChannel(addr, InsecureChannelCredentials())); } void KillServer() { server_.reset(); } diff --git a/test/cpp/end2end/client_crash_test_server.cc b/test/cpp/end2end/client_crash_test_server.cc index cb4afd71670..d92f9c5cff3 100644 --- a/test/cpp/end2end/client_crash_test_server.cc +++ b/test/cpp/end2end/client_crash_test_server.cc @@ -27,6 +27,7 @@ #include #include "src/proto/grpc/testing/echo.grpc.pb.h" +#include "test/cpp/util/test_config.h" DEFINE_string(address, "", "Address to bind to"); @@ -72,7 +73,7 @@ void RunServer() { } // namespace grpc int main(int argc, char** argv) { - ParseCommandLineFlags(&argc, &argv, true); + grpc::testing::InitTest(&argc, &argv, true); grpc::testing::RunServer(); return 0; diff --git a/test/cpp/end2end/client_lb_end2end_test.cc b/test/cpp/end2end/client_lb_end2end_test.cc index 6623a2ff55f..b623348e13f 100644 --- a/test/cpp/end2end/client_lb_end2end_test.cc +++ b/test/cpp/end2end/client_lb_end2end_test.cc @@ -37,13 +37,13 @@ #include #include +#include "src/core/ext/filters/client_channel/backup_poller.h" #include "src/core/ext/filters/client_channel/global_subchannel_pool.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" #include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gprpp/debug_location.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/tcp_client.h" @@ -142,7 +142,7 @@ class ClientLbEnd2endTest : public ::testing::Test { grpc_fake_transport_security_credentials_create())) { // Make the backup poller poll very frequently in order to pick up // updates from all the subchannels's FDs. - gpr_setenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS", "1"); + GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 1); } void SetUp() override { @@ -237,7 +237,7 @@ class ClientLbEnd2endTest : public ::testing::Test { } // else, default to pick first args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR, response_generator_.get()); - return CreateCustomChannel("fake:///", creds_, args); + return ::grpc::CreateCustomChannel("fake:///", creds_, args); } bool SendRpc( @@ -1019,8 +1019,8 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) { auto channel = BuildChannel("round_robin"); auto stub = BuildStub(channel); std::vector ports; - // Start with a single server. + gpr_log(GPR_INFO, "*** FIRST BACKEND ***"); ports.emplace_back(servers_[0]->port_); SetNextResolution(ports); WaitForServer(stub, 0, DEBUG_LOCATION); @@ -1030,36 +1030,33 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) { EXPECT_EQ(0, servers_[1]->service_.request_count()); EXPECT_EQ(0, servers_[2]->service_.request_count()); servers_[0]->service_.ResetCounters(); - // And now for the second server. + gpr_log(GPR_INFO, "*** SECOND BACKEND ***"); ports.clear(); ports.emplace_back(servers_[1]->port_); SetNextResolution(ports); - // Wait until update has been processed, as signaled by the second backend // receiving a request. EXPECT_EQ(0, servers_[1]->service_.request_count()); WaitForServer(stub, 1, DEBUG_LOCATION); - for (size_t i = 0; i < 10; ++i) CheckRpcSendOk(stub, DEBUG_LOCATION); EXPECT_EQ(0, servers_[0]->service_.request_count()); EXPECT_EQ(10, servers_[1]->service_.request_count()); EXPECT_EQ(0, servers_[2]->service_.request_count()); servers_[1]->service_.ResetCounters(); - // ... and for the last server. + gpr_log(GPR_INFO, "*** THIRD BACKEND ***"); ports.clear(); ports.emplace_back(servers_[2]->port_); SetNextResolution(ports); WaitForServer(stub, 2, DEBUG_LOCATION); - for (size_t i = 0; i < 10; ++i) CheckRpcSendOk(stub, DEBUG_LOCATION); EXPECT_EQ(0, servers_[0]->service_.request_count()); EXPECT_EQ(0, servers_[1]->service_.request_count()); EXPECT_EQ(10, servers_[2]->service_.request_count()); servers_[2]->service_.ResetCounters(); - // Back to all servers. + gpr_log(GPR_INFO, "*** ALL BACKENDS ***"); ports.clear(); ports.emplace_back(servers_[0]->port_); ports.emplace_back(servers_[1]->port_); @@ -1068,14 +1065,13 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) { WaitForServer(stub, 0, DEBUG_LOCATION); WaitForServer(stub, 1, DEBUG_LOCATION); WaitForServer(stub, 2, DEBUG_LOCATION); - // Send three RPCs, one per server. for (size_t i = 0; i < 3; ++i) CheckRpcSendOk(stub, DEBUG_LOCATION); EXPECT_EQ(1, servers_[0]->service_.request_count()); EXPECT_EQ(1, servers_[1]->service_.request_count()); EXPECT_EQ(1, servers_[2]->service_.request_count()); - // An empty update will result in the channel going into TRANSIENT_FAILURE. + gpr_log(GPR_INFO, "*** NO BACKENDS ***"); ports.clear(); SetNextResolution(ports); grpc_connectivity_state channel_state; @@ -1084,15 +1080,14 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) { } while (channel_state == GRPC_CHANNEL_READY); ASSERT_NE(channel_state, GRPC_CHANNEL_READY); servers_[0]->service_.ResetCounters(); - // Next update introduces servers_[1], making the channel recover. + gpr_log(GPR_INFO, "*** BACK TO SECOND BACKEND ***"); ports.clear(); ports.emplace_back(servers_[1]->port_); SetNextResolution(ports); WaitForServer(stub, 1, DEBUG_LOCATION); channel_state = channel->GetState(false /* try to connect */); ASSERT_EQ(channel_state, GRPC_CHANNEL_READY); - // Check LB policy name for the channel. EXPECT_EQ("round_robin", channel->GetLoadBalancingPolicyName()); } @@ -1211,8 +1206,9 @@ TEST_F(ClientLbEnd2endTest, RoundRobinSingleReconnect) { auto channel = BuildChannel("round_robin"); auto stub = BuildStub(channel); SetNextResolution(ports); - for (size_t i = 0; i < kNumServers; ++i) + for (size_t i = 0; i < kNumServers; ++i) { WaitForServer(stub, i, DEBUG_LOCATION); + } for (size_t i = 0; i < servers_.size(); ++i) { CheckRpcSendOk(stub, DEBUG_LOCATION); EXPECT_EQ(1, servers_[i]->service_.request_count()) << "for backend #" << i; @@ -1236,7 +1232,6 @@ TEST_F(ClientLbEnd2endTest, RoundRobinSingleReconnect) { // No requests have gone to the deceased server. EXPECT_EQ(pre_death, post_death); // Bring the first server back up. - servers_[0].reset(new ServerData(ports[0])); StartServer(0); // Requests should start arriving at the first server either right away (if // the server managed to start before the RR policy retried the subchannel) or @@ -1360,6 +1355,52 @@ TEST_F(ClientLbEnd2endTest, RoundRobinWithHealthCheckingInhibitPerChannel) { // Second channel should be READY. EXPECT_TRUE(WaitForChannelReady(channel2.get(), 1)); CheckRpcSendOk(stub2, DEBUG_LOCATION); + // Enable health checks on the backend and wait for channel 1 to succeed. + servers_[0]->SetServingStatus("health_check_service_name", true); + CheckRpcSendOk(stub1, DEBUG_LOCATION, true /* wait_for_ready */); + // Check that we created only one subchannel to the backend. + EXPECT_EQ(1UL, servers_[0]->service_.clients().size()); + // Clean up. + EnableDefaultHealthCheckService(false); +} + +TEST_F(ClientLbEnd2endTest, RoundRobinWithHealthCheckingServiceNamePerChannel) { + EnableDefaultHealthCheckService(true); + // Start server. + const int kNumServers = 1; + StartServers(kNumServers); + // Create a channel with health-checking enabled. + ChannelArguments args; + args.SetServiceConfigJSON( + "{\"healthCheckConfig\": " + "{\"serviceName\": \"health_check_service_name\"}}"); + auto channel1 = BuildChannel("round_robin", args); + auto stub1 = BuildStub(channel1); + std::vector ports = GetServersPorts(); + SetNextResolution(ports); + // Create a channel with health-checking enabled with a different + // service name. + ChannelArguments args2; + args2.SetServiceConfigJSON( + "{\"healthCheckConfig\": " + "{\"serviceName\": \"health_check_service_name2\"}}"); + auto channel2 = BuildChannel("round_robin", args2); + auto stub2 = BuildStub(channel2); + SetNextResolution(ports); + // Allow health checks from channel 2 to succeed. + servers_[0]->SetServingStatus("health_check_service_name2", true); + // First channel should not become READY, because health checks should be + // failing. + EXPECT_FALSE(WaitForChannelReady(channel1.get(), 1)); + CheckRpcSendFailure(stub1); + // Second channel should be READY. + EXPECT_TRUE(WaitForChannelReady(channel2.get(), 1)); + CheckRpcSendOk(stub2, DEBUG_LOCATION); + // Enable health checks for channel 1 and wait for it to succeed. + servers_[0]->SetServingStatus("health_check_service_name", true); + CheckRpcSendOk(stub1, DEBUG_LOCATION, true /* wait_for_ready */); + // Check that we created only one subchannel to the backend. + EXPECT_EQ(1UL, servers_[0]->service_.clients().size()); // Clean up. EnableDefaultHealthCheckService(false); } diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index fb951fd44e6..c027e5954ec 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -34,7 +34,7 @@ #include #include -#include "src/core/lib/gpr/env.h" +#include "src/core/ext/filters/client_channel/backup_poller.h" #include "src/core/lib/iomgr/iomgr.h" #include "src/core/lib/security/credentials/credentials.h" #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h" @@ -46,6 +46,10 @@ #include "test/cpp/util/string_ref_helper.h" #include "test/cpp/util/test_credentials_provider.h" +#ifdef GRPC_POSIX_SOCKET +#include "src/core/lib/iomgr/ev_posix.h" +#endif // GRPC_POSIX_SOCKET + #include using grpc::testing::EchoRequest; @@ -129,7 +133,7 @@ class TestAuthMetadataProcessor : public AuthMetadataProcessor { TestAuthMetadataProcessor(bool is_blocking) : is_blocking_(is_blocking) {} std::shared_ptr GetCompatibleClientCreds() { - return MetadataCredentialsFromPlugin( + return grpc::MetadataCredentialsFromPlugin( std::unique_ptr( new TestMetadataCredentialsPlugin( TestMetadataCredentialsPlugin::kGoodMetadataKey, kGoodGuy, @@ -137,7 +141,7 @@ class TestAuthMetadataProcessor : public AuthMetadataProcessor { } std::shared_ptr GetIncompatibleClientCreds() { - return MetadataCredentialsFromPlugin( + return grpc::MetadataCredentialsFromPlugin( std::unique_ptr( new TestMetadataCredentialsPlugin( TestMetadataCredentialsPlugin::kGoodMetadataKey, "Mr Hyde", @@ -340,8 +344,8 @@ class End2endTest : public ::testing::TestWithParam { if (!GetParam().inproc) { if (!GetParam().use_interceptors) { - channel_ = - CreateCustomChannel(server_address_.str(), channel_creds, args); + channel_ = ::grpc::CreateCustomChannel(server_address_.str(), + channel_creds, args); } else { channel_ = CreateCustomChannelWithInterceptors( server_address_.str(), channel_creds, args, @@ -374,7 +378,8 @@ class End2endTest : public ::testing::TestWithParam { proxy_server_ = builder.BuildAndStart(); - channel_ = CreateChannel(proxyaddr.str(), InsecureChannelCredentials()); + channel_ = + grpc::CreateChannel(proxyaddr.str(), InsecureChannelCredentials()); } stub_ = grpc::testing::EchoTestService::NewStub(channel_); @@ -807,11 +812,12 @@ TEST_P(End2endTest, ReconnectChannel) { int poller_slowdown_factor = 1; // It needs 2 pollset_works to reconnect the channel with polling engine // "poll" - char* s = gpr_getenv("GRPC_POLL_STRATEGY"); - if (s != nullptr && 0 == strcmp(s, "poll")) { +#ifdef GRPC_POSIX_SOCKET + grpc_core::UniquePtr poller = GPR_GLOBAL_CONFIG_GET(grpc_poll_strategy); + if (0 == strcmp(poller.get(), "poll")) { poller_slowdown_factor = 2; } - gpr_free(s); +#endif // GRPC_POSIX_SOCKET ResetStub(); SendRpc(stub_.get(), 1, false); RestartServer(std::shared_ptr()); @@ -1277,7 +1283,7 @@ TEST_P(End2endTest, ChannelStateTimeout) { server_address << "127.0.0.1:" << port; // Channel to non-existing server auto channel = - CreateChannel(server_address.str(), InsecureChannelCredentials()); + grpc::CreateChannel(server_address.str(), InsecureChannelCredentials()); // Start IDLE EXPECT_EQ(GRPC_CHANNEL_IDLE, channel->GetState(true)); @@ -1825,8 +1831,8 @@ TEST_P(SecureEnd2endTest, AuthMetadataPluginKeyFailure) { EchoRequest request; EchoResponse response; ClientContext context; - context.set_credentials( - MetadataCredentialsFromPlugin(std::unique_ptr( + context.set_credentials(grpc::MetadataCredentialsFromPlugin( + std::unique_ptr( new TestMetadataCredentialsPlugin( TestMetadataCredentialsPlugin::kBadMetadataKey, "Does not matter, will fail the key is invalid.", false, true)))); @@ -1843,8 +1849,8 @@ TEST_P(SecureEnd2endTest, AuthMetadataPluginValueFailure) { EchoRequest request; EchoResponse response; ClientContext context; - context.set_credentials( - MetadataCredentialsFromPlugin(std::unique_ptr( + context.set_credentials(grpc::MetadataCredentialsFromPlugin( + std::unique_ptr( new TestMetadataCredentialsPlugin( TestMetadataCredentialsPlugin::kGoodMetadataKey, "With illegal \n value.", false, true)))); @@ -1861,8 +1867,8 @@ TEST_P(SecureEnd2endTest, NonBlockingAuthMetadataPluginFailure) { EchoRequest request; EchoResponse response; ClientContext context; - context.set_credentials( - MetadataCredentialsFromPlugin(std::unique_ptr( + context.set_credentials(grpc::MetadataCredentialsFromPlugin( + std::unique_ptr( new TestMetadataCredentialsPlugin( TestMetadataCredentialsPlugin::kGoodMetadataKey, "Does not matter, will fail anyway (see 3rd param)", false, @@ -1925,8 +1931,8 @@ TEST_P(SecureEnd2endTest, BlockingAuthMetadataPluginFailure) { EchoRequest request; EchoResponse response; ClientContext context; - context.set_credentials( - MetadataCredentialsFromPlugin(std::unique_ptr( + context.set_credentials(grpc::MetadataCredentialsFromPlugin( + std::unique_ptr( new TestMetadataCredentialsPlugin( TestMetadataCredentialsPlugin::kGoodMetadataKey, "Does not matter, will fail anyway (see 3rd param)", true, @@ -1952,13 +1958,15 @@ TEST_P(SecureEnd2endTest, CompositeCallCreds) { const char kMetadataVal1[] = "call-creds-val1"; const char kMetadataVal2[] = "call-creds-val2"; - context.set_credentials(CompositeCallCredentials( - MetadataCredentialsFromPlugin(std::unique_ptr( - new TestMetadataCredentialsPlugin(kMetadataKey1, kMetadataVal1, true, - true))), - MetadataCredentialsFromPlugin(std::unique_ptr( - new TestMetadataCredentialsPlugin(kMetadataKey2, kMetadataVal2, true, - true))))); + context.set_credentials(grpc::CompositeCallCredentials( + grpc::MetadataCredentialsFromPlugin( + std::unique_ptr( + new TestMetadataCredentialsPlugin(kMetadataKey1, kMetadataVal1, + true, true))), + grpc::MetadataCredentialsFromPlugin( + std::unique_ptr( + new TestMetadataCredentialsPlugin(kMetadataKey2, kMetadataVal2, + true, true))))); request.set_message("Hello"); request.mutable_param()->set_echo_metadata(true); @@ -2104,8 +2112,12 @@ INSTANTIATE_TEST_CASE_P( } // namespace grpc int main(int argc, char** argv) { - gpr_setenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS", "200"); + GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 200); grpc::testing::TestEnvironment env(argc, argv); + // The grpc_init is to cover the MAYBE_SKIP_TEST. + grpc_init(); ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + int ret = RUN_ALL_TESTS(); + grpc_shutdown(); + return ret; } diff --git a/test/cpp/end2end/filter_end2end_test.cc b/test/cpp/end2end/filter_end2end_test.cc index ad67402e3df..a4c981a3eb1 100644 --- a/test/cpp/end2end/filter_end2end_test.cc +++ b/test/cpp/end2end/filter_end2end_test.cc @@ -146,8 +146,8 @@ class FilterEnd2endTest : public ::testing::Test { } void ResetStub() { - std::shared_ptr channel = - CreateChannel(server_address_.str(), InsecureChannelCredentials()); + std::shared_ptr channel = grpc::CreateChannel( + server_address_.str(), InsecureChannelCredentials()); generic_stub_.reset(new GenericStub(channel)); ResetConnectionCounter(); ResetCallCounter(); diff --git a/test/cpp/end2end/flaky_network_test.cc b/test/cpp/end2end/flaky_network_test.cc index 63a6897f931..626b5a56226 100644 --- a/test/cpp/end2end/flaky_network_test.cc +++ b/test/cpp/end2end/flaky_network_test.cc @@ -16,12 +16,6 @@ * */ -#include -#include -#include -#include -#include - #include #include #include @@ -35,16 +29,22 @@ #include #include #include +#include + +#include +#include +#include +#include +#include #include "src/core/lib/backoff/backoff.h" #include "src/core/lib/gpr/env.h" - #include "src/proto/grpc/testing/echo.grpc.pb.h" +#include "test/core/util/debugger_macros.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" #include "test/cpp/end2end/test_service_impl.h" - -#include +#include "test/cpp/util/test_credentials_provider.h" #ifdef GPR_LINUX using grpc::testing::EchoRequest; @@ -54,14 +54,20 @@ namespace grpc { namespace testing { namespace { -class FlakyNetworkTest : public ::testing::Test { +struct TestScenario { + TestScenario(const grpc::string& creds_type, const grpc::string& content) + : credentials_type(creds_type), message_content(content) {} + const grpc::string credentials_type; + const grpc::string message_content; +}; + +class FlakyNetworkTest : public ::testing::TestWithParam { protected: FlakyNetworkTest() : server_host_("grpctest"), interface_("lo:1"), ipv4_address_("10.0.0.1"), - netmask_("/32"), - kRequestMessage_("🖖") {} + netmask_("/32") {} void InterfaceUp() { std::ostringstream cmd; @@ -129,10 +135,11 @@ class FlakyNetworkTest : public ::testing::Test { void FlakeNetwork() { std::ostringstream cmd; // Emulate a flaky network connection over interface_. Add a delay of 100ms - // +/- 590ms, 3% packet loss, 1% duplicates and 0.1% corrupt packets. + // +/- 20ms, 0.1% packet loss, 1% duplicates and 0.01% corrupt packets. cmd << "tc qdisc replace dev " << interface_ - << " root netem delay 100ms 50ms distribution normal loss 3% duplicate " - "1% corrupt 0.1% "; + << " root netem delay 100ms 20ms distribution normal loss 0.1% " + "duplicate " + "0.1% corrupt 0.01% "; std::system(cmd.str().c_str()); } @@ -172,7 +179,7 @@ class FlakyNetworkTest : public ::testing::Test { // ip6-looopback, but ipv6 support is not enabled by default in docker. port_ = SERVER_PORT; - server_.reset(new ServerData(port_)); + server_.reset(new ServerData(port_, GetParam().credentials_type)); server_->Start(server_host_); } void StopServer() { server_->Shutdown(); } @@ -188,10 +195,11 @@ class FlakyNetworkTest : public ::testing::Test { if (lb_policy_name.size() > 0) { args.SetLoadBalancingPolicyName(lb_policy_name); } // else, default to pick first + auto channel_creds = GetCredentialsProvider()->GetChannelCredentials( + GetParam().credentials_type, &args); std::ostringstream server_address; server_address << server_host_ << ":" << port_; - return CreateCustomChannel(server_address.str(), - InsecureChannelCredentials(), args); + return CreateCustomChannel(server_address.str(), channel_creds, args); } bool SendRpc( @@ -199,7 +207,8 @@ class FlakyNetworkTest : public ::testing::Test { int timeout_ms = 0, bool wait_for_ready = false) { auto response = std::unique_ptr(new EchoResponse()); EchoRequest request; - request.set_message(kRequestMessage_); + auto& msg = GetParam().message_content; + request.set_message(msg); ClientContext context; if (timeout_ms > 0) { context.set_deadline(grpc_timeout_milliseconds_to_deadline(timeout_ms)); @@ -211,22 +220,33 @@ class FlakyNetworkTest : public ::testing::Test { } Status status = stub->Echo(&context, request, response.get()); auto ok = status.ok(); + int stream_id = 0; + grpc_call* call = context.c_call(); + if (call) { + grpc_chttp2_stream* stream = grpc_chttp2_stream_from_call(call); + if (stream) { + stream_id = stream->id; + } + } if (ok) { - gpr_log(GPR_DEBUG, "RPC returned %s\n", response->message().c_str()); + gpr_log(GPR_DEBUG, "RPC with stream_id %d succeeded", stream_id); } else { - gpr_log(GPR_DEBUG, "RPC failed: %s", status.error_message().c_str()); + gpr_log(GPR_DEBUG, "RPC with stream_id %d failed: %s", stream_id, + status.error_message().c_str()); } return ok; } struct ServerData { int port_; + const grpc::string creds_; std::unique_ptr server_; TestServiceImpl service_; std::unique_ptr thread_; bool server_ready_ = false; - explicit ServerData(int port) { port_ = port; } + ServerData(int port, const grpc::string& creds) + : port_(port), creds_(creds) {} void Start(const grpc::string& server_host) { gpr_log(GPR_INFO, "starting server on port %d", port_); @@ -245,8 +265,9 @@ class FlakyNetworkTest : public ::testing::Test { std::ostringstream server_address; server_address << server_host << ":" << port_; ServerBuilder builder; - builder.AddListeningPort(server_address.str(), - InsecureServerCredentials()); + auto server_creds = + GetCredentialsProvider()->GetServerCredentials(creds_); + builder.AddListeningPort(server_address.str(), server_creds); builder.RegisterService(&service_); server_ = builder.BuildAndStart(); std::lock_guard lock(*mu); @@ -291,11 +312,43 @@ class FlakyNetworkTest : public ::testing::Test { std::unique_ptr server_; const int SERVER_PORT = 32750; int port_; - const grpc::string kRequestMessage_; }; +std::vector CreateTestScenarios() { + std::vector scenarios; + std::vector credentials_types; + std::vector messages; + + credentials_types.push_back(kInsecureCredentialsType); + auto sec_list = GetCredentialsProvider()->GetSecureCredentialsTypeList(); + for (auto sec = sec_list.begin(); sec != sec_list.end(); sec++) { + credentials_types.push_back(*sec); + } + + messages.push_back("🖖"); + for (size_t k = 1; k < GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH / 1024; k *= 32) { + grpc::string big_msg; + for (size_t i = 0; i < k * 1024; ++i) { + char c = 'a' + (i % 26); + big_msg += c; + } + messages.push_back(big_msg); + } + for (auto cred = credentials_types.begin(); cred != credentials_types.end(); + ++cred) { + for (auto msg = messages.begin(); msg != messages.end(); msg++) { + scenarios.emplace_back(*cred, *msg); + } + } + + return scenarios; +} + +INSTANTIATE_TEST_CASE_P(FlakyNetworkTest, FlakyNetworkTest, + ::testing::ValuesIn(CreateTestScenarios())); + // Network interface connected to server flaps -TEST_F(FlakyNetworkTest, NetworkTransition) { +TEST_P(FlakyNetworkTest, NetworkTransition) { const int kKeepAliveTimeMs = 1000; const int kKeepAliveTimeoutMs = 1000; ChannelArguments args; @@ -336,7 +389,7 @@ TEST_F(FlakyNetworkTest, NetworkTransition) { } // Traffic to server server is blackholed temporarily with keepalives enabled -TEST_F(FlakyNetworkTest, ServerUnreachableWithKeepalive) { +TEST_P(FlakyNetworkTest, ServerUnreachableWithKeepalive) { const int kKeepAliveTimeMs = 1000; const int kKeepAliveTimeoutMs = 1000; const int kReconnectBackoffMs = 1000; @@ -385,7 +438,7 @@ TEST_F(FlakyNetworkTest, ServerUnreachableWithKeepalive) { // // Traffic to server server is blackholed temporarily with keepalives disabled -TEST_F(FlakyNetworkTest, ServerUnreachableNoKeepalive) { +TEST_P(FlakyNetworkTest, ServerUnreachableNoKeepalive) { auto channel = BuildChannel("pick_first", ChannelArguments()); auto stub = BuildStub(channel); // Channel should be in READY state after we send an RPC @@ -411,7 +464,7 @@ TEST_F(FlakyNetworkTest, ServerUnreachableNoKeepalive) { } // Send RPCs over a flaky network connection -TEST_F(FlakyNetworkTest, FlakyNetwork) { +TEST_P(FlakyNetworkTest, FlakyNetwork) { const int kKeepAliveTimeMs = 1000; const int kKeepAliveTimeoutMs = 1000; const int kMessageCount = 100; @@ -438,7 +491,7 @@ TEST_F(FlakyNetworkTest, FlakyNetwork) { } // Server is shutdown gracefully and restarted. Client keepalives are enabled -TEST_F(FlakyNetworkTest, ServerRestartKeepaliveEnabled) { +TEST_P(FlakyNetworkTest, ServerRestartKeepaliveEnabled) { const int kKeepAliveTimeMs = 1000; const int kKeepAliveTimeoutMs = 1000; ChannelArguments args; @@ -468,7 +521,7 @@ TEST_F(FlakyNetworkTest, ServerRestartKeepaliveEnabled) { } // Server is shutdown gracefully and restarted. Client keepalives are enabled -TEST_F(FlakyNetworkTest, ServerRestartKeepaliveDisabled) { +TEST_P(FlakyNetworkTest, ServerRestartKeepaliveDisabled) { auto channel = BuildChannel("pick_first", ChannelArguments()); auto stub = BuildStub(channel); // Channel should be in READY state after we send an RPC diff --git a/test/cpp/end2end/generic_end2end_test.cc b/test/cpp/end2end/generic_end2end_test.cc index 8c4b3cf1fd3..c2807310aa4 100644 --- a/test/cpp/end2end/generic_end2end_test.cc +++ b/test/cpp/end2end/generic_end2end_test.cc @@ -90,8 +90,8 @@ class GenericEnd2endTest : public ::testing::Test { } void ResetStub() { - std::shared_ptr channel = - CreateChannel(server_address_.str(), InsecureChannelCredentials()); + std::shared_ptr channel = grpc::CreateChannel( + server_address_.str(), InsecureChannelCredentials()); generic_stub_.reset(new GenericStub(channel)); } diff --git a/test/cpp/end2end/grpclb_end2end_test.cc b/test/cpp/end2end/grpclb_end2end_test.cc index f8d887dd24d..50b1383e7e1 100644 --- a/test/cpp/end2end/grpclb_end2end_test.cc +++ b/test/cpp/end2end/grpclb_end2end_test.cc @@ -34,11 +34,11 @@ #include #include +#include "src/core/ext/filters/client_channel/backup_poller.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" #include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/ext/filters/client_channel/service_config.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/iomgr/sockaddr.h" #include "src/core/lib/security/credentials/fake/fake_credentials.h" @@ -375,7 +375,7 @@ class GrpclbEnd2endTest : public ::testing::Test { client_load_reporting_interval_seconds) { // Make the backup poller poll very frequently in order to pick up // updates from all the subchannels's FDs. - gpr_setenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS", "1"); + GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 1); } void SetUp() override { @@ -434,7 +434,7 @@ class GrpclbEnd2endTest : public ::testing::Test { channel_creds, call_creds, nullptr))); call_creds->Unref(); channel_creds->Unref(); - channel_ = CreateCustomChannel(uri.str(), creds, args); + channel_ = ::grpc::CreateCustomChannel(uri.str(), creds, args); stub_ = grpc::testing::EchoTestService::NewStub(channel_); } @@ -737,6 +737,39 @@ TEST_F(SingleBalancerTest, SelectGrpclbWithMigrationServiceConfig) { EXPECT_EQ("grpclb", channel_->GetLoadBalancingPolicyName()); } +TEST_F(SingleBalancerTest, + DoNotSpecialCaseUseGrpclbWithLoadBalancingConfigTest) { + const int kFallbackTimeoutMs = 200 * grpc_test_slowdown_factor(); + ResetStub(kFallbackTimeoutMs); + SetNextResolution({AddressData{backends_[0]->port_, false, ""}, + AddressData{balancers_[0]->port_, true, ""}}, + "{\n" + " \"loadBalancingConfig\":[\n" + " {\"pick_first\":{} }\n" + " ]\n" + "}"); + CheckRpcSendOk(); + // Check LB policy name for the channel. + EXPECT_EQ("pick_first", channel_->GetLoadBalancingPolicyName()); +} + +TEST_F( + SingleBalancerTest, + DoNotSpecialCaseUseGrpclbWithLoadBalancingConfigTestAndNoBackendAddress) { + const int kFallbackTimeoutMs = 200 * grpc_test_slowdown_factor(); + ResetStub(kFallbackTimeoutMs); + SetNextResolution({AddressData{balancers_[0]->port_, true, ""}}, + "{\n" + " \"loadBalancingConfig\":[\n" + " {\"pick_first\":{} }\n" + " ]\n" + "}"); + // This should fail since we do not have a non-balancer backend + CheckRpcSendFailure(); + // Check LB policy name for the channel. + EXPECT_EQ("pick_first", channel_->GetLoadBalancingPolicyName()); +} + TEST_F(SingleBalancerTest, SelectGrpclbWithMigrationServiceConfigAndNoAddresses) { const int kFallbackTimeoutMs = 200 * grpc_test_slowdown_factor(); @@ -1034,12 +1067,12 @@ TEST_F(SingleBalancerTest, Fallback) { SetNextResolutionAllBalancers(); const int kFallbackTimeoutMs = 200 * grpc_test_slowdown_factor(); const int kServerlistDelayMs = 500 * grpc_test_slowdown_factor(); - const size_t kNumBackendInResolution = backends_.size() / 2; + const size_t kNumBackendsInResolution = backends_.size() / 2; ResetStub(kFallbackTimeoutMs); std::vector addresses; addresses.emplace_back(AddressData{balancers_[0]->port_, true, ""}); - for (size_t i = 0; i < kNumBackendInResolution; ++i) { + for (size_t i = 0; i < kNumBackendsInResolution; ++i) { addresses.emplace_back(AddressData{backends_[i]->port_, false, ""}); } SetNextResolution(addresses); @@ -1048,45 +1081,45 @@ TEST_F(SingleBalancerTest, Fallback) { ScheduleResponseForBalancer( 0, BalancerServiceImpl::BuildResponseForBackends( - GetBackendPorts(kNumBackendInResolution /* start_index */), {}), + GetBackendPorts(kNumBackendsInResolution /* start_index */), {}), kServerlistDelayMs); // Wait until all the fallback backends are reachable. - for (size_t i = 0; i < kNumBackendInResolution; ++i) { + for (size_t i = 0; i < kNumBackendsInResolution; ++i) { WaitForBackend(i); } // The first request. gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH =========="); - CheckRpcSendOk(kNumBackendInResolution); + CheckRpcSendOk(kNumBackendsInResolution); gpr_log(GPR_INFO, "========= DONE WITH FIRST BATCH =========="); // Fallback is used: each backend returned by the resolver should have // gotten one request. - for (size_t i = 0; i < kNumBackendInResolution; ++i) { + for (size_t i = 0; i < kNumBackendsInResolution; ++i) { EXPECT_EQ(1U, backends_[i]->service_.request_count()); } - for (size_t i = kNumBackendInResolution; i < backends_.size(); ++i) { + for (size_t i = kNumBackendsInResolution; i < backends_.size(); ++i) { EXPECT_EQ(0U, backends_[i]->service_.request_count()); } // Wait until the serverlist reception has been processed and all backends // in the serverlist are reachable. - for (size_t i = kNumBackendInResolution; i < backends_.size(); ++i) { + for (size_t i = kNumBackendsInResolution; i < backends_.size(); ++i) { WaitForBackend(i); } // Send out the second request. gpr_log(GPR_INFO, "========= BEFORE SECOND BATCH =========="); - CheckRpcSendOk(backends_.size() - kNumBackendInResolution); + CheckRpcSendOk(backends_.size() - kNumBackendsInResolution); gpr_log(GPR_INFO, "========= DONE WITH SECOND BATCH =========="); // Serverlist is used: each backend returned by the balancer should // have gotten one request. - for (size_t i = 0; i < kNumBackendInResolution; ++i) { + for (size_t i = 0; i < kNumBackendsInResolution; ++i) { EXPECT_EQ(0U, backends_[i]->service_.request_count()); } - for (size_t i = kNumBackendInResolution; i < backends_.size(); ++i) { + for (size_t i = kNumBackendsInResolution; i < backends_.size(); ++i) { EXPECT_EQ(1U, backends_[i]->service_.request_count()); } @@ -1101,13 +1134,13 @@ TEST_F(SingleBalancerTest, FallbackUpdate) { SetNextResolutionAllBalancers(); const int kFallbackTimeoutMs = 200 * grpc_test_slowdown_factor(); const int kServerlistDelayMs = 500 * grpc_test_slowdown_factor(); - const size_t kNumBackendInResolution = backends_.size() / 3; - const size_t kNumBackendInResolutionUpdate = backends_.size() / 3; + const size_t kNumBackendsInResolution = backends_.size() / 3; + const size_t kNumBackendsInResolutionUpdate = backends_.size() / 3; ResetStub(kFallbackTimeoutMs); std::vector addresses; addresses.emplace_back(AddressData{balancers_[0]->port_, true, ""}); - for (size_t i = 0; i < kNumBackendInResolution; ++i) { + for (size_t i = 0; i < kNumBackendsInResolution; ++i) { addresses.emplace_back(AddressData{backends_[i]->port_, false, ""}); } SetNextResolution(addresses); @@ -1116,84 +1149,84 @@ TEST_F(SingleBalancerTest, FallbackUpdate) { ScheduleResponseForBalancer( 0, BalancerServiceImpl::BuildResponseForBackends( - GetBackendPorts(kNumBackendInResolution + - kNumBackendInResolutionUpdate /* start_index */), + GetBackendPorts(kNumBackendsInResolution + + kNumBackendsInResolutionUpdate /* start_index */), {}), kServerlistDelayMs); // Wait until all the fallback backends are reachable. - for (size_t i = 0; i < kNumBackendInResolution; ++i) { + for (size_t i = 0; i < kNumBackendsInResolution; ++i) { WaitForBackend(i); } // The first request. gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH =========="); - CheckRpcSendOk(kNumBackendInResolution); + CheckRpcSendOk(kNumBackendsInResolution); gpr_log(GPR_INFO, "========= DONE WITH FIRST BATCH =========="); // Fallback is used: each backend returned by the resolver should have // gotten one request. - for (size_t i = 0; i < kNumBackendInResolution; ++i) { + for (size_t i = 0; i < kNumBackendsInResolution; ++i) { EXPECT_EQ(1U, backends_[i]->service_.request_count()); } - for (size_t i = kNumBackendInResolution; i < backends_.size(); ++i) { + for (size_t i = kNumBackendsInResolution; i < backends_.size(); ++i) { EXPECT_EQ(0U, backends_[i]->service_.request_count()); } addresses.clear(); addresses.emplace_back(AddressData{balancers_[0]->port_, true, ""}); - for (size_t i = kNumBackendInResolution; - i < kNumBackendInResolution + kNumBackendInResolutionUpdate; ++i) { + for (size_t i = kNumBackendsInResolution; + i < kNumBackendsInResolution + kNumBackendsInResolutionUpdate; ++i) { addresses.emplace_back(AddressData{backends_[i]->port_, false, ""}); } SetNextResolution(addresses); // Wait until the resolution update has been processed and all the new // fallback backends are reachable. - for (size_t i = kNumBackendInResolution; - i < kNumBackendInResolution + kNumBackendInResolutionUpdate; ++i) { + for (size_t i = kNumBackendsInResolution; + i < kNumBackendsInResolution + kNumBackendsInResolutionUpdate; ++i) { WaitForBackend(i); } // Send out the second request. gpr_log(GPR_INFO, "========= BEFORE SECOND BATCH =========="); - CheckRpcSendOk(kNumBackendInResolutionUpdate); + CheckRpcSendOk(kNumBackendsInResolutionUpdate); gpr_log(GPR_INFO, "========= DONE WITH SECOND BATCH =========="); // The resolution update is used: each backend in the resolution update should // have gotten one request. - for (size_t i = 0; i < kNumBackendInResolution; ++i) { + for (size_t i = 0; i < kNumBackendsInResolution; ++i) { EXPECT_EQ(0U, backends_[i]->service_.request_count()); } - for (size_t i = kNumBackendInResolution; - i < kNumBackendInResolution + kNumBackendInResolutionUpdate; ++i) { + for (size_t i = kNumBackendsInResolution; + i < kNumBackendsInResolution + kNumBackendsInResolutionUpdate; ++i) { EXPECT_EQ(1U, backends_[i]->service_.request_count()); } - for (size_t i = kNumBackendInResolution + kNumBackendInResolutionUpdate; + for (size_t i = kNumBackendsInResolution + kNumBackendsInResolutionUpdate; i < backends_.size(); ++i) { EXPECT_EQ(0U, backends_[i]->service_.request_count()); } // Wait until the serverlist reception has been processed and all backends // in the serverlist are reachable. - for (size_t i = kNumBackendInResolution + kNumBackendInResolutionUpdate; + for (size_t i = kNumBackendsInResolution + kNumBackendsInResolutionUpdate; i < backends_.size(); ++i) { WaitForBackend(i); } // Send out the third request. gpr_log(GPR_INFO, "========= BEFORE THIRD BATCH =========="); - CheckRpcSendOk(backends_.size() - kNumBackendInResolution - - kNumBackendInResolutionUpdate); + CheckRpcSendOk(backends_.size() - kNumBackendsInResolution - + kNumBackendsInResolutionUpdate); gpr_log(GPR_INFO, "========= DONE WITH THIRD BATCH =========="); // Serverlist is used: each backend returned by the balancer should // have gotten one request. for (size_t i = 0; - i < kNumBackendInResolution + kNumBackendInResolutionUpdate; ++i) { + i < kNumBackendsInResolution + kNumBackendsInResolutionUpdate; ++i) { EXPECT_EQ(0U, backends_[i]->service_.request_count()); } - for (size_t i = kNumBackendInResolution + kNumBackendInResolutionUpdate; + for (size_t i = kNumBackendsInResolution + kNumBackendsInResolutionUpdate; i < backends_.size(); ++i) { EXPECT_EQ(1U, backends_[i]->service_.request_count()); } diff --git a/test/cpp/end2end/health_service_end2end_test.cc b/test/cpp/end2end/health_service_end2end_test.cc index b96ff53a3ea..13d5ea55c15 100644 --- a/test/cpp/end2end/health_service_end2end_test.cc +++ b/test/cpp/end2end/health_service_end2end_test.cc @@ -124,8 +124,8 @@ class HealthServiceEnd2endTest : public ::testing::Test { } void ResetStubs() { - std::shared_ptr channel = - CreateChannel(server_address_.str(), InsecureChannelCredentials()); + std::shared_ptr channel = grpc::CreateChannel( + server_address_.str(), InsecureChannelCredentials()); hc_stub_ = grpc::health::v1::Health::NewStub(channel); } diff --git a/test/cpp/end2end/hybrid_end2end_test.cc b/test/cpp/end2end/hybrid_end2end_test.cc index b0dd901cf11..75001f0ab27 100644 --- a/test/cpp/end2end/hybrid_end2end_test.cc +++ b/test/cpp/end2end/hybrid_end2end_test.cc @@ -296,8 +296,8 @@ class HybridEnd2endTest : public ::testing::TestWithParam { void ResetStub() { std::shared_ptr channel = inproc_ ? server_->InProcessChannel(ChannelArguments()) - : CreateChannel(server_address_.str(), - InsecureChannelCredentials()); + : grpc::CreateChannel(server_address_.str(), + InsecureChannelCredentials()); stub_ = grpc::testing::EchoTestService::NewStub(channel); } @@ -321,8 +321,8 @@ class HybridEnd2endTest : public ::testing::TestWithParam { } void SendEchoToDupService() { - std::shared_ptr channel = - CreateChannel(server_address_.str(), InsecureChannelCredentials()); + std::shared_ptr channel = grpc::CreateChannel( + server_address_.str(), InsecureChannelCredentials()); auto stub = grpc::testing::duplicate::EchoTestService::NewStub(channel); EchoRequest send_request; EchoResponse recv_response; @@ -373,8 +373,8 @@ class HybridEnd2endTest : public ::testing::TestWithParam { } void SendSimpleServerStreamingToDupService() { - std::shared_ptr channel = - CreateChannel(server_address_.str(), InsecureChannelCredentials()); + std::shared_ptr channel = grpc::CreateChannel( + server_address_.str(), InsecureChannelCredentials()); auto stub = grpc::testing::duplicate::EchoTestService::NewStub(channel); EchoRequest request; EchoResponse response; diff --git a/test/cpp/end2end/message_allocator_end2end_test.cc b/test/cpp/end2end/message_allocator_end2end_test.cc index 55f792aa3bf..1c52259088a 100644 --- a/test/cpp/end2end/message_allocator_end2end_test.cc +++ b/test/cpp/end2end/message_allocator_end2end_test.cc @@ -25,6 +25,7 @@ #include +#include #include #include @@ -62,11 +63,9 @@ class CallbackTestServiceImpl public: explicit CallbackTestServiceImpl() {} - void SetFreeRequest() { free_request_ = true; } - void SetAllocatorMutator( - std::function + std::function mutator) { allocator_mutator_ = mutator; } @@ -75,18 +74,15 @@ class CallbackTestServiceImpl EchoResponse* response, experimental::ServerCallbackRpcController* controller) override { response->set_message(request->message()); - if (free_request_) { - controller->FreeRequest(); - } else if (allocator_mutator_) { - allocator_mutator_(controller->GetAllocatorState(), request, response); + if (allocator_mutator_) { + allocator_mutator_(controller->GetRpcAllocatorState(), request, response); } controller->Finish(Status::OK); } private: - bool free_request_ = false; - std::function + std::function allocator_mutator_; }; @@ -153,8 +149,8 @@ class MessageAllocatorEnd2endTestBase GetParam().credentials_type, &args); switch (GetParam().protocol) { case Protocol::TCP: - channel_ = - CreateCustomChannel(server_address_.str(), channel_creds, args); + channel_ = ::grpc::CreateCustomChannel(server_address_.str(), + channel_creds, args); break; case Protocol::INPROC: channel_ = server_->InProcessChannel(args); @@ -230,26 +226,44 @@ class SimpleAllocatorTest : public MessageAllocatorEnd2endTestBase { class SimpleAllocator : public experimental::MessageAllocator { public: - void AllocateMessages( - experimental::RpcAllocatorInfo* info) { + class MessageHolderImpl + : public experimental::MessageHolder { + public: + MessageHolderImpl(int* request_deallocation_count, + int* messages_deallocation_count) + : request_deallocation_count_(request_deallocation_count), + messages_deallocation_count_(messages_deallocation_count) { + set_request(new EchoRequest); + set_response(new EchoResponse); + } + void Release() override { + (*messages_deallocation_count_)++; + delete request(); + delete response(); + delete this; + } + void FreeRequest() override { + (*request_deallocation_count_)++; + delete request(); + set_request(nullptr); + } + + EchoRequest* ReleaseRequest() { + auto* ret = request(); + set_request(nullptr); + return ret; + } + + private: + int* request_deallocation_count_; + int* messages_deallocation_count_; + }; + experimental::MessageHolder* AllocateMessages() + override { allocation_count++; - info->request = new EchoRequest; - info->response = new EchoResponse; - info->allocator_state = info; - } - void DeallocateRequest( - experimental::RpcAllocatorInfo* info) { - request_deallocation_count++; - delete info->request; - info->request = nullptr; - } - void DeallocateMessages( - experimental::RpcAllocatorInfo* info) { - messages_deallocation_count++; - delete info->request; - delete info->response; + return new MessageHolderImpl(&request_deallocation_count, + &messages_deallocation_count); } - int allocation_count = 0; int request_deallocation_count = 0; int messages_deallocation_count = 0; @@ -272,7 +286,16 @@ TEST_P(SimpleAllocatorTest, RpcWithEarlyFreeRequest) { MAYBE_SKIP_TEST; const int kRpcCount = 10; std::unique_ptr allocator(new SimpleAllocator); - callback_service_.SetFreeRequest(); + auto mutator = [](experimental::RpcAllocatorState* allocator_state, + const EchoRequest* req, EchoResponse* resp) { + auto* info = + static_cast(allocator_state); + EXPECT_EQ(req, info->request()); + EXPECT_EQ(resp, info->response()); + allocator_state->FreeRequest(); + EXPECT_EQ(nullptr, info->request()); + }; + callback_service_.SetAllocatorMutator(mutator); CreateServer(allocator.get()); ResetStub(); SendRpcs(kRpcCount); @@ -286,17 +309,15 @@ TEST_P(SimpleAllocatorTest, RpcWithReleaseRequest) { const int kRpcCount = 10; std::unique_ptr allocator(new SimpleAllocator); std::vector released_requests; - auto mutator = [&released_requests](void* allocator_state, - const EchoRequest* req, - EchoResponse* resp) { + auto mutator = [&released_requests]( + experimental::RpcAllocatorState* allocator_state, + const EchoRequest* req, EchoResponse* resp) { auto* info = - static_cast*>( - allocator_state); - EXPECT_EQ(req, info->request); - EXPECT_EQ(resp, info->response); - EXPECT_EQ(allocator_state, info->allocator_state); - released_requests.push_back(info->request); - info->request = nullptr; + static_cast(allocator_state); + EXPECT_EQ(req, info->request()); + EXPECT_EQ(resp, info->response()); + released_requests.push_back(info->ReleaseRequest()); + EXPECT_EQ(nullptr, info->request()); }; callback_service_.SetAllocatorMutator(mutator); CreateServer(allocator.get()); @@ -316,30 +337,27 @@ class ArenaAllocatorTest : public MessageAllocatorEnd2endTestBase { class ArenaAllocator : public experimental::MessageAllocator { public: - void AllocateMessages( - experimental::RpcAllocatorInfo* info) { + class MessageHolderImpl + : public experimental::MessageHolder { + public: + MessageHolderImpl() { + set_request( + google::protobuf::Arena::CreateMessage(&arena_)); + set_response( + google::protobuf::Arena::CreateMessage(&arena_)); + } + void Release() override { delete this; } + void FreeRequest() override { GPR_ASSERT(0); } + + private: + google::protobuf::Arena arena_; + }; + experimental::MessageHolder* AllocateMessages() + override { allocation_count++; - auto* arena = new google::protobuf::Arena; - info->allocator_state = arena; - info->request = - google::protobuf::Arena::CreateMessage(arena); - info->response = - google::protobuf::Arena::CreateMessage(arena); - } - void DeallocateRequest( - experimental::RpcAllocatorInfo* info) { - GPR_ASSERT(0); + return new MessageHolderImpl; } - void DeallocateMessages( - experimental::RpcAllocatorInfo* info) { - deallocation_count++; - auto* arena = - static_cast(info->allocator_state); - delete arena; - } - int allocation_count = 0; - int deallocation_count = 0; }; }; @@ -351,7 +369,6 @@ TEST_P(ArenaAllocatorTest, SimpleRpc) { ResetStub(); SendRpcs(kRpcCount); EXPECT_EQ(kRpcCount, allocator->allocation_count); - EXPECT_EQ(kRpcCount, allocator->deallocation_count); } std::vector CreateTestScenarios(bool test_insecure) { diff --git a/test/cpp/end2end/mock_test.cc b/test/cpp/end2end/mock_test.cc index 917ca28020a..0196c9de7e0 100644 --- a/test/cpp/end2end/mock_test.cc +++ b/test/cpp/end2end/mock_test.cc @@ -244,8 +244,8 @@ class MockTest : public ::testing::Test { void TearDown() override { server_->Shutdown(); } void ResetStub() { - std::shared_ptr channel = - CreateChannel(server_address_.str(), InsecureChannelCredentials()); + std::shared_ptr channel = grpc::CreateChannel( + server_address_.str(), InsecureChannelCredentials()); stub_ = grpc::testing::EchoTestService::NewStub(channel); } diff --git a/test/cpp/end2end/nonblocking_test.cc b/test/cpp/end2end/nonblocking_test.cc index 36dea1fcb31..eb651df21df 100644 --- a/test/cpp/end2end/nonblocking_test.cc +++ b/test/cpp/end2end/nonblocking_test.cc @@ -106,7 +106,7 @@ class NonblockingTest : public ::testing::Test { } void ResetStub() { - std::shared_ptr channel = CreateChannel( + std::shared_ptr channel = grpc::CreateChannel( server_address_.str(), grpc::InsecureChannelCredentials()); stub_ = grpc::testing::EchoTestService::NewStub(channel); } diff --git a/test/cpp/end2end/port_sharing_end2end_test.cc b/test/cpp/end2end/port_sharing_end2end_test.cc new file mode 100644 index 00000000000..a2b9417d172 --- /dev/null +++ b/test/cpp/end2end/port_sharing_end2end_test.cc @@ -0,0 +1,364 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "src/core/lib/iomgr/endpoint.h" +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/iomgr/pollset.h" +#include "src/core/lib/iomgr/port.h" +#include "src/core/lib/iomgr/tcp_server.h" +#include "src/core/lib/security/credentials/credentials.h" +#include "src/proto/grpc/testing/echo.grpc.pb.h" +#include "test/core/util/port.h" +#include "test/core/util/test_config.h" +#include "test/core/util/test_tcp_server.h" +#include "test/cpp/end2end/test_service_impl.h" +#include "test/cpp/util/test_credentials_provider.h" + +#ifdef GRPC_POSIX_SOCKET_TCP_SERVER + +#include "src/core/lib/iomgr/tcp_posix.h" + +namespace grpc { +namespace testing { +namespace { + +class TestScenario { + public: + TestScenario(bool server_port, bool pending_data, + const grpc::string& creds_type) + : server_has_port(server_port), + queue_pending_data(pending_data), + credentials_type(creds_type) {} + void Log() const; + // server has its own port or not + bool server_has_port; + // whether tcp server should read some data before handoff + bool queue_pending_data; + const grpc::string credentials_type; +}; + +static std::ostream& operator<<(std::ostream& out, + const TestScenario& scenario) { + return out << "TestScenario{server_has_port=" + << (scenario.server_has_port ? "true" : "false") + << ", queue_pending_data=" + << (scenario.queue_pending_data ? "true" : "false") + << ", credentials='" << scenario.credentials_type << "'}"; +} + +void TestScenario::Log() const { + std::ostringstream out; + out << *this; + gpr_log(GPR_ERROR, "%s", out.str().c_str()); +} + +// Set up a test tcp server which is in charge of accepting connections and +// handing off the connections as fds. +class TestTcpServer { + public: + TestTcpServer() + : shutdown_(false), + queue_data_(false), + port_(grpc_pick_unused_port_or_die()) { + std::ostringstream server_address; + server_address << "localhost:" << port_; + address_ = server_address.str(); + test_tcp_server_init(&tcp_server_, &TestTcpServer::OnConnect, this); + GRPC_CLOSURE_INIT(&on_fd_released_, &TestTcpServer::OnFdReleased, this, + grpc_schedule_on_exec_ctx); + } + + ~TestTcpServer() { + running_thread_.join(); + test_tcp_server_destroy(&tcp_server_); + grpc_recycle_unused_port(port_); + } + + // Read some data before handing off the connection. + void SetQueueData() { queue_data_ = true; } + + void Start() { + test_tcp_server_start(&tcp_server_, port_); + gpr_log(GPR_INFO, "Test TCP server started at %s", address_.c_str()); + } + + const grpc::string& address() { return address_; } + + void SetAcceptor( + std::unique_ptr acceptor) { + connection_acceptor_ = std::move(acceptor); + } + + void Run() { + running_thread_ = std::thread([this]() { + while (true) { + { + std::lock_guard lock(mu_); + if (shutdown_) { + return; + } + } + test_tcp_server_poll(&tcp_server_, 1); + } + }); + } + + void Shutdown() { + std::lock_guard lock(mu_); + shutdown_ = true; + } + + static void OnConnect(void* arg, grpc_endpoint* tcp, + grpc_pollset* accepting_pollset, + grpc_tcp_server_acceptor* acceptor) { + auto* self = static_cast(arg); + self->OnConnect(tcp, accepting_pollset, acceptor); + } + + static void OnFdReleased(void* arg, grpc_error* err) { + auto* self = static_cast(arg); + self->OnFdReleased(err); + } + + private: + void OnConnect(grpc_endpoint* tcp, grpc_pollset* accepting_pollset, + grpc_tcp_server_acceptor* acceptor) { + char* peer = grpc_endpoint_get_peer(tcp); + gpr_log(GPR_INFO, "Got incoming connection! from %s", peer); + gpr_free(peer); + EXPECT_FALSE(acceptor->external_connection); + gpr_free(acceptor); + grpc_tcp_destroy_and_release_fd(tcp, &fd_, &on_fd_released_); + } + + void OnFdReleased(grpc_error* err) { + EXPECT_EQ(GRPC_ERROR_NONE, err); + experimental::ExternalConnectionAcceptor::NewConnectionParameters p; + p.fd = fd_; + if (queue_data_) { + char buf[1024]; + ssize_t read_bytes = 0; + while (read_bytes <= 0) { + read_bytes = read(fd_, buf, 1024); + } + Slice data(buf, read_bytes); + p.read_buffer = ByteBuffer(&data, 1); + } + gpr_log(GPR_INFO, "Handing off fd %d with data size %d", fd_, + static_cast(p.read_buffer.Length())); + connection_acceptor_->HandleNewConnection(&p); + } + + std::mutex mu_; + bool shutdown_; + + int fd_; + bool queue_data_; + + grpc_closure on_fd_released_; + std::thread running_thread_; + int port_; + grpc::string address_; + std::unique_ptr + connection_acceptor_; + test_tcp_server tcp_server_; +}; + +class PortSharingEnd2endTest : public ::testing::TestWithParam { + protected: + PortSharingEnd2endTest() : is_server_started_(false), first_picked_port_(0) { + GetParam().Log(); + } + + void SetUp() override { + if (GetParam().queue_pending_data) { + tcp_server1_.SetQueueData(); + tcp_server2_.SetQueueData(); + } + tcp_server1_.Start(); + tcp_server2_.Start(); + ServerBuilder builder; + if (GetParam().server_has_port) { + int port = grpc_pick_unused_port_or_die(); + first_picked_port_ = port; + server_address_ << "localhost:" << port; + auto creds = GetCredentialsProvider()->GetServerCredentials( + GetParam().credentials_type); + builder.AddListeningPort(server_address_.str(), creds); + gpr_log(GPR_INFO, "gRPC server listening on %s", + server_address_.str().c_str()); + } + auto server_creds = GetCredentialsProvider()->GetServerCredentials( + GetParam().credentials_type); + auto acceptor1 = builder.experimental().AddExternalConnectionAcceptor( + ServerBuilder::experimental_type::ExternalConnectionType::FROM_FD, + server_creds); + tcp_server1_.SetAcceptor(std::move(acceptor1)); + auto acceptor2 = builder.experimental().AddExternalConnectionAcceptor( + ServerBuilder::experimental_type::ExternalConnectionType::FROM_FD, + server_creds); + tcp_server2_.SetAcceptor(std::move(acceptor2)); + builder.RegisterService(&service_); + server_ = builder.BuildAndStart(); + is_server_started_ = true; + + tcp_server1_.Run(); + tcp_server2_.Run(); + } + + void TearDown() override { + tcp_server1_.Shutdown(); + tcp_server2_.Shutdown(); + if (is_server_started_) { + server_->Shutdown(); + } + if (first_picked_port_ > 0) { + grpc_recycle_unused_port(first_picked_port_); + } + } + + void ResetStubs() { + EXPECT_TRUE(is_server_started_); + ChannelArguments args; + args.SetInt(GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL, 1); + auto channel_creds = GetCredentialsProvider()->GetChannelCredentials( + GetParam().credentials_type, &args); + channel_handoff1_ = + CreateCustomChannel(tcp_server1_.address(), channel_creds, args); + stub_handoff1_ = EchoTestService::NewStub(channel_handoff1_); + channel_handoff2_ = + CreateCustomChannel(tcp_server2_.address(), channel_creds, args); + stub_handoff2_ = EchoTestService::NewStub(channel_handoff2_); + if (GetParam().server_has_port) { + ChannelArguments direct_args; + direct_args.SetInt(GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL, 1); + auto direct_creds = GetCredentialsProvider()->GetChannelCredentials( + GetParam().credentials_type, &direct_args); + channel_direct_ = + CreateCustomChannel(server_address_.str(), direct_creds, direct_args); + stub_direct_ = EchoTestService::NewStub(channel_direct_); + } + } + + bool is_server_started_; + // channel/stub to the test tcp server, the connection will be handed to the + // grpc server. + std::shared_ptr channel_handoff1_; + std::unique_ptr stub_handoff1_; + std::shared_ptr channel_handoff2_; + std::unique_ptr stub_handoff2_; + // channel/stub to talk to the grpc server directly, if applicable. + std::shared_ptr channel_direct_; + std::unique_ptr stub_direct_; + std::unique_ptr server_; + std::ostringstream server_address_; + TestServiceImpl service_; + TestTcpServer tcp_server1_; + TestTcpServer tcp_server2_; + int first_picked_port_; +}; + +static void SendRpc(EchoTestService::Stub* stub, int num_rpcs) { + EchoRequest request; + EchoResponse response; + request.set_message("Hello hello hello hello"); + + for (int i = 0; i < num_rpcs; ++i) { + ClientContext context; + Status s = stub->Echo(&context, request, &response); + EXPECT_EQ(response.message(), request.message()); + EXPECT_TRUE(s.ok()); + } +} + +std::vector CreateTestScenarios() { + std::vector scenarios; + std::vector credentials_types; + credentials_types = GetCredentialsProvider()->GetSecureCredentialsTypeList(); + // Only allow insecure credentials type when it is registered with the + // provider. User may create providers that do not have insecure. + if (GetCredentialsProvider()->GetChannelCredentials(kInsecureCredentialsType, + nullptr) != nullptr) { + credentials_types.push_back(kInsecureCredentialsType); + } + + GPR_ASSERT(!credentials_types.empty()); + for (const auto& cred : credentials_types) { + for (auto server_has_port : {true, false}) { + for (auto queue_pending_data : {true, false}) { + scenarios.emplace_back(server_has_port, queue_pending_data, cred); + } + } + } + return scenarios; +} + +TEST_P(PortSharingEnd2endTest, HandoffAndDirectCalls) { + ResetStubs(); + SendRpc(stub_handoff1_.get(), 5); + if (GetParam().server_has_port) { + SendRpc(stub_direct_.get(), 5); + } +} + +TEST_P(PortSharingEnd2endTest, MultipleHandoff) { + for (int i = 0; i < 3; i++) { + ResetStubs(); + SendRpc(stub_handoff2_.get(), 1); + } +} + +TEST_P(PortSharingEnd2endTest, TwoHandoffPorts) { + for (int i = 0; i < 3; i++) { + ResetStubs(); + SendRpc(stub_handoff1_.get(), 5); + SendRpc(stub_handoff2_.get(), 5); + } +} + +INSTANTIATE_TEST_CASE_P(PortSharingEnd2end, PortSharingEnd2endTest, + ::testing::ValuesIn(CreateTestScenarios())); + +} // namespace +} // namespace testing +} // namespace grpc + +#endif // GRPC_POSIX_SOCKET_TCP_SERVER + +int main(int argc, char** argv) { + grpc::testing::TestEnvironment env(argc, argv); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/cpp/end2end/proto_server_reflection_test.cc b/test/cpp/end2end/proto_server_reflection_test.cc index ff097aa9a77..d817438f41b 100644 --- a/test/cpp/end2end/proto_server_reflection_test.cc +++ b/test/cpp/end2end/proto_server_reflection_test.cc @@ -55,7 +55,7 @@ class ProtoServerReflectionTest : public ::testing::Test { void ResetStub() { string target = "dns:localhost:" + to_string(port_); std::shared_ptr channel = - CreateChannel(target, InsecureChannelCredentials()); + grpc::CreateChannel(target, InsecureChannelCredentials()); stub_ = grpc::testing::EchoTestService::NewStub(channel); desc_db_.reset(new ProtoReflectionDescriptorDatabase(channel)); desc_pool_.reset(new protobuf::DescriptorPool(desc_db_.get())); diff --git a/test/cpp/end2end/raw_end2end_test.cc b/test/cpp/end2end/raw_end2end_test.cc index c8556bae954..184dc1e5f56 100644 --- a/test/cpp/end2end/raw_end2end_test.cc +++ b/test/cpp/end2end/raw_end2end_test.cc @@ -130,7 +130,7 @@ class RawEnd2EndTest : public ::testing::Test { void ResetStub() { ChannelArguments args; - std::shared_ptr channel = CreateChannel( + std::shared_ptr channel = grpc::CreateChannel( server_address_.str(), grpc::InsecureChannelCredentials()); stub_ = grpc::testing::EchoTestService::NewStub(channel); } diff --git a/test/cpp/end2end/server_builder_plugin_test.cc b/test/cpp/end2end/server_builder_plugin_test.cc index d744a93912e..43b00b95f49 100644 --- a/test/cpp/end2end/server_builder_plugin_test.cc +++ b/test/cpp/end2end/server_builder_plugin_test.cc @@ -185,7 +185,7 @@ class ServerBuilderPluginTest : public ::testing::TestWithParam { void ResetStub() { string target = "dns:localhost:" + to_string(port_); - channel_ = CreateChannel(target, InsecureChannelCredentials()); + channel_ = grpc::CreateChannel(target, InsecureChannelCredentials()); stub_ = grpc::testing::EchoTestService::NewStub(channel_); } diff --git a/test/cpp/end2end/server_crash_test_client.cc b/test/cpp/end2end/server_crash_test_client.cc index c05fcfdb810..b261560470d 100644 --- a/test/cpp/end2end/server_crash_test_client.cc +++ b/test/cpp/end2end/server_crash_test_client.cc @@ -28,6 +28,7 @@ #include #include "src/proto/grpc/testing/echo.grpc.pb.h" +#include "test/cpp/util/test_config.h" DEFINE_string(address, "", "Address to connect to"); DEFINE_string(mode, "", "Test mode to use"); @@ -35,15 +36,8 @@ DEFINE_string(mode, "", "Test mode to use"); using grpc::testing::EchoRequest; using grpc::testing::EchoResponse; -// In some distros, gflags is in the namespace google, and in some others, -// in gflags. This hack is enabling us to find both. -namespace google {} -namespace gflags {} -using namespace google; -using namespace gflags; - int main(int argc, char** argv) { - ParseCommandLineFlags(&argc, &argv, true); + grpc::testing::InitTest(&argc, &argv, true); auto stub = grpc::testing::EchoTestService::NewStub( grpc::CreateChannel(FLAGS_address, grpc::InsecureChannelCredentials())); diff --git a/test/cpp/end2end/server_early_return_test.cc b/test/cpp/end2end/server_early_return_test.cc index c47e25052e2..6f35c3e7d93 100644 --- a/test/cpp/end2end/server_early_return_test.cc +++ b/test/cpp/end2end/server_early_return_test.cc @@ -122,8 +122,8 @@ class ServerEarlyReturnTest : public ::testing::Test { builder.RegisterService(&service_); server_ = builder.BuildAndStart(); - channel_ = - CreateChannel(server_address_.str(), InsecureChannelCredentials()); + channel_ = grpc::CreateChannel(server_address_.str(), + InsecureChannelCredentials()); stub_ = grpc::testing::EchoTestService::NewStub(channel_); } diff --git a/test/cpp/end2end/server_interceptors_end2end_test.cc b/test/cpp/end2end/server_interceptors_end2end_test.cc index 028191c93c3..68103f7ed34 100644 --- a/test/cpp/end2end/server_interceptors_end2end_test.cc +++ b/test/cpp/end2end/server_interceptors_end2end_test.cc @@ -265,7 +265,8 @@ class ServerInterceptorsEnd2endSyncUnaryTest : public ::testing::Test { TEST_F(ServerInterceptorsEnd2endSyncUnaryTest, UnaryTest) { ChannelArguments args; DummyInterceptor::Reset(); - auto channel = CreateChannel(server_address_, InsecureChannelCredentials()); + auto channel = + grpc::CreateChannel(server_address_, InsecureChannelCredentials()); MakeCall(channel); // Make sure all 20 dummy interceptors were run EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20); @@ -308,7 +309,8 @@ class ServerInterceptorsEnd2endSyncStreamingTest : public ::testing::Test { TEST_F(ServerInterceptorsEnd2endSyncStreamingTest, ClientStreamingTest) { ChannelArguments args; DummyInterceptor::Reset(); - auto channel = CreateChannel(server_address_, InsecureChannelCredentials()); + auto channel = + grpc::CreateChannel(server_address_, InsecureChannelCredentials()); MakeClientStreamingCall(channel); // Make sure all 20 dummy interceptors were run EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20); @@ -317,7 +319,8 @@ TEST_F(ServerInterceptorsEnd2endSyncStreamingTest, ClientStreamingTest) { TEST_F(ServerInterceptorsEnd2endSyncStreamingTest, ServerStreamingTest) { ChannelArguments args; DummyInterceptor::Reset(); - auto channel = CreateChannel(server_address_, InsecureChannelCredentials()); + auto channel = + grpc::CreateChannel(server_address_, InsecureChannelCredentials()); MakeServerStreamingCall(channel); // Make sure all 20 dummy interceptors were run EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20); @@ -326,7 +329,8 @@ TEST_F(ServerInterceptorsEnd2endSyncStreamingTest, ServerStreamingTest) { TEST_F(ServerInterceptorsEnd2endSyncStreamingTest, BidiStreamingTest) { ChannelArguments args; DummyInterceptor::Reset(); - auto channel = CreateChannel(server_address_, InsecureChannelCredentials()); + auto channel = + grpc::CreateChannel(server_address_, InsecureChannelCredentials()); MakeBidiStreamingCall(channel); // Make sure all 20 dummy interceptors were run EXPECT_EQ(DummyInterceptor::GetNumTimesRun(), 20); @@ -356,7 +360,8 @@ TEST_F(ServerInterceptorsAsyncEnd2endTest, UnaryTest) { auto server = builder.BuildAndStart(); ChannelArguments args; - auto channel = CreateChannel(server_address, InsecureChannelCredentials()); + auto channel = + grpc::CreateChannel(server_address, InsecureChannelCredentials()); auto stub = grpc::testing::EchoTestService::NewStub(channel); EchoRequest send_request; @@ -428,7 +433,8 @@ TEST_F(ServerInterceptorsAsyncEnd2endTest, BidiStreamingTest) { auto server = builder.BuildAndStart(); ChannelArguments args; - auto channel = CreateChannel(server_address, InsecureChannelCredentials()); + auto channel = + grpc::CreateChannel(server_address, InsecureChannelCredentials()); auto stub = grpc::testing::EchoTestService::NewStub(channel); EchoRequest send_request; @@ -509,7 +515,8 @@ TEST_F(ServerInterceptorsAsyncEnd2endTest, GenericRPCTest) { auto server = builder.BuildAndStart(); ChannelArguments args; - auto channel = CreateChannel(server_address, InsecureChannelCredentials()); + auto channel = + grpc::CreateChannel(server_address, InsecureChannelCredentials()); GenericStub generic_stub(channel); const grpc::string kMethodName("/grpc.cpp.test.util.EchoTestService/Echo"); @@ -612,7 +619,7 @@ TEST_F(ServerInterceptorsAsyncEnd2endTest, UnimplementedRpcTest) { ChannelArguments args; std::shared_ptr channel = - CreateChannel(server_address, InsecureChannelCredentials()); + grpc::CreateChannel(server_address, InsecureChannelCredentials()); std::unique_ptr stub; stub = grpc::testing::UnimplementedEchoService::NewStub(channel); EchoRequest send_request; @@ -665,7 +672,7 @@ TEST_F(ServerInterceptorsSyncUnimplementedEnd2endTest, UnimplementedRpcTest) { ChannelArguments args; std::shared_ptr channel = - CreateChannel(server_address, InsecureChannelCredentials()); + grpc::CreateChannel(server_address, InsecureChannelCredentials()); std::unique_ptr stub; stub = grpc::testing::UnimplementedEchoService::NewStub(channel); EchoRequest send_request; diff --git a/test/cpp/end2end/server_load_reporting_end2end_test.cc b/test/cpp/end2end/server_load_reporting_end2end_test.cc index 7bc9af2a6eb..8eba9127ec6 100644 --- a/test/cpp/end2end/server_load_reporting_end2end_test.cc +++ b/test/cpp/end2end/server_load_reporting_end2end_test.cc @@ -94,7 +94,7 @@ class ServerLoadReportingEnd2endTest : public ::testing::Test { const grpc::string& lb_tag, const grpc::string& message, size_t num_requests) { auto stub = EchoTestService::NewStub( - CreateChannel(server_address_, InsecureChannelCredentials())); + grpc::CreateChannel(server_address_, InsecureChannelCredentials())); grpc::string lb_token = lb_id + lb_tag; for (int i = 0; i < num_requests; ++i) { ClientContext ctx; diff --git a/test/cpp/end2end/service_config_end2end_test.cc b/test/cpp/end2end/service_config_end2end_test.cc new file mode 100644 index 00000000000..b3299232763 --- /dev/null +++ b/test/cpp/end2end/service_config_end2end_test.cc @@ -0,0 +1,614 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "src/core/ext/filters/client_channel/backup_poller.h" +#include "src/core/ext/filters/client_channel/global_subchannel_pool.h" +#include "src/core/ext/filters/client_channel/parse_address.h" +#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" +#include "src/core/ext/filters/client_channel/server_address.h" +#include "src/core/lib/backoff/backoff.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/gprpp/debug_location.h" +#include "src/core/lib/gprpp/ref_counted_ptr.h" +#include "src/core/lib/iomgr/tcp_client.h" +#include "src/core/lib/security/credentials/fake/fake_credentials.h" +#include "src/cpp/client/secure_credentials.h" +#include "src/cpp/server/secure_server_credentials.h" + +#include "src/proto/grpc/testing/echo.grpc.pb.h" +#include "test/core/util/port.h" +#include "test/core/util/test_config.h" +#include "test/cpp/end2end/test_service_impl.h" + +#include +#include + +using grpc::testing::EchoRequest; +using grpc::testing::EchoResponse; +using std::chrono::system_clock; + +namespace grpc { +namespace testing { +namespace { + +// Subclass of TestServiceImpl that increments a request counter for +// every call to the Echo RPC. +class MyTestServiceImpl : public TestServiceImpl { + public: + MyTestServiceImpl() : request_count_(0) {} + + Status Echo(ServerContext* context, const EchoRequest* request, + EchoResponse* response) override { + { + grpc::internal::MutexLock lock(&mu_); + ++request_count_; + } + AddClient(context->peer()); + return TestServiceImpl::Echo(context, request, response); + } + + int request_count() { + grpc::internal::MutexLock lock(&mu_); + return request_count_; + } + + void ResetCounters() { + grpc::internal::MutexLock lock(&mu_); + request_count_ = 0; + } + + std::set clients() { + grpc::internal::MutexLock lock(&clients_mu_); + return clients_; + } + + private: + void AddClient(const grpc::string& client) { + grpc::internal::MutexLock lock(&clients_mu_); + clients_.insert(client); + } + + grpc::internal::Mutex mu_; + int request_count_; + grpc::internal::Mutex clients_mu_; + std::set clients_; +}; + +class ServiceConfigEnd2endTest : public ::testing::Test { + protected: + ServiceConfigEnd2endTest() + : server_host_("localhost"), + kRequestMessage_("Live long and prosper."), + creds_(new SecureChannelCredentials( + grpc_fake_transport_security_credentials_create())) { + // Make the backup poller poll very frequently in order to pick up + // updates from all the subchannels's FDs. + GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 1); + } + + void SetUp() override { + grpc_init(); + response_generator_ = + grpc_core::MakeRefCounted(); + } + + void TearDown() override { + for (size_t i = 0; i < servers_.size(); ++i) { + servers_[i]->Shutdown(); + } + // Explicitly destroy all the members so that we can make sure grpc_shutdown + // has finished by the end of this function, and thus all the registered + // LB policy factories are removed. + stub_.reset(); + servers_.clear(); + creds_.reset(); + grpc_shutdown_blocking(); + } + + void CreateServers(size_t num_servers, + std::vector ports = std::vector()) { + servers_.clear(); + for (size_t i = 0; i < num_servers; ++i) { + int port = 0; + if (ports.size() == num_servers) port = ports[i]; + servers_.emplace_back(new ServerData(port)); + } + } + + void StartServer(size_t index) { servers_[index]->Start(server_host_); } + + void StartServers(size_t num_servers, + std::vector ports = std::vector()) { + CreateServers(num_servers, std::move(ports)); + for (size_t i = 0; i < num_servers; ++i) { + StartServer(i); + } + } + + grpc_core::Resolver::Result BuildFakeResults(const std::vector& ports) { + grpc_core::Resolver::Result result; + for (const int& port : ports) { + char* lb_uri_str; + gpr_asprintf(&lb_uri_str, "ipv4:127.0.0.1:%d", port); + grpc_uri* lb_uri = grpc_uri_parse(lb_uri_str, true); + GPR_ASSERT(lb_uri != nullptr); + grpc_resolved_address address; + GPR_ASSERT(grpc_parse_uri(lb_uri, &address)); + result.addresses.emplace_back(address.addr, address.len, + nullptr /* args */); + grpc_uri_destroy(lb_uri); + gpr_free(lb_uri_str); + } + return result; + } + + void SetNextResolutionNoServiceConfig(const std::vector& ports) { + grpc_core::ExecCtx exec_ctx; + grpc_core::Resolver::Result result = BuildFakeResults(ports); + response_generator_->SetResponse(result); + } + + void SetNextResolutionValidServiceConfig(const std::vector& ports) { + grpc_core::ExecCtx exec_ctx; + grpc_core::Resolver::Result result = BuildFakeResults(ports); + result.service_config = + grpc_core::ServiceConfig::Create("{}", &result.service_config_error); + response_generator_->SetResponse(result); + } + + void SetNextResolutionInvalidServiceConfig(const std::vector& ports) { + grpc_core::ExecCtx exec_ctx; + grpc_core::Resolver::Result result = BuildFakeResults(ports); + result.service_config = + grpc_core::ServiceConfig::Create("{", &result.service_config_error); + response_generator_->SetResponse(result); + } + + void SetNextResolutionWithServiceConfig(const std::vector& ports, + const char* svc_cfg) { + grpc_core::ExecCtx exec_ctx; + grpc_core::Resolver::Result result = BuildFakeResults(ports); + result.service_config = + grpc_core::ServiceConfig::Create(svc_cfg, &result.service_config_error); + response_generator_->SetResponse(result); + } + + std::vector GetServersPorts(size_t start_index = 0) { + std::vector ports; + for (size_t i = start_index; i < servers_.size(); ++i) { + ports.push_back(servers_[i]->port_); + } + return ports; + } + + std::unique_ptr BuildStub( + const std::shared_ptr& channel) { + return grpc::testing::EchoTestService::NewStub(channel); + } + + std::shared_ptr BuildChannel() { + ChannelArguments args; + args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR, + response_generator_.get()); + return ::grpc::CreateCustomChannel("fake:///", creds_, args); + } + + std::shared_ptr BuildChannelWithDefaultServiceConfig() { + ChannelArguments args; + args.SetServiceConfigJSON(ValidDefaultServiceConfig()); + args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR, + response_generator_.get()); + return ::grpc::CreateCustomChannel("fake:///", creds_, args); + } + + std::shared_ptr BuildChannelWithInvalidDefaultServiceConfig() { + ChannelArguments args; + args.SetServiceConfigJSON(InvalidDefaultServiceConfig()); + args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR, + response_generator_.get()); + return ::grpc::CreateCustomChannel("fake:///", creds_, args); + } + + bool SendRpc( + const std::unique_ptr& stub, + EchoResponse* response = nullptr, int timeout_ms = 1000, + Status* result = nullptr, bool wait_for_ready = false) { + const bool local_response = (response == nullptr); + if (local_response) response = new EchoResponse; + EchoRequest request; + request.set_message(kRequestMessage_); + ClientContext context; + context.set_deadline(grpc_timeout_milliseconds_to_deadline(timeout_ms)); + if (wait_for_ready) context.set_wait_for_ready(true); + Status status = stub->Echo(&context, request, response); + if (result != nullptr) *result = status; + if (local_response) delete response; + return status.ok(); + } + + void CheckRpcSendOk( + const std::unique_ptr& stub, + const grpc_core::DebugLocation& location, bool wait_for_ready = false) { + EchoResponse response; + Status status; + const bool success = + SendRpc(stub, &response, 2000, &status, wait_for_ready); + ASSERT_TRUE(success) << "From " << location.file() << ":" << location.line() + << "\n" + << "Error: " << status.error_message() << " " + << status.error_details(); + ASSERT_EQ(response.message(), kRequestMessage_) + << "From " << location.file() << ":" << location.line(); + if (!success) abort(); + } + + void CheckRpcSendFailure( + const std::unique_ptr& stub) { + const bool success = SendRpc(stub); + EXPECT_FALSE(success); + } + + struct ServerData { + int port_; + std::unique_ptr server_; + MyTestServiceImpl service_; + std::unique_ptr thread_; + bool server_ready_ = false; + bool started_ = false; + + explicit ServerData(int port = 0) { + port_ = port > 0 ? port : grpc_pick_unused_port_or_die(); + } + + void Start(const grpc::string& server_host) { + gpr_log(GPR_INFO, "starting server on port %d", port_); + started_ = true; + grpc::internal::Mutex mu; + grpc::internal::MutexLock lock(&mu); + grpc::internal::CondVar cond; + thread_.reset(new std::thread( + std::bind(&ServerData::Serve, this, server_host, &mu, &cond))); + cond.WaitUntil(&mu, [this] { return server_ready_; }); + server_ready_ = false; + gpr_log(GPR_INFO, "server startup complete"); + } + + void Serve(const grpc::string& server_host, grpc::internal::Mutex* mu, + grpc::internal::CondVar* cond) { + std::ostringstream server_address; + server_address << server_host << ":" << port_; + ServerBuilder builder; + std::shared_ptr creds(new SecureServerCredentials( + grpc_fake_transport_security_server_credentials_create())); + builder.AddListeningPort(server_address.str(), std::move(creds)); + builder.RegisterService(&service_); + server_ = builder.BuildAndStart(); + grpc::internal::MutexLock lock(mu); + server_ready_ = true; + cond->Signal(); + } + + void Shutdown() { + if (!started_) return; + server_->Shutdown(grpc_timeout_milliseconds_to_deadline(0)); + thread_->join(); + started_ = false; + } + + void SetServingStatus(const grpc::string& service, bool serving) { + server_->GetHealthCheckService()->SetServingStatus(service, serving); + } + }; + + void ResetCounters() { + for (const auto& server : servers_) server->service_.ResetCounters(); + } + + void WaitForServer( + const std::unique_ptr& stub, + size_t server_idx, const grpc_core::DebugLocation& location, + bool ignore_failure = false) { + do { + if (ignore_failure) { + SendRpc(stub); + } else { + CheckRpcSendOk(stub, location, true); + } + } while (servers_[server_idx]->service_.request_count() == 0); + ResetCounters(); + } + + bool WaitForChannelNotReady(Channel* channel, int timeout_seconds = 5) { + const gpr_timespec deadline = + grpc_timeout_seconds_to_deadline(timeout_seconds); + grpc_connectivity_state state; + while ((state = channel->GetState(false /* try_to_connect */)) == + GRPC_CHANNEL_READY) { + if (!channel->WaitForStateChange(state, deadline)) return false; + } + return true; + } + + bool WaitForChannelReady(Channel* channel, int timeout_seconds = 5) { + const gpr_timespec deadline = + grpc_timeout_seconds_to_deadline(timeout_seconds); + grpc_connectivity_state state; + while ((state = channel->GetState(true /* try_to_connect */)) != + GRPC_CHANNEL_READY) { + if (!channel->WaitForStateChange(state, deadline)) return false; + } + return true; + } + + bool SeenAllServers() { + for (const auto& server : servers_) { + if (server->service_.request_count() == 0) return false; + } + return true; + } + + // Updates \a connection_order by appending to it the index of the newly + // connected server. Must be called after every single RPC. + void UpdateConnectionOrder( + const std::vector>& servers, + std::vector* connection_order) { + for (size_t i = 0; i < servers.size(); ++i) { + if (servers[i]->service_.request_count() == 1) { + // Was the server index known? If not, update connection_order. + const auto it = + std::find(connection_order->begin(), connection_order->end(), i); + if (it == connection_order->end()) { + connection_order->push_back(i); + return; + } + } + } + } + + const char* ValidServiceConfigV1() { return "{\"version\": \"1\"}"; } + + const char* ValidServiceConfigV2() { return "{\"version\": \"2\"}"; } + + const char* ValidDefaultServiceConfig() { + return "{\"version\": \"valid_default\"}"; + } + + const char* InvalidDefaultServiceConfig() { + return "{\"version\": \"invalid_default\""; + } + + const grpc::string server_host_; + std::unique_ptr stub_; + std::vector> servers_; + grpc_core::RefCountedPtr + response_generator_; + const grpc::string kRequestMessage_; + std::shared_ptr creds_; +}; + +TEST_F(ServiceConfigEnd2endTest, NoServiceConfigTest) { + StartServers(1); + auto channel = BuildChannel(); + auto stub = BuildStub(channel); + SetNextResolutionNoServiceConfig(GetServersPorts()); + CheckRpcSendOk(stub, DEBUG_LOCATION); + EXPECT_STREQ("", channel->GetServiceConfigJSON().c_str()); +} + +TEST_F(ServiceConfigEnd2endTest, NoServiceConfigWithDefaultConfigTest) { + StartServers(1); + auto channel = BuildChannelWithDefaultServiceConfig(); + auto stub = BuildStub(channel); + SetNextResolutionNoServiceConfig(GetServersPorts()); + CheckRpcSendOk(stub, DEBUG_LOCATION); + EXPECT_STREQ(ValidDefaultServiceConfig(), + channel->GetServiceConfigJSON().c_str()); +} + +TEST_F(ServiceConfigEnd2endTest, InvalidServiceConfigTest) { + StartServers(1); + auto channel = BuildChannel(); + auto stub = BuildStub(channel); + SetNextResolutionInvalidServiceConfig(GetServersPorts()); + CheckRpcSendFailure(stub); +} + +TEST_F(ServiceConfigEnd2endTest, InvalidServiceConfigWithDefaultConfigTest) { + StartServers(1); + auto channel = BuildChannelWithDefaultServiceConfig(); + auto stub = BuildStub(channel); + SetNextResolutionInvalidServiceConfig(GetServersPorts()); + CheckRpcSendOk(stub, DEBUG_LOCATION); + EXPECT_STREQ(ValidDefaultServiceConfig(), + channel->GetServiceConfigJSON().c_str()); +} + +TEST_F(ServiceConfigEnd2endTest, ValidServiceConfigUpdatesTest) { + StartServers(1); + auto channel = BuildChannel(); + auto stub = BuildStub(channel); + SetNextResolutionWithServiceConfig(GetServersPorts(), ValidServiceConfigV1()); + CheckRpcSendOk(stub, DEBUG_LOCATION); + EXPECT_STREQ(ValidServiceConfigV1(), channel->GetServiceConfigJSON().c_str()); + SetNextResolutionWithServiceConfig(GetServersPorts(), ValidServiceConfigV2()); + CheckRpcSendOk(stub, DEBUG_LOCATION); + EXPECT_STREQ(ValidServiceConfigV2(), channel->GetServiceConfigJSON().c_str()); +} + +TEST_F(ServiceConfigEnd2endTest, + NoServiceConfigUpdateAfterValidServiceConfigTest) { + StartServers(1); + auto channel = BuildChannel(); + auto stub = BuildStub(channel); + SetNextResolutionWithServiceConfig(GetServersPorts(), ValidServiceConfigV1()); + CheckRpcSendOk(stub, DEBUG_LOCATION); + EXPECT_STREQ(ValidServiceConfigV1(), channel->GetServiceConfigJSON().c_str()); + SetNextResolutionNoServiceConfig(GetServersPorts()); + CheckRpcSendOk(stub, DEBUG_LOCATION); + EXPECT_STREQ("", channel->GetServiceConfigJSON().c_str()); +} + +TEST_F(ServiceConfigEnd2endTest, + NoServiceConfigUpdateAfterValidServiceConfigWithDefaultConfigTest) { + StartServers(1); + auto channel = BuildChannelWithDefaultServiceConfig(); + auto stub = BuildStub(channel); + SetNextResolutionWithServiceConfig(GetServersPorts(), ValidServiceConfigV1()); + CheckRpcSendOk(stub, DEBUG_LOCATION); + EXPECT_STREQ(ValidServiceConfigV1(), channel->GetServiceConfigJSON().c_str()); + SetNextResolutionNoServiceConfig(GetServersPorts()); + CheckRpcSendOk(stub, DEBUG_LOCATION); + EXPECT_STREQ(ValidDefaultServiceConfig(), + channel->GetServiceConfigJSON().c_str()); +} + +TEST_F(ServiceConfigEnd2endTest, + InvalidServiceConfigUpdateAfterValidServiceConfigTest) { + StartServers(1); + auto channel = BuildChannel(); + auto stub = BuildStub(channel); + SetNextResolutionWithServiceConfig(GetServersPorts(), ValidServiceConfigV1()); + CheckRpcSendOk(stub, DEBUG_LOCATION); + EXPECT_STREQ(ValidServiceConfigV1(), channel->GetServiceConfigJSON().c_str()); + SetNextResolutionInvalidServiceConfig(GetServersPorts()); + CheckRpcSendOk(stub, DEBUG_LOCATION); + EXPECT_STREQ(ValidServiceConfigV1(), channel->GetServiceConfigJSON().c_str()); +} + +TEST_F(ServiceConfigEnd2endTest, + InvalidServiceConfigUpdateAfterValidServiceConfigWithDefaultConfigTest) { + StartServers(1); + auto channel = BuildChannelWithDefaultServiceConfig(); + auto stub = BuildStub(channel); + SetNextResolutionWithServiceConfig(GetServersPorts(), ValidServiceConfigV1()); + CheckRpcSendOk(stub, DEBUG_LOCATION); + EXPECT_STREQ(ValidServiceConfigV1(), channel->GetServiceConfigJSON().c_str()); + SetNextResolutionInvalidServiceConfig(GetServersPorts()); + CheckRpcSendOk(stub, DEBUG_LOCATION); + EXPECT_STREQ(ValidServiceConfigV1(), channel->GetServiceConfigJSON().c_str()); +} + +TEST_F(ServiceConfigEnd2endTest, + ValidServiceConfigAfterInvalidServiceConfigTest) { + StartServers(1); + auto channel = BuildChannel(); + auto stub = BuildStub(channel); + SetNextResolutionInvalidServiceConfig(GetServersPorts()); + CheckRpcSendFailure(stub); + SetNextResolutionValidServiceConfig(GetServersPorts()); + CheckRpcSendOk(stub, DEBUG_LOCATION); +} + +TEST_F(ServiceConfigEnd2endTest, NoServiceConfigAfterInvalidServiceConfigTest) { + StartServers(1); + auto channel = BuildChannel(); + auto stub = BuildStub(channel); + SetNextResolutionInvalidServiceConfig(GetServersPorts()); + CheckRpcSendFailure(stub); + SetNextResolutionNoServiceConfig(GetServersPorts()); + CheckRpcSendOk(stub, DEBUG_LOCATION); + EXPECT_STREQ("", channel->GetServiceConfigJSON().c_str()); +} + +TEST_F(ServiceConfigEnd2endTest, + AnotherInvalidServiceConfigAfterInvalidServiceConfigTest) { + StartServers(1); + auto channel = BuildChannel(); + auto stub = BuildStub(channel); + SetNextResolutionInvalidServiceConfig(GetServersPorts()); + CheckRpcSendFailure(stub); + SetNextResolutionInvalidServiceConfig(GetServersPorts()); + CheckRpcSendFailure(stub); +} + +TEST_F(ServiceConfigEnd2endTest, InvalidDefaultServiceConfigTest) { + StartServers(1); + auto channel = BuildChannelWithInvalidDefaultServiceConfig(); + auto stub = BuildStub(channel); + // An invalid default service config results in a lame channel which fails all + // RPCs + CheckRpcSendFailure(stub); +} + +TEST_F(ServiceConfigEnd2endTest, + InvalidDefaultServiceConfigTestWithValidServiceConfig) { + StartServers(1); + auto channel = BuildChannelWithInvalidDefaultServiceConfig(); + auto stub = BuildStub(channel); + CheckRpcSendFailure(stub); + // An invalid default service config results in a lame channel which fails all + // RPCs + SetNextResolutionValidServiceConfig(GetServersPorts()); + CheckRpcSendFailure(stub); +} + +TEST_F(ServiceConfigEnd2endTest, + InvalidDefaultServiceConfigTestWithInvalidServiceConfig) { + StartServers(1); + auto channel = BuildChannelWithInvalidDefaultServiceConfig(); + auto stub = BuildStub(channel); + CheckRpcSendFailure(stub); + // An invalid default service config results in a lame channel which fails all + // RPCs + SetNextResolutionInvalidServiceConfig(GetServersPorts()); + CheckRpcSendFailure(stub); +} + +TEST_F(ServiceConfigEnd2endTest, + InvalidDefaultServiceConfigTestWithNoServiceConfig) { + StartServers(1); + auto channel = BuildChannelWithInvalidDefaultServiceConfig(); + auto stub = BuildStub(channel); + CheckRpcSendFailure(stub); + // An invalid default service config results in a lame channel which fails all + // RPCs + SetNextResolutionNoServiceConfig(GetServersPorts()); + CheckRpcSendFailure(stub); +} + +} // namespace +} // namespace testing +} // namespace grpc + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + grpc::testing::TestEnvironment env(argc, argv); + const auto result = RUN_ALL_TESTS(); + return result; +} diff --git a/test/cpp/end2end/shutdown_test.cc b/test/cpp/end2end/shutdown_test.cc index da42178d67c..9e925364b1f 100644 --- a/test/cpp/end2end/shutdown_test.cc +++ b/test/cpp/end2end/shutdown_test.cc @@ -86,7 +86,7 @@ class ShutdownTest : public ::testing::TestWithParam { ChannelArguments args; auto channel_creds = GetCredentialsProvider()->GetChannelCredentials(GetParam(), &args); - channel_ = CreateCustomChannel(target, channel_creds, args); + channel_ = ::grpc::CreateCustomChannel(target, channel_creds, args); stub_ = grpc::testing::EchoTestService::NewStub(channel_); } diff --git a/test/cpp/end2end/streaming_throughput_test.cc b/test/cpp/end2end/streaming_throughput_test.cc index 440656588b2..0c10957eb77 100644 --- a/test/cpp/end2end/streaming_throughput_test.cc +++ b/test/cpp/end2end/streaming_throughput_test.cc @@ -145,8 +145,8 @@ class End2endTest : public ::testing::Test { void TearDown() override { server_->Shutdown(); } void ResetStub() { - std::shared_ptr channel = - CreateChannel(server_address_.str(), InsecureChannelCredentials()); + std::shared_ptr channel = grpc::CreateChannel( + server_address_.str(), InsecureChannelCredentials()); stub_ = grpc::testing::EchoTestService::NewStub(channel); } diff --git a/test/cpp/end2end/test_health_check_service_impl.cc b/test/cpp/end2end/test_health_check_service_impl.cc index 0801e301996..5898527a6cd 100644 --- a/test/cpp/end2end/test_health_check_service_impl.cc +++ b/test/cpp/end2end/test_health_check_service_impl.cc @@ -54,6 +54,7 @@ Status HealthCheckServiceImpl::Watch( } if (response.status() != last_state) { writer->Write(response, ::grpc::WriteOptions()); + last_state = response.status(); } } gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), diff --git a/test/cpp/end2end/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc index 5b8af61ee33..eb8e7958b4b 100644 --- a/test/cpp/end2end/thread_stress_test.cc +++ b/test/cpp/end2end/thread_stress_test.cc @@ -96,8 +96,8 @@ template class CommonStressTestInsecure : public CommonStressTest { public: void ResetStub() override { - std::shared_ptr channel = - CreateChannel(server_address_.str(), InsecureChannelCredentials()); + std::shared_ptr channel = grpc::CreateChannel( + server_address_.str(), InsecureChannelCredentials()); this->stub_ = grpc::testing::EchoTestService::NewStub(channel); } bool AllowExhaustion() override { return false; } diff --git a/test/cpp/end2end/time_change_test.cc b/test/cpp/end2end/time_change_test.cc index 7f4e3caf6f9..688549e5772 100644 --- a/test/cpp/end2end/time_change_test.cc +++ b/test/cpp/end2end/time_change_test.cc @@ -139,7 +139,7 @@ class TimeChangeTest : public ::testing::Test { "--address=" + addr, })); GPR_ASSERT(server_); - channel_ = CreateChannel(addr, InsecureChannelCredentials()); + channel_ = grpc::CreateChannel(addr, InsecureChannelCredentials()); GPR_ASSERT(channel_); stub_ = grpc::testing::EchoTestService::NewStub(channel_); } diff --git a/test/cpp/end2end/xds_end2end_test.cc b/test/cpp/end2end/xds_end2end_test.cc index ee248239909..87a231c588d 100644 --- a/test/cpp/end2end/xds_end2end_test.cc +++ b/test/cpp/end2end/xds_end2end_test.cc @@ -33,6 +33,7 @@ #include #include +#include "src/core/ext/filters/client_channel/backup_poller.h" #include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h" #include "src/core/ext/filters/client_channel/server_address.h" @@ -370,7 +371,7 @@ class XdsEnd2endTest : public ::testing::Test { client_load_reporting_interval_seconds) { // Make the backup poller poll very frequently in order to pick up // updates from all the subchannels's FDs. - gpr_setenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS", "1"); + GPR_GLOBAL_CONFIG_SET(grpc_client_channel_backup_poll_interval_ms, 1); } void SetUp() override { @@ -413,7 +414,9 @@ class XdsEnd2endTest : public ::testing::Test { const grpc::string& expected_targets = "") { ChannelArguments args; // TODO(juanlishen): Add setter to ChannelArguments. - args.SetInt(GRPC_ARG_XDS_FALLBACK_TIMEOUT_MS, fallback_timeout); + if (fallback_timeout > 0) { + args.SetInt(GRPC_ARG_XDS_FALLBACK_TIMEOUT_MS, fallback_timeout); + } args.SetPointer(GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR, response_generator_.get()); if (!expected_targets.empty()) { @@ -432,7 +435,7 @@ class XdsEnd2endTest : public ::testing::Test { channel_creds, call_creds, nullptr))); call_creds->Unref(); channel_creds->Unref(); - channel_ = CreateCustomChannel(uri.str(), creds, args); + channel_ = ::grpc::CreateCustomChannel(uri.str(), creds, args); stub_ = grpc::testing::EchoTestService::NewStub(channel_); } @@ -855,15 +858,230 @@ TEST_F(SingleBalancerTest, AllServersUnreachableFailFast) { EXPECT_EQ(1U, balancers_[0]->service_.response_count()); } -// The fallback tests are deferred because the fallback mode hasn't been -// supported yet. +TEST_F(SingleBalancerTest, Fallback) { + const int kFallbackTimeoutMs = 200 * grpc_test_slowdown_factor(); + const int kServerlistDelayMs = 500 * grpc_test_slowdown_factor(); + const size_t kNumBackendsInResolution = backends_.size() / 2; + ResetStub(kFallbackTimeoutMs); + SetNextResolution(GetBackendPorts(0, kNumBackendsInResolution), + kDefaultServiceConfig_.c_str()); + SetNextResolutionForLbChannelAllBalancers(); + // Send non-empty serverlist only after kServerlistDelayMs. + ScheduleResponseForBalancer( + 0, + BalancerServiceImpl::BuildResponseForBackends( + GetBackendPorts(kNumBackendsInResolution /* start_index */), {}), + kServerlistDelayMs); + // Wait until all the fallback backends are reachable. + WaitForAllBackends(1 /* num_requests_multiple_of */, 0 /* start_index */, + kNumBackendsInResolution /* stop_index */); + gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH =========="); + CheckRpcSendOk(kNumBackendsInResolution); + gpr_log(GPR_INFO, "========= DONE WITH FIRST BATCH =========="); + // Fallback is used: each backend returned by the resolver should have + // gotten one request. + for (size_t i = 0; i < kNumBackendsInResolution; ++i) { + EXPECT_EQ(1U, backends_[i]->service_.request_count()); + } + for (size_t i = kNumBackendsInResolution; i < backends_.size(); ++i) { + EXPECT_EQ(0U, backends_[i]->service_.request_count()); + } + // Wait until the serverlist reception has been processed and all backends + // in the serverlist are reachable. + WaitForAllBackends(1 /* num_requests_multiple_of */, + kNumBackendsInResolution /* start_index */); + gpr_log(GPR_INFO, "========= BEFORE SECOND BATCH =========="); + CheckRpcSendOk(backends_.size() - kNumBackendsInResolution); + gpr_log(GPR_INFO, "========= DONE WITH SECOND BATCH =========="); + // Serverlist is used: each backend returned by the balancer should + // have gotten one request. + for (size_t i = 0; i < kNumBackendsInResolution; ++i) { + EXPECT_EQ(0U, backends_[i]->service_.request_count()); + } + for (size_t i = kNumBackendsInResolution; i < backends_.size(); ++i) { + EXPECT_EQ(1U, backends_[i]->service_.request_count()); + } + // The balancer got a single request. + EXPECT_EQ(1U, balancers_[0]->service_.request_count()); + // and sent a single response. + EXPECT_EQ(1U, balancers_[0]->service_.response_count()); +} + +TEST_F(SingleBalancerTest, FallbackUpdate) { + const int kFallbackTimeoutMs = 200 * grpc_test_slowdown_factor(); + const int kServerlistDelayMs = 500 * grpc_test_slowdown_factor(); + const size_t kNumBackendsInResolution = backends_.size() / 3; + const size_t kNumBackendsInResolutionUpdate = backends_.size() / 3; + ResetStub(kFallbackTimeoutMs); + SetNextResolution(GetBackendPorts(0, kNumBackendsInResolution), + kDefaultServiceConfig_.c_str()); + SetNextResolutionForLbChannelAllBalancers(); + // Send non-empty serverlist only after kServerlistDelayMs. + ScheduleResponseForBalancer( + 0, + BalancerServiceImpl::BuildResponseForBackends( + GetBackendPorts(kNumBackendsInResolution + + kNumBackendsInResolutionUpdate /* start_index */), + {}), + kServerlistDelayMs); + // Wait until all the fallback backends are reachable. + WaitForAllBackends(1 /* num_requests_multiple_of */, 0 /* start_index */, + kNumBackendsInResolution /* stop_index */); + gpr_log(GPR_INFO, "========= BEFORE FIRST BATCH =========="); + CheckRpcSendOk(kNumBackendsInResolution); + gpr_log(GPR_INFO, "========= DONE WITH FIRST BATCH =========="); + // Fallback is used: each backend returned by the resolver should have + // gotten one request. + for (size_t i = 0; i < kNumBackendsInResolution; ++i) { + EXPECT_EQ(1U, backends_[i]->service_.request_count()); + } + for (size_t i = kNumBackendsInResolution; i < backends_.size(); ++i) { + EXPECT_EQ(0U, backends_[i]->service_.request_count()); + } + SetNextResolution(GetBackendPorts(kNumBackendsInResolution, + kNumBackendsInResolution + + kNumBackendsInResolutionUpdate), + kDefaultServiceConfig_.c_str()); + // Wait until the resolution update has been processed and all the new + // fallback backends are reachable. + WaitForAllBackends(1 /* num_requests_multiple_of */, + kNumBackendsInResolution /* start_index */, + kNumBackendsInResolution + + kNumBackendsInResolutionUpdate /* stop_index */); + gpr_log(GPR_INFO, "========= BEFORE SECOND BATCH =========="); + CheckRpcSendOk(kNumBackendsInResolutionUpdate); + gpr_log(GPR_INFO, "========= DONE WITH SECOND BATCH =========="); + // The resolution update is used: each backend in the resolution update should + // have gotten one request. + for (size_t i = 0; i < kNumBackendsInResolution; ++i) { + EXPECT_EQ(0U, backends_[i]->service_.request_count()); + } + for (size_t i = kNumBackendsInResolution; + i < kNumBackendsInResolution + kNumBackendsInResolutionUpdate; ++i) { + EXPECT_EQ(1U, backends_[i]->service_.request_count()); + } + for (size_t i = kNumBackendsInResolution + kNumBackendsInResolutionUpdate; + i < backends_.size(); ++i) { + EXPECT_EQ(0U, backends_[i]->service_.request_count()); + } + // Wait until the serverlist reception has been processed and all backends + // in the serverlist are reachable. + WaitForAllBackends(1 /* num_requests_multiple_of */, + kNumBackendsInResolution + + kNumBackendsInResolutionUpdate /* start_index */); + gpr_log(GPR_INFO, "========= BEFORE THIRD BATCH =========="); + CheckRpcSendOk(backends_.size() - kNumBackendsInResolution - + kNumBackendsInResolutionUpdate); + gpr_log(GPR_INFO, "========= DONE WITH THIRD BATCH =========="); + // Serverlist is used: each backend returned by the balancer should + // have gotten one request. + for (size_t i = 0; + i < kNumBackendsInResolution + kNumBackendsInResolutionUpdate; ++i) { + EXPECT_EQ(0U, backends_[i]->service_.request_count()); + } + for (size_t i = kNumBackendsInResolution + kNumBackendsInResolutionUpdate; + i < backends_.size(); ++i) { + EXPECT_EQ(1U, backends_[i]->service_.request_count()); + } + // The balancer got a single request. + EXPECT_EQ(1U, balancers_[0]->service_.request_count()); + // and sent a single response. + EXPECT_EQ(1U, balancers_[0]->service_.response_count()); +} + +TEST_F(SingleBalancerTest, FallbackEarlyWhenBalancerChannelFails) { + const int kFallbackTimeoutMs = 10000 * grpc_test_slowdown_factor(); + ResetStub(kFallbackTimeoutMs); + // Return an unreachable balancer and one fallback backend. + SetNextResolution({backends_[0]->port_}, kDefaultServiceConfig_.c_str()); + SetNextResolutionForLbChannel({grpc_pick_unused_port_or_die()}); + // Send RPC with deadline less than the fallback timeout and make sure it + // succeeds. + CheckRpcSendOk(/* times */ 1, /* timeout_ms */ 1000, + /* wait_for_ready */ false); +} -// TODO(juanlishen): Add TEST_F(SingleBalancerTest, Fallback) +TEST_F(SingleBalancerTest, FallbackEarlyWhenBalancerCallFails) { + const int kFallbackTimeoutMs = 10000 * grpc_test_slowdown_factor(); + ResetStub(kFallbackTimeoutMs); + // Return one balancer and one fallback backend. + SetNextResolution({backends_[0]->port_}, kDefaultServiceConfig_.c_str()); + SetNextResolutionForLbChannelAllBalancers(); + // Balancer drops call without sending a serverlist. + balancers_[0]->service_.NotifyDoneWithServerlists(); + // Send RPC with deadline less than the fallback timeout and make sure it + // succeeds. + CheckRpcSendOk(/* times */ 1, /* timeout_ms */ 1000, + /* wait_for_ready */ false); +} + +TEST_F(SingleBalancerTest, FallbackIfResponseReceivedButChildNotReady) { + const int kFallbackTimeoutMs = 500 * grpc_test_slowdown_factor(); + ResetStub(kFallbackTimeoutMs); + SetNextResolution({backends_[0]->port_}, kDefaultServiceConfig_.c_str()); + SetNextResolutionForLbChannelAllBalancers(); + // Send a serverlist that only contains an unreachable backend before fallback + // timeout. + ScheduleResponseForBalancer(0, + BalancerServiceImpl::BuildResponseForBackends( + {grpc_pick_unused_port_or_die()}, {}), + 0); + // Because no child policy is ready before fallback timeout, we enter fallback + // mode. + WaitForBackend(0); +} -// TODO(juanlishen): Add TEST_F(SingleBalancerTest, FallbackUpdate) +TEST_F(SingleBalancerTest, FallbackModeIsExitedWhenBalancerSaysToDropAllCalls) { + // Return an unreachable balancer and one fallback backend. + SetNextResolution({backends_[0]->port_}, kDefaultServiceConfig_.c_str()); + SetNextResolutionForLbChannel({grpc_pick_unused_port_or_die()}); + // Enter fallback mode because the LB channel fails to connect. + WaitForBackend(0); + // Return a new balancer that sends an empty serverlist. + ScheduleResponseForBalancer( + 0, BalancerServiceImpl::BuildResponseForBackends({}, {}), 0); + SetNextResolutionForLbChannelAllBalancers(); + // Send RPCs until failure. + gpr_timespec deadline = gpr_time_add( + gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(5000, GPR_TIMESPAN)); + do { + auto status = SendRpc(); + if (!status.ok()) break; + } while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0); + CheckRpcSendFailure(); +} -// TODO(juanlishen): Add TEST_F(SingleBalancerTest, -// FallbackEarlyWhenBalancerChannelFails) +TEST_F(SingleBalancerTest, FallbackModeIsExitedAfterChildRready) { + // Return an unreachable balancer and one fallback backend. + SetNextResolution({backends_[0]->port_}, kDefaultServiceConfig_.c_str()); + SetNextResolutionForLbChannel({grpc_pick_unused_port_or_die()}); + // Enter fallback mode because the LB channel fails to connect. + WaitForBackend(0); + // Return a new balancer that sends a dead backend. + ShutdownBackend(1); + ScheduleResponseForBalancer( + 0, + BalancerServiceImpl::BuildResponseForBackends({backends_[1]->port_}, {}), + 0); + SetNextResolutionForLbChannelAllBalancers(); + // The state (TRANSIENT_FAILURE) update from the child policy will be ignored + // because we are still in fallback mode. + gpr_timespec deadline = gpr_time_add( + gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(5000, GPR_TIMESPAN)); + // Send 5 seconds worth of RPCs. + do { + CheckRpcSendOk(); + } while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0); + // After the backend is restarted, the child policy will eventually be READY, + // and we will exit fallback mode. + StartBackend(1); + WaitForBackend(1); + // We have exited fallback mode, so calls will go to the child policy + // exclusively. + CheckRpcSendOk(100); + EXPECT_EQ(0U, backends_[0]->service_.request_count()); + EXPECT_EQ(100U, backends_[1]->service_.request_count()); +} TEST_F(SingleBalancerTest, BackendsRestart) { SetNextResolution({}, kDefaultServiceConfig_.c_str()); diff --git a/test/cpp/microbenchmarks/BUILD b/test/cpp/microbenchmarks/BUILD index 6e844a6dc62..d9424f24f16 100644 --- a/test/cpp/microbenchmarks/BUILD +++ b/test/cpp/microbenchmarks/BUILD @@ -39,85 +39,85 @@ grpc_cc_library( external_deps = [ "benchmark", ], + tags = ["no_windows"], deps = [ "//:grpc++_unsecure", "//src/proto/grpc/testing:echo_proto", "//test/core/util:grpc_test_util_unsecure", "//test/cpp/util:test_config", ], - tags = ["no_windows"], ) grpc_cc_binary( name = "bm_closure", testonly = 1, srcs = ["bm_closure.cc"], - deps = [":helpers"], tags = ["no_windows"], + deps = [":helpers"], ) grpc_cc_binary( name = "bm_alarm", testonly = 1, srcs = ["bm_alarm.cc"], - deps = [":helpers"], tags = ["no_windows"], + deps = [":helpers"], ) grpc_cc_binary( name = "bm_arena", testonly = 1, srcs = ["bm_arena.cc"], - deps = [":helpers"], tags = ["no_windows"], + deps = [":helpers"], ) grpc_cc_binary( name = "bm_byte_buffer", testonly = 1, srcs = ["bm_byte_buffer.cc"], - deps = [":helpers"], tags = ["no_windows"], + deps = [":helpers"], ) grpc_cc_binary( name = "bm_channel", testonly = 1, srcs = ["bm_channel.cc"], - deps = [":helpers"], tags = ["no_windows"], + deps = [":helpers"], ) grpc_cc_binary( name = "bm_call_create", testonly = 1, srcs = ["bm_call_create.cc"], - deps = [":helpers"], tags = ["no_windows"], + deps = [":helpers"], ) grpc_cc_binary( name = "bm_cq", testonly = 1, srcs = ["bm_cq.cc"], - deps = [":helpers"], tags = ["no_windows"], + deps = [":helpers"], ) grpc_cc_binary( name = "bm_cq_multiple_threads", testonly = 1, srcs = ["bm_cq_multiple_threads.cc"], - deps = [":helpers"], tags = ["no_windows"], + deps = [":helpers"], ) grpc_cc_binary( name = "bm_error", testonly = 1, srcs = ["bm_error.cc"], - deps = [":helpers"], tags = ["no_windows"], + deps = [":helpers"], ) grpc_cc_library( @@ -126,8 +126,8 @@ grpc_cc_library( hdrs = [ "fullstack_streaming_ping_pong.h", ], - deps = [":helpers"], tags = ["no_windows"], + deps = [":helpers"], ) grpc_cc_binary( @@ -136,8 +136,8 @@ grpc_cc_binary( srcs = [ "bm_fullstack_streaming_ping_pong.cc", ], - deps = [":fullstack_streaming_ping_pong_h"], tags = ["no_windows"], + deps = [":fullstack_streaming_ping_pong_h"], ) grpc_cc_library( @@ -155,16 +155,16 @@ grpc_cc_binary( srcs = [ "bm_fullstack_streaming_pump.cc", ], - deps = [":fullstack_streaming_pump_h"], tags = ["no_windows"], + deps = [":fullstack_streaming_pump_h"], ) grpc_cc_binary( name = "bm_fullstack_trickle", testonly = 1, srcs = ["bm_fullstack_trickle.cc"], - deps = [":helpers"], tags = ["no_windows"], + deps = [":helpers"], ) grpc_cc_library( @@ -182,24 +182,24 @@ grpc_cc_binary( srcs = [ "bm_fullstack_unary_ping_pong.cc", ], - deps = [":fullstack_unary_ping_pong_h"], tags = ["no_windows"], + deps = [":fullstack_unary_ping_pong_h"], ) grpc_cc_binary( name = "bm_metadata", testonly = 1, srcs = ["bm_metadata.cc"], - deps = [":helpers"], tags = ["no_windows"], + deps = [":helpers"], ) grpc_cc_binary( name = "bm_chttp2_hpack", testonly = 1, srcs = ["bm_chttp2_hpack.cc"], - deps = [":helpers"], tags = ["no_windows"], + deps = [":helpers"], ) grpc_cc_binary( @@ -218,6 +218,65 @@ grpc_cc_binary( name = "bm_timer", testonly = 1, srcs = ["bm_timer.cc"], + tags = ["no_windows"], deps = [":helpers"], +) + +grpc_cc_library( + name = "bm_callback_test_service_impl", + testonly = 1, + srcs = ["callback_test_service.cc"], + hdrs = ["callback_test_service.h"], + external_deps = [ + "benchmark", + ], + deps = [ + ":helpers", + "//src/proto/grpc/testing:echo_proto", + "//test/cpp/util:test_util", + ], +) + +grpc_cc_library( + name = "callback_unary_ping_pong_h", + testonly = 1, + hdrs = [ + "callback_unary_ping_pong.h", + ], + deps = [ + ":bm_callback_test_service_impl", + ":helpers", + ], +) + +grpc_cc_binary( + name = "bm_callback_unary_ping_pong", + testonly = 1, + srcs = [ + "bm_callback_unary_ping_pong.cc", + ], + tags = ["no_windows"], + deps = [":callback_unary_ping_pong_h"], +) + +grpc_cc_library( + name = "callback_streaming_ping_pong_h", + testonly = 1, + hdrs = [ + "callback_streaming_ping_pong.h", + ], + deps = [ + ":bm_callback_test_service_impl", + ":helpers", + ], +) + +grpc_cc_binary( + name = "bm_callback_streaming_ping_pong", + testonly = 1, + srcs = [ + "bm_callback_streaming_ping_pong.cc", + ], tags = ["no_windows"], + deps = [":callback_streaming_ping_pong_h"], ) diff --git a/test/cpp/microbenchmarks/bm_alarm.cc b/test/cpp/microbenchmarks/bm_alarm.cc index 64aad6476de..d95771a57c6 100644 --- a/test/cpp/microbenchmarks/bm_alarm.cc +++ b/test/cpp/microbenchmarks/bm_alarm.cc @@ -30,8 +30,6 @@ namespace grpc { namespace testing { -auto& force_library_initialization = Library::get(); - static void BM_Alarm_Tag_Immediate(benchmark::State& state) { TrackCounters track_counters; CompletionQueue cq; @@ -57,6 +55,7 @@ void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } } // namespace benchmark int main(int argc, char** argv) { + LibraryInitializer libInit; ::benchmark::Initialize(&argc, argv); ::grpc::testing::InitTest(&argc, &argv, false); benchmark::RunTheBenchmarksNamespaced(); diff --git a/test/cpp/microbenchmarks/bm_arena.cc b/test/cpp/microbenchmarks/bm_arena.cc index b97c954fae8..c3ded0d76f7 100644 --- a/test/cpp/microbenchmarks/bm_arena.cc +++ b/test/cpp/microbenchmarks/bm_arena.cc @@ -19,40 +19,42 @@ /* Benchmark arenas */ #include -#include "src/core/lib/gpr/arena.h" +#include "src/core/lib/gprpp/arena.h" #include "test/cpp/microbenchmarks/helpers.h" #include "test/cpp/util/test_config.h" +using grpc_core::Arena; + static void BM_Arena_NoOp(benchmark::State& state) { while (state.KeepRunning()) { - gpr_arena_destroy(gpr_arena_create(state.range(0))); + Arena::Create(state.range(0))->Destroy(); } } BENCHMARK(BM_Arena_NoOp)->Range(1, 1024 * 1024); static void BM_Arena_ManyAlloc(benchmark::State& state) { - gpr_arena* a = gpr_arena_create(state.range(0)); + Arena* a = Arena::Create(state.range(0)); const size_t realloc_after = 1024 * 1024 * 1024 / ((state.range(1) + 15) & 0xffffff0u); while (state.KeepRunning()) { - gpr_arena_alloc(a, state.range(1)); + a->Alloc(state.range(1)); // periodically recreate arena to avoid OOM if (state.iterations() % realloc_after == 0) { - gpr_arena_destroy(a); - a = gpr_arena_create(state.range(0)); + a->Destroy(); + a = Arena::Create(state.range(0)); } } - gpr_arena_destroy(a); + a->Destroy(); } BENCHMARK(BM_Arena_ManyAlloc)->Ranges({{1, 1024 * 1024}, {1, 32 * 1024}}); static void BM_Arena_Batch(benchmark::State& state) { while (state.KeepRunning()) { - gpr_arena* a = gpr_arena_create(state.range(0)); + Arena* a = Arena::Create(state.range(0)); for (int i = 0; i < state.range(1); i++) { - gpr_arena_alloc(a, state.range(2)); + a->Alloc(state.range(2)); } - gpr_arena_destroy(a); + a->Destroy(); } } BENCHMARK(BM_Arena_Batch)->Ranges({{1, 64 * 1024}, {1, 64}, {1, 1024}}); diff --git a/test/cpp/microbenchmarks/bm_byte_buffer.cc b/test/cpp/microbenchmarks/bm_byte_buffer.cc index 644c27c4873..595cc734b69 100644 --- a/test/cpp/microbenchmarks/bm_byte_buffer.cc +++ b/test/cpp/microbenchmarks/bm_byte_buffer.cc @@ -30,7 +30,6 @@ namespace grpc { namespace testing { static void BM_ByteBuffer_Copy(benchmark::State& state) { - Library::get(); int num_slices = state.range(0); size_t slice_size = state.range(1); std::vector slices; @@ -48,7 +47,6 @@ static void BM_ByteBuffer_Copy(benchmark::State& state) { BENCHMARK(BM_ByteBuffer_Copy)->Ranges({{1, 64}, {1, 1024 * 1024}}); static void BM_ByteBufferReader_Next(benchmark::State& state) { - Library::get(); const int num_slices = state.range(0); constexpr size_t kSliceSize = 16; std::vector slices; @@ -82,7 +80,6 @@ static void BM_ByteBufferReader_Next(benchmark::State& state) { BENCHMARK(BM_ByteBufferReader_Next)->Ranges({{64 * 1024, 1024 * 1024}}); static void BM_ByteBufferReader_Peek(benchmark::State& state) { - Library::get(); const int num_slices = state.range(0); constexpr size_t kSliceSize = 16; std::vector slices; @@ -125,6 +122,7 @@ void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } } // namespace benchmark int main(int argc, char** argv) { + LibraryInitializer libInit; ::benchmark::Initialize(&argc, argv); ::grpc::testing::InitTest(&argc, &argv, false); benchmark::RunTheBenchmarksNamespaced(); diff --git a/test/cpp/microbenchmarks/bm_call_create.cc b/test/cpp/microbenchmarks/bm_call_create.cc index e84999b213f..3bd1464b2aa 100644 --- a/test/cpp/microbenchmarks/bm_call_create.cc +++ b/test/cpp/microbenchmarks/bm_call_create.cc @@ -47,8 +47,6 @@ #include "test/cpp/microbenchmarks/helpers.h" #include "test/cpp/util/test_config.h" -auto& force_library_initialization = Library::get(); - void BM_Zalloc(benchmark::State& state) { // speed of light for call creation is zalloc, so benchmark a few interesting // sizes @@ -405,7 +403,7 @@ const char* name; /* implementation of grpc_transport_init_stream */ int InitStream(grpc_transport* self, grpc_stream* stream, grpc_stream_refcount* refcount, const void* server_data, - gpr_arena* arena) { + grpc_core::Arena* arena) { return 0; } @@ -540,7 +538,7 @@ static void BM_IsolatedFilter(benchmark::State& state) { method, start_time, deadline, - gpr_arena_create(kArenaSize), + grpc_core::Arena::Create(kArenaSize), nullptr}; while (state.KeepRunning()) { GPR_TIMER_SCOPE("BenchmarkCycle", 0); @@ -552,11 +550,11 @@ static void BM_IsolatedFilter(benchmark::State& state) { grpc_core::ExecCtx::Get()->Flush(); // recreate arena every 64k iterations to avoid oom if (0 == (state.iterations() & 0xffff)) { - gpr_arena_destroy(call_args.arena); - call_args.arena = gpr_arena_create(kArenaSize); + call_args.arena->Destroy(); + call_args.arena = grpc_core::Arena::Create(kArenaSize); } } - gpr_arena_destroy(call_args.arena); + call_args.arena->Destroy(); grpc_channel_stack_destroy(channel_stack); grpc_core::ExecCtx::Get()->Flush(); @@ -609,7 +607,7 @@ BENCHMARK_TEMPLATE(BM_IsolatedFilter, MessageSizeFilter, SendEmptyMetadata); namespace isolated_call_filter { typedef struct { - grpc_call_combiner* call_combiner; + grpc_core::CallCombiner* call_combiner; } call_data; static void StartTransportStreamOp(grpc_call_element* elem, @@ -823,6 +821,7 @@ void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } } // namespace benchmark int main(int argc, char** argv) { + LibraryInitializer libInit; ::benchmark::Initialize(&argc, argv); ::grpc::testing::InitTest(&argc, &argv, false); benchmark::RunTheBenchmarksNamespaced(); diff --git a/test/cpp/microbenchmarks/bm_callback_streaming_ping_pong.cc b/test/cpp/microbenchmarks/bm_callback_streaming_ping_pong.cc new file mode 100644 index 00000000000..cde3eb2a241 --- /dev/null +++ b/test/cpp/microbenchmarks/bm_callback_streaming_ping_pong.cc @@ -0,0 +1,136 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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 "test/cpp/microbenchmarks/callback_streaming_ping_pong.h" +#include "test/cpp/util/test_config.h" + +namespace grpc { +namespace testing { + +/******************************************************************************* + * CONFIGURATIONS + */ + +// Replace "benchmark::internal::Benchmark" with "::testing::Benchmark" to use +// internal microbenchmarking tooling +static void StreamingPingPongMsgSizeArgs(benchmark::internal::Benchmark* b) { + // base case: 0 byte ping-pong msgs + b->Args({0, 1}); + b->Args({0, 2}); + + for (int msg_size = 1; msg_size <= 128 * 1024 * 1024; msg_size *= 8) { + b->Args({msg_size, 1}); + b->Args({msg_size, 2}); + } +} + +// Replace "benchmark::internal::Benchmark" with "::testing::Benchmark" to use +// internal microbenchmarking tooling +static void StreamingPingPongMsgsNumberArgs(benchmark::internal::Benchmark* b) { + for (int msg_number = 1; msg_number <= 256 * 1024; msg_number *= 8) { + b->Args({0, msg_number}); + b->Args({1024, msg_number}); + } +} + +// Streaming with different message size +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, NoOpMutator, + NoOpMutator) + ->Apply(StreamingPingPongMsgSizeArgs); +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, MinInProcess, NoOpMutator, + NoOpMutator) + ->Apply(StreamingPingPongMsgSizeArgs); + +// Streaming with different message number +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, NoOpMutator, + NoOpMutator) + ->Apply(StreamingPingPongMsgsNumberArgs); +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, MinInProcess, NoOpMutator, + NoOpMutator) + ->Apply(StreamingPingPongMsgsNumberArgs); + +// Client context with different metadata +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, + Client_AddMetadata, 1>, NoOpMutator) + ->Args({0, 1}); +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, + Client_AddMetadata, 1>, NoOpMutator) + ->Args({0, 1}); +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, + Client_AddMetadata, 1>, + NoOpMutator) + ->Args({0, 1}); +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, + Client_AddMetadata, 2>, NoOpMutator) + ->Args({0, 1}); +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, + Client_AddMetadata, 2>, NoOpMutator) + ->Args({0, 1}); +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, + Client_AddMetadata, 2>, + NoOpMutator) + ->Args({0, 1}); +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, + Client_AddMetadata, 1>, NoOpMutator) + ->Args({0, 1}); +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, + Client_AddMetadata, 1>, NoOpMutator) + ->Args({0, 1}); +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, + Client_AddMetadata, 1>, NoOpMutator) + ->Args({0, 1}); + +// Server context with different metadata +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, NoOpMutator, + Server_AddInitialMetadata, 1>) + ->Args({0, 1}); +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, NoOpMutator, + Server_AddInitialMetadata, 1>) + ->Args({0, 1}); +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, NoOpMutator, + Server_AddInitialMetadata, 1>) + ->Args({0, 1}); +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, NoOpMutator, + Server_AddInitialMetadata, 1>) + ->Args({0, 1}); +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, NoOpMutator, + Server_AddInitialMetadata, 1>) + ->Args({0, 1}); +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, NoOpMutator, + Server_AddInitialMetadata, 1>) + ->Args({0, 1}); +BENCHMARK_TEMPLATE(BM_CallbackBidiStreaming, InProcess, NoOpMutator, + Server_AddInitialMetadata, 100>) + ->Args({0, 1}); + +} // namespace testing +} // namespace grpc + +// Some distros have RunSpecifiedBenchmarks under the benchmark namespace, +// and others do not. This allows us to support both modes. +namespace benchmark { +void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } +} // namespace benchmark + +int main(int argc, char** argv) { + LibraryInitializer libInit; + ::benchmark::Initialize(&argc, argv); + ::grpc::testing::InitTest(&argc, &argv, false); + benchmark::RunTheBenchmarksNamespaced(); + return 0; +} diff --git a/test/cpp/microbenchmarks/bm_callback_unary_ping_pong.cc b/test/cpp/microbenchmarks/bm_callback_unary_ping_pong.cc new file mode 100644 index 00000000000..4ee77525bc6 --- /dev/null +++ b/test/cpp/microbenchmarks/bm_callback_unary_ping_pong.cc @@ -0,0 +1,118 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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 "test/cpp/microbenchmarks/callback_unary_ping_pong.h" +#include "test/cpp/util/test_config.h" + +namespace grpc { +namespace testing { + +/******************************************************************************* + * CONFIGURATIONS + */ + +// Replace "benchmark::internal::Benchmark" with "::testing::Benchmark" to use +// internal microbenchmarking tooling +static void SweepSizesArgs(benchmark::internal::Benchmark* b) { + b->Args({0, 0}); + for (int i = 1; i <= 128 * 1024 * 1024; i *= 8) { + // First argument is the message size of request + // Second argument is the message size of response + b->Args({i, 0}); + b->Args({0, i}); + b->Args({i, i}); + } +} + +// Unary ping pong with different message size of request and response +BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, NoOpMutator, + NoOpMutator) + ->Apply(SweepSizesArgs); +BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, MinInProcess, NoOpMutator, + NoOpMutator) + ->Apply(SweepSizesArgs); + +// Client context with different metadata +BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, + Client_AddMetadata, 1>, NoOpMutator) + ->Args({0, 0}); +BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, + Client_AddMetadata, 1>, NoOpMutator) + ->Args({0, 0}); +BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, + Client_AddMetadata, 1>, + NoOpMutator) + ->Args({0, 0}); +BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, + Client_AddMetadata, 2>, NoOpMutator) + ->Args({0, 0}); +BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, + Client_AddMetadata, 2>, NoOpMutator) + ->Args({0, 0}); +BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, + Client_AddMetadata, 2>, + NoOpMutator) + ->Args({0, 0}); +BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, + Client_AddMetadata, 1>, NoOpMutator) + ->Args({0, 0}); +BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, + Client_AddMetadata, 1>, NoOpMutator) + ->Args({0, 0}); +BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, + Client_AddMetadata, 1>, NoOpMutator) + ->Args({0, 0}); + +// Server context with different metadata +BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, NoOpMutator, + Server_AddInitialMetadata, 1>) + ->Args({0, 0}); +BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, NoOpMutator, + Server_AddInitialMetadata, 1>) + ->Args({0, 0}); +BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, NoOpMutator, + Server_AddInitialMetadata, 1>) + ->Args({0, 0}); +BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, NoOpMutator, + Server_AddInitialMetadata, 1>) + ->Args({0, 0}); +BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, NoOpMutator, + Server_AddInitialMetadata, 1>) + ->Args({0, 0}); +BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, NoOpMutator, + Server_AddInitialMetadata, 1>) + ->Args({0, 0}); +BENCHMARK_TEMPLATE(BM_CallbackUnaryPingPong, InProcess, NoOpMutator, + Server_AddInitialMetadata, 100>) + ->Args({0, 0}); +} // namespace testing +} // namespace grpc + +// Some distros have RunSpecifiedBenchmarks under the benchmark namespace, +// and others do not. This allows us to support both modes. +namespace benchmark { +void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } +} // namespace benchmark + +int main(int argc, char** argv) { + LibraryInitializer libInit; + ::benchmark::Initialize(&argc, argv); + ::grpc::testing::InitTest(&argc, &argv, false); + benchmark::RunTheBenchmarksNamespaced(); + return 0; +} diff --git a/test/cpp/microbenchmarks/bm_channel.cc b/test/cpp/microbenchmarks/bm_channel.cc index 15ac9975400..88856c3439b 100644 --- a/test/cpp/microbenchmarks/bm_channel.cc +++ b/test/cpp/microbenchmarks/bm_channel.cc @@ -23,8 +23,6 @@ #include "test/cpp/microbenchmarks/helpers.h" #include "test/cpp/util/test_config.h" -auto& force_library_initialization = Library::get(); - class ChannelDestroyerFixture { public: ChannelDestroyerFixture() {} @@ -83,6 +81,7 @@ void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } } // namespace benchmark int main(int argc, char** argv) { + LibraryInitializer libInit; ::benchmark::Initialize(&argc, argv); ::grpc::testing::InitTest(&argc, &argv, false); benchmark::RunTheBenchmarksNamespaced(); diff --git a/test/cpp/microbenchmarks/bm_chttp2_hpack.cc b/test/cpp/microbenchmarks/bm_chttp2_hpack.cc index 85d233dd264..d0ed1da7671 100644 --- a/test/cpp/microbenchmarks/bm_chttp2_hpack.cc +++ b/test/cpp/microbenchmarks/bm_chttp2_hpack.cc @@ -36,8 +36,6 @@ #include "test/cpp/microbenchmarks/helpers.h" #include "test/cpp/util/test_config.h" -auto& force_library_initialization = Library::get(); - static grpc_slice MakeSlice(std::vector bytes) { grpc_slice s = grpc_slice_malloc(bytes.size()); uint8_t* p = GRPC_SLICE_START_PTR(s); @@ -458,7 +456,7 @@ static void BM_HpackParserParseHeader(benchmark::State& state) { grpc_chttp2_hpack_parser p; grpc_chttp2_hpack_parser_init(&p); const int kArenaSize = 4096 * 4096; - p.on_header_user_data = gpr_arena_create(kArenaSize); + p.on_header_user_data = grpc_core::Arena::Create(kArenaSize); p.on_header = OnHeader; for (auto slice : init_slices) { GPR_ASSERT(GRPC_ERROR_NONE == grpc_chttp2_hpack_parser_parse(&p, slice)); @@ -470,12 +468,12 @@ static void BM_HpackParserParseHeader(benchmark::State& state) { grpc_core::ExecCtx::Get()->Flush(); // Recreate arena every 4k iterations to avoid oom if (0 == (state.iterations() & 0xfff)) { - gpr_arena_destroy((gpr_arena*)p.on_header_user_data); - p.on_header_user_data = gpr_arena_create(kArenaSize); + static_cast(p.on_header_user_data)->Destroy(); + p.on_header_user_data = grpc_core::Arena::Create(kArenaSize); } } // Clean up - gpr_arena_destroy((gpr_arena*)p.on_header_user_data); + static_cast(p.on_header_user_data)->Destroy(); for (auto slice : init_slices) grpc_slice_unref(slice); for (auto slice : benchmark_slices) grpc_slice_unref(slice); grpc_chttp2_hpack_parser_destroy(&p); @@ -778,7 +776,8 @@ static void free_timeout(void* p) { gpr_free(p); } // Benchmark the current on_initial_header implementation static void OnInitialHeader(void* user_data, grpc_mdelem md) { // Setup for benchmark. This will bloat the absolute values of this benchmark - grpc_chttp2_incoming_metadata_buffer buffer((gpr_arena*)user_data); + grpc_chttp2_incoming_metadata_buffer buffer( + static_cast(user_data)); bool seen_error = false; // Below here is the code we actually care about benchmarking @@ -927,6 +926,7 @@ void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } } // namespace benchmark int main(int argc, char** argv) { + LibraryInitializer libInit; ::benchmark::Initialize(&argc, argv); ::grpc::testing::InitTest(&argc, &argv, false); benchmark::RunTheBenchmarksNamespaced(); diff --git a/test/cpp/microbenchmarks/bm_chttp2_transport.cc b/test/cpp/microbenchmarks/bm_chttp2_transport.cc index baa6da3fbcf..05504584c20 100644 --- a/test/cpp/microbenchmarks/bm_chttp2_transport.cc +++ b/test/cpp/microbenchmarks/bm_chttp2_transport.cc @@ -36,8 +36,6 @@ #include "test/cpp/microbenchmarks/helpers.h" #include "test/cpp/util/test_config.h" -auto& force_library_initialization = Library::get(); - //////////////////////////////////////////////////////////////////////////////// // Helper classes // @@ -57,7 +55,8 @@ class DummyEndpoint : public grpc_endpoint { get_fd, can_track_err}; grpc_endpoint::vtable = &my_vtable; - ru_ = grpc_resource_user_create(Library::get().rq(), "dummy_endpoint"); + ru_ = grpc_resource_user_create(LibraryInitializer::get().rq(), + "dummy_endpoint"); } void PushInput(grpc_slice slice) { @@ -193,13 +192,13 @@ class Stream { Stream(Fixture* f) : f_(f) { stream_size_ = grpc_transport_stream_size(f->transport()); stream_ = gpr_malloc(stream_size_); - arena_ = gpr_arena_create(4096); + arena_ = grpc_core::Arena::Create(4096); } ~Stream() { gpr_event_wait(&done_, gpr_inf_future(GPR_CLOCK_REALTIME)); gpr_free(stream_); - gpr_arena_destroy(arena_); + arena_->Destroy(); } void Init(benchmark::State& state) { @@ -208,8 +207,8 @@ class Stream { gpr_event_init(&done_); memset(stream_, 0, stream_size_); if ((state.iterations() & 0xffff) == 0) { - gpr_arena_destroy(arena_); - arena_ = gpr_arena_create(4096); + arena_->Destroy(); + arena_ = grpc_core::Arena::Create(4096); } grpc_transport_init_stream(f_->transport(), static_cast(stream_), &refcount_, @@ -245,7 +244,7 @@ class Stream { Fixture* f_; grpc_stream_refcount refcount_; - gpr_arena* arena_; + grpc_core::Arena* arena_; size_t stream_size_; void* stream_; grpc_closure* destroy_closure_ = nullptr; @@ -642,6 +641,7 @@ void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } } // namespace benchmark int main(int argc, char** argv) { + LibraryInitializer libInit; ::benchmark::Initialize(&argc, argv); ::grpc::testing::InitTest(&argc, &argv, false); benchmark::RunTheBenchmarksNamespaced(); diff --git a/test/cpp/microbenchmarks/bm_closure.cc b/test/cpp/microbenchmarks/bm_closure.cc index e1f1e92d4d8..84b1c536bf0 100644 --- a/test/cpp/microbenchmarks/bm_closure.cc +++ b/test/cpp/microbenchmarks/bm_closure.cc @@ -30,8 +30,6 @@ #include "test/cpp/microbenchmarks/helpers.h" #include "test/cpp/util/test_config.h" -auto& force_library_initialization = Library::get(); - static void BM_NoOpExecCtx(benchmark::State& state) { TrackCounters track_counters; while (state.KeepRunning()) { @@ -425,6 +423,7 @@ void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } } // namespace benchmark int main(int argc, char** argv) { + LibraryInitializer libInit; ::benchmark::Initialize(&argc, argv); ::grpc::testing::InitTest(&argc, &argv, false); benchmark::RunTheBenchmarksNamespaced(); diff --git a/test/cpp/microbenchmarks/bm_cq.cc b/test/cpp/microbenchmarks/bm_cq.cc index a7cb939265f..50eb9454fbe 100644 --- a/test/cpp/microbenchmarks/bm_cq.cc +++ b/test/cpp/microbenchmarks/bm_cq.cc @@ -32,8 +32,6 @@ namespace grpc { namespace testing { -auto& force_library_initialization = Library::get(); - static void BM_CreateDestroyCpp(benchmark::State& state) { TrackCounters track_counters; while (state.KeepRunning()) { @@ -146,6 +144,66 @@ static void BM_EmptyCore(benchmark::State& state) { } BENCHMARK(BM_EmptyCore); +// Helper for tests to shutdown correctly and tersely +static void shutdown_and_destroy(grpc_completion_queue* cc) { + grpc_completion_queue_shutdown(cc); + grpc_completion_queue_destroy(cc); +} + +// Tag completion queue iterate times +class TagCallback : public grpc_experimental_completion_queue_functor { + public: + explicit TagCallback(int* iter) : iter_(iter) { + functor_run = &TagCallback::Run; + } + ~TagCallback() {} + static void Run(grpc_experimental_completion_queue_functor* cb, int ok) { + GPR_ASSERT(static_cast(ok)); + *static_cast(cb)->iter_ += 1; + }; + + private: + int* iter_; +}; + +// Check if completion queue is shut down +class ShutdownCallback : public grpc_experimental_completion_queue_functor { + public: + explicit ShutdownCallback(bool* done) : done_(done) { + functor_run = &ShutdownCallback::Run; + } + ~ShutdownCallback() {} + static void Run(grpc_experimental_completion_queue_functor* cb, int ok) { + *static_cast(cb)->done_ = static_cast(ok); + } + + private: + bool* done_; +}; + +static void BM_Callback_CQ_Pass1Core(benchmark::State& state) { + TrackCounters track_counters; + int iteration = 0; + TagCallback tag_cb(&iteration); + bool got_shutdown = false; + ShutdownCallback shutdown_cb(&got_shutdown); + grpc_completion_queue* cc = + grpc_completion_queue_create_for_callback(&shutdown_cb, nullptr); + while (state.KeepRunning()) { + grpc_core::ApplicationCallbackExecCtx callback_exec_ctx; + grpc_core::ExecCtx exec_ctx; + grpc_cq_completion completion; + GPR_ASSERT(grpc_cq_begin_op(cc, &tag_cb)); + grpc_cq_end_op(cc, &tag_cb, GRPC_ERROR_NONE, DoneWithCompletionOnStack, + nullptr, &completion); + } + shutdown_and_destroy(cc); + GPR_ASSERT(got_shutdown); + GPR_ASSERT(iteration == static_cast(state.iterations())); + track_counters.Finish(state); +} +BENCHMARK(BM_Callback_CQ_Pass1Core); + } // namespace testing } // namespace grpc @@ -156,6 +214,7 @@ void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } } // namespace benchmark int main(int argc, char** argv) { + LibraryInitializer libInit; ::benchmark::Initialize(&argc, argv); ::grpc::testing::InitTest(&argc, &argv, false); benchmark::RunTheBenchmarksNamespaced(); diff --git a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc index 54455350c24..329eaf2434e 100644 --- a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc +++ b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc @@ -138,7 +138,7 @@ static void teardown() { Setup: The benchmark framework ensures that none of the threads proceed beyond the state.KeepRunning() call unless all the threads have called state.keepRunning - atleast once. So it is safe to do the initialization in one of the threads + at least once. So it is safe to do the initialization in one of the threads before state.KeepRunning() is called. Teardown: diff --git a/test/cpp/microbenchmarks/bm_error.cc b/test/cpp/microbenchmarks/bm_error.cc index ae557a580aa..a71817f7e54 100644 --- a/test/cpp/microbenchmarks/bm_error.cc +++ b/test/cpp/microbenchmarks/bm_error.cc @@ -27,8 +27,6 @@ #include "test/cpp/microbenchmarks/helpers.h" #include "test/cpp/util/test_config.h" -auto& force_library_initialization = Library::get(); - class ErrorDeleter { public: void operator()(grpc_error* error) { GRPC_ERROR_UNREF(error); } @@ -318,6 +316,7 @@ void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } } // namespace benchmark int main(int argc, char** argv) { + LibraryInitializer libInit; ::benchmark::Initialize(&argc, argv); ::grpc::testing::InitTest(&argc, &argv, false); benchmark::RunTheBenchmarksNamespaced(); diff --git a/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc b/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc index 34df77aca3c..60ca9a093ed 100644 --- a/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc +++ b/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc @@ -24,9 +24,6 @@ namespace grpc { namespace testing { -// force library initialization -auto& force_library_initialization = Library::get(); - /******************************************************************************* * CONFIGURATIONS */ @@ -122,6 +119,7 @@ void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } } // namespace benchmark int main(int argc, char** argv) { + LibraryInitializer libInit; ::benchmark::Initialize(&argc, argv); ::grpc::testing::InitTest(&argc, &argv, false); benchmark::RunTheBenchmarksNamespaced(); diff --git a/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc b/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc index da98f3cbcd4..d4533e6c78e 100644 --- a/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc +++ b/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc @@ -28,9 +28,6 @@ namespace testing { * CONFIGURATIONS */ -// force library initialization -auto& force_library_initialization = Library::get(); - BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, TCP) ->Range(0, 128 * 1024 * 1024); BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, UDS) @@ -72,6 +69,7 @@ void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } } // namespace benchmark int main(int argc, char** argv) { + LibraryInitializer libInit; ::benchmark::Initialize(&argc, argv); ::grpc::testing::InitTest(&argc, &argv, false); benchmark::RunTheBenchmarksNamespaced(); diff --git a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc index 1af92d2c80c..2d733bcaa42 100644 --- a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc +++ b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc @@ -214,8 +214,8 @@ class TrickledCHTTP2 : public EndpointPairFixture { static grpc_endpoint_pair MakeEndpoints(size_t kilobits, grpc_passthru_endpoint_stats* stats) { grpc_endpoint_pair p; - grpc_passthru_endpoint_create(&p.client, &p.server, Library::get().rq(), - stats); + grpc_passthru_endpoint_create(&p.client, &p.server, + LibraryInitializer::get().rq(), stats); double bytes_per_second = 125.0 * kilobits; p.client = grpc_trickle_endpoint_create(p.client, bytes_per_second); p.server = grpc_trickle_endpoint_create(p.server, bytes_per_second); @@ -235,9 +235,6 @@ class TrickledCHTTP2 : public EndpointPairFixture { } }; -// force library initialization -auto& force_library_initialization = Library::get(); - static void TrickleCQNext(TrickledCHTTP2* fixture, void** t, bool* ok, int64_t iteration) { while (true) { @@ -465,6 +462,7 @@ void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } } // namespace benchmark int main(int argc, char** argv) { + LibraryInitializer libInit; ::benchmark::Initialize(&argc, argv); ::grpc::testing::InitTest(&argc, &argv, false); grpc_timer_manager_set_threading(false); diff --git a/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc b/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc index d4bd58b9838..3e8f9344021 100644 --- a/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc +++ b/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc @@ -24,9 +24,6 @@ namespace grpc { namespace testing { -// force library initialization -auto& force_library_initialization = Library::get(); - /******************************************************************************* * CONFIGURATIONS */ @@ -174,6 +171,7 @@ void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } } // namespace benchmark int main(int argc, char** argv) { + LibraryInitializer libInit; ::benchmark::Initialize(&argc, argv); ::grpc::testing::InitTest(&argc, &argv, false); benchmark::RunTheBenchmarksNamespaced(); diff --git a/test/cpp/microbenchmarks/bm_metadata.cc b/test/cpp/microbenchmarks/bm_metadata.cc index 553b33c4028..ff8fe541dfc 100644 --- a/test/cpp/microbenchmarks/bm_metadata.cc +++ b/test/cpp/microbenchmarks/bm_metadata.cc @@ -27,8 +27,6 @@ #include "test/cpp/microbenchmarks/helpers.h" #include "test/cpp/util/test_config.h" -auto& force_library_initialization = Library::get(); - static void BM_SliceFromStatic(benchmark::State& state) { TrackCounters track_counters; while (state.KeepRunning()) { @@ -298,6 +296,7 @@ void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } } // namespace benchmark int main(int argc, char** argv) { + LibraryInitializer libInit; ::benchmark::Initialize(&argc, argv); ::grpc::testing::InitTest(&argc, &argv, false); benchmark::RunTheBenchmarksNamespaced(); diff --git a/test/cpp/microbenchmarks/bm_pollset.cc b/test/cpp/microbenchmarks/bm_pollset.cc index 050c7f7c171..f8e36f178e4 100644 --- a/test/cpp/microbenchmarks/bm_pollset.cc +++ b/test/cpp/microbenchmarks/bm_pollset.cc @@ -40,8 +40,6 @@ #include #endif -auto& force_library_initialization = Library::get(); - static void shutdown_ps(void* ps, grpc_error* error) { grpc_pollset_destroy(static_cast(ps)); } @@ -264,6 +262,7 @@ void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } } // namespace benchmark int main(int argc, char** argv) { + LibraryInitializer libInit; ::benchmark::Initialize(&argc, argv); ::grpc::testing::InitTest(&argc, &argv, false); benchmark::RunTheBenchmarksNamespaced(); diff --git a/test/cpp/microbenchmarks/bm_timer.cc b/test/cpp/microbenchmarks/bm_timer.cc index f5a411251b5..53aaead992d 100644 --- a/test/cpp/microbenchmarks/bm_timer.cc +++ b/test/cpp/microbenchmarks/bm_timer.cc @@ -32,8 +32,6 @@ namespace grpc { namespace testing { -auto& force_library_initialization = Library::get(); - struct TimerClosure { grpc_timer timer; grpc_closure closure; @@ -111,6 +109,7 @@ void RunTheBenchmarksNamespaced() { RunSpecifiedBenchmarks(); } } // namespace benchmark int main(int argc, char** argv) { + LibraryInitializer libInit; ::benchmark::Initialize(&argc, argv); ::grpc::testing::InitTest(&argc, &argv, false); benchmark::RunTheBenchmarksNamespaced(); diff --git a/test/cpp/microbenchmarks/callback_streaming_ping_pong.h b/test/cpp/microbenchmarks/callback_streaming_ping_pong.h new file mode 100644 index 00000000000..9fb86bd8299 --- /dev/null +++ b/test/cpp/microbenchmarks/callback_streaming_ping_pong.h @@ -0,0 +1,150 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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 TEST_CPP_MICROBENCHMARKS_CALLBACK_STREAMING_PING_PONG_H +#define TEST_CPP_MICROBENCHMARKS_CALLBACK_STREAMING_PING_PONG_H + +#include +#include +#include "src/core/lib/profiling/timers.h" +#include "src/proto/grpc/testing/echo.grpc.pb.h" +#include "test/cpp/microbenchmarks/callback_test_service.h" +#include "test/cpp/microbenchmarks/fullstack_context_mutators.h" +#include "test/cpp/microbenchmarks/fullstack_fixtures.h" + +namespace grpc { +namespace testing { + +/******************************************************************************* + * BENCHMARKING KERNELS + */ + +class BidiClient + : public grpc::experimental::ClientBidiReactor { + public: + BidiClient(benchmark::State* state, EchoTestService::Stub* stub, + ClientContext* cli_ctx, EchoRequest* request, + EchoResponse* response) + : state_{state}, + stub_{stub}, + cli_ctx_{cli_ctx}, + request_{request}, + response_{response} { + msgs_size_ = state->range(0); + msgs_to_send_ = state->range(1); + StartNewRpc(); + } + + void OnReadDone(bool ok) override { + if (!ok) { + gpr_log(GPR_ERROR, "Client read failed"); + return; + } + MaybeWrite(); + } + + void OnWriteDone(bool ok) override { + if (!ok) { + gpr_log(GPR_ERROR, "Client write failed"); + return; + } + writes_complete_++; + StartRead(response_); + } + + void OnDone(const Status& s) override { + GPR_ASSERT(s.ok()); + GPR_ASSERT(writes_complete_ == msgs_to_send_); + if (state_->KeepRunning()) { + writes_complete_ = 0; + StartNewRpc(); + } else { + std::unique_lock l(mu); + done = true; + cv.notify_one(); + } + } + + void StartNewRpc() { + cli_ctx_->~ClientContext(); + new (cli_ctx_) ClientContext(); + cli_ctx_->AddMetadata(kServerMessageSize, grpc::to_string(msgs_size_)); + stub_->experimental_async()->BidiStream(cli_ctx_, this); + MaybeWrite(); + StartCall(); + } + + void Await() { + std::unique_lock l(mu); + while (!done) { + cv.wait(l); + } + } + + private: + void MaybeWrite() { + if (writes_complete_ < msgs_to_send_) { + StartWrite(request_); + } else { + StartWritesDone(); + } + } + + benchmark::State* state_; + EchoTestService::Stub* stub_; + ClientContext* cli_ctx_; + EchoRequest* request_; + EchoResponse* response_; + int writes_complete_{0}; + int msgs_to_send_; + int msgs_size_; + std::mutex mu; + std::condition_variable cv; + bool done; +}; + +template +static void BM_CallbackBidiStreaming(benchmark::State& state) { + int message_size = state.range(0); + int max_ping_pongs = state.range(1); + CallbackStreamingTestService service; + std::unique_ptr fixture(new Fixture(&service)); + std::unique_ptr stub_( + EchoTestService::NewStub(fixture->channel())); + EchoRequest request; + EchoResponse response; + ClientContext cli_ctx; + if (message_size > 0) { + request.set_message(std::string(message_size, 'a')); + } else { + request.set_message(""); + } + if (state.KeepRunning()) { + GPR_TIMER_SCOPE("BenchmarkCycle", 0); + BidiClient test{&state, stub_.get(), &cli_ctx, &request, &response}; + test.Await(); + } + fixture->Finish(state); + fixture.reset(); + state.SetBytesProcessed(2 * message_size * max_ping_pongs * + state.iterations()); +} + +} // namespace testing +} // namespace grpc +#endif // TEST_CPP_MICROBENCHMARKS_CALLBACK_STREAMING_PING_PONG_H diff --git a/test/cpp/microbenchmarks/callback_test_service.cc b/test/cpp/microbenchmarks/callback_test_service.cc new file mode 100644 index 00000000000..321a5b39184 --- /dev/null +++ b/test/cpp/microbenchmarks/callback_test_service.cc @@ -0,0 +1,112 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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 "test/cpp/microbenchmarks/callback_test_service.h" + +namespace grpc { +namespace testing { +namespace { + +grpc::string ToString(const grpc::string_ref& r) { + return grpc::string(r.data(), r.size()); +} + +int GetIntValueFromMetadataHelper( + const char* key, + const std::multimap& metadata, + int default_value) { + if (metadata.find(key) != metadata.end()) { + std::istringstream iss(ToString(metadata.find(key)->second)); + iss >> default_value; + } + + return default_value; +} + +int GetIntValueFromMetadata( + const char* key, + const std::multimap& metadata, + int default_value) { + return GetIntValueFromMetadataHelper(key, metadata, default_value); +} +} // namespace + +void CallbackStreamingTestService::Echo( + ServerContext* context, const EchoRequest* request, EchoResponse* response, + experimental::ServerCallbackRpcController* controller) { + int response_msgs_size = GetIntValueFromMetadata( + kServerMessageSize, context->client_metadata(), 0); + if (response_msgs_size > 0) { + response->set_message(std::string(response_msgs_size, 'a')); + } else { + response->set_message(""); + } + controller->Finish(Status::OK); +} + +experimental::ServerBidiReactor* +CallbackStreamingTestService::BidiStream() { + class Reactor + : public experimental::ServerBidiReactor { + public: + Reactor() {} + void OnStarted(ServerContext* context) override { + ctx_ = context; + message_size_ = GetIntValueFromMetadata(kServerMessageSize, + context->client_metadata(), 0); + StartRead(&request_); + } + void OnDone() override { + GPR_ASSERT(finished_); + delete this; + } + void OnCancel() override {} + void OnReadDone(bool ok) override { + if (!ok) { + // Stream is over + Finish(::grpc::Status::OK); + finished_ = true; + return; + } + if (message_size_ > 0) { + response_.set_message(std::string(message_size_, 'a')); + } else { + response_.set_message(""); + } + StartWrite(&response_); + } + void OnWriteDone(bool ok) override { + if (!ok) { + gpr_log(GPR_ERROR, "Server write failed"); + return; + } + StartRead(&request_); + } + + private: + ServerContext* ctx_; + EchoRequest request_; + EchoResponse response_; + int message_size_; + bool finished_{false}; + }; + + return new Reactor; +} +} // namespace testing +} // namespace grpc diff --git a/test/cpp/microbenchmarks/callback_test_service.h b/test/cpp/microbenchmarks/callback_test_service.h new file mode 100644 index 00000000000..97188595382 --- /dev/null +++ b/test/cpp/microbenchmarks/callback_test_service.h @@ -0,0 +1,48 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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 TEST_CPP_MICROBENCHMARKS_CALLBACK_TEST_SERVICE_H +#define TEST_CPP_MICROBENCHMARKS_CALLBACK_TEST_SERVICE_H + +#include +#include +#include +#include +#include +#include "src/proto/grpc/testing/echo.grpc.pb.h" +#include "test/cpp/util/string_ref_helper.h" + +namespace grpc { +namespace testing { + +const char* const kServerMessageSize = "server_message_size"; + +class CallbackStreamingTestService + : public EchoTestService::ExperimentalCallbackService { + public: + CallbackStreamingTestService() {} + void Echo(ServerContext* context, const EchoRequest* request, + EchoResponse* response, + experimental::ServerCallbackRpcController* controller) override; + + experimental::ServerBidiReactor* BidiStream() + override; +}; +} // namespace testing +} // namespace grpc +#endif // TEST_CPP_MICROBENCHMARKS_CALLBACK_TEST_SERVICE_H diff --git a/test/cpp/microbenchmarks/callback_unary_ping_pong.h b/test/cpp/microbenchmarks/callback_unary_ping_pong.h new file mode 100644 index 00000000000..359b91eb6fe --- /dev/null +++ b/test/cpp/microbenchmarks/callback_unary_ping_pong.h @@ -0,0 +1,101 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * 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. + * + */ + +/* Benchmark gRPC end2end in various configurations */ + +#ifndef TEST_CPP_MICROBENCHMARKS_CALLBACK_UNARY_PING_PONG_H +#define TEST_CPP_MICROBENCHMARKS_CALLBACK_UNARY_PING_PONG_H + +#include +#include +#include "src/core/lib/profiling/timers.h" +#include "src/proto/grpc/testing/echo.grpc.pb.h" +#include "test/cpp/microbenchmarks/callback_test_service.h" +#include "test/cpp/microbenchmarks/fullstack_context_mutators.h" +#include "test/cpp/microbenchmarks/fullstack_fixtures.h" + +namespace grpc { +namespace testing { + +/******************************************************************************* + * BENCHMARKING KERNELS + */ + +void SendCallbackUnaryPingPong(benchmark::State* state, ClientContext* cli_ctx, + EchoRequest* request, EchoResponse* response, + EchoTestService::Stub* stub_, bool* done, + std::mutex* mu, std::condition_variable* cv) { + int response_msgs_size = state->range(1); + cli_ctx->AddMetadata(kServerMessageSize, grpc::to_string(response_msgs_size)); + stub_->experimental_async()->Echo( + cli_ctx, request, response, + [state, cli_ctx, request, response, stub_, done, mu, cv](Status s) { + GPR_ASSERT(s.ok()); + if (state->KeepRunning()) { + cli_ctx->~ClientContext(); + new (cli_ctx) ClientContext(); + SendCallbackUnaryPingPong(state, cli_ctx, request, response, stub_, + done, mu, cv); + } else { + std::lock_guard l(*mu); + *done = true; + cv->notify_one(); + } + }); +}; + +template +static void BM_CallbackUnaryPingPong(benchmark::State& state) { + int request_msgs_size = state.range(0); + int response_msgs_size = state.range(1); + CallbackStreamingTestService service; + std::unique_ptr fixture(new Fixture(&service)); + std::unique_ptr stub_( + EchoTestService::NewStub(fixture->channel())); + EchoRequest request; + EchoResponse response; + ClientContext cli_ctx; + + if (request_msgs_size > 0) { + request.set_message(std::string(request_msgs_size, 'a')); + } else { + request.set_message(""); + } + + std::mutex mu; + std::condition_variable cv; + bool done = false; + if (state.KeepRunning()) { + GPR_TIMER_SCOPE("BenchmarkCycle", 0); + SendCallbackUnaryPingPong(&state, &cli_ctx, &request, &response, + stub_.get(), &done, &mu, &cv); + } + std::unique_lock l(mu); + while (!done) { + cv.wait(l); + } + fixture->Finish(state); + fixture.reset(); + state.SetBytesProcessed(request_msgs_size * state.iterations() + + response_msgs_size * state.iterations()); +} + +} // namespace testing +} // namespace grpc + +#endif // TEST_CPP_MICROBENCHMARKS_FULLSTACK_UNARY_PING_PONG_H diff --git a/test/cpp/microbenchmarks/fullstack_fixtures.h b/test/cpp/microbenchmarks/fullstack_fixtures.h index 6bbf553bbd8..4d60e97d5f6 100644 --- a/test/cpp/microbenchmarks/fullstack_fixtures.h +++ b/test/cpp/microbenchmarks/fullstack_fixtures.h @@ -86,8 +86,8 @@ class FullstackFixture : public BaseFixture { ChannelArguments args; config.ApplyCommonChannelArguments(&args); if (address.length() > 0) { - channel_ = - CreateCustomChannel(address, InsecureChannelCredentials(), args); + channel_ = ::grpc::CreateCustomChannel( + address, InsecureChannelCredentials(), args); } else { channel_ = server_->InProcessChannel(args); } @@ -218,7 +218,7 @@ class EndpointPairFixture : public BaseFixture { "target", &c_args, GRPC_CLIENT_DIRECT_CHANNEL, client_transport_); grpc_chttp2_transport_start_reading(client_transport_, nullptr, nullptr); - channel_ = CreateChannelInternal( + channel_ = ::grpc::CreateChannelInternal( "", channel, std::vector>()); @@ -299,8 +299,8 @@ class InProcessCHTTP2WithExplicitStats : public EndpointPairFixture { static grpc_endpoint_pair MakeEndpoints(grpc_passthru_endpoint_stats* stats) { grpc_endpoint_pair p; - grpc_passthru_endpoint_create(&p.client, &p.server, Library::get().rq(), - stats); + grpc_passthru_endpoint_create(&p.client, &p.server, + LibraryInitializer::get().rq(), stats); return p; } }; diff --git a/test/cpp/microbenchmarks/helpers.cc b/test/cpp/microbenchmarks/helpers.cc index d4070de7481..7d78e21aef7 100644 --- a/test/cpp/microbenchmarks/helpers.cc +++ b/test/cpp/microbenchmarks/helpers.cc @@ -21,8 +21,12 @@ #include "test/cpp/microbenchmarks/helpers.h" static grpc::internal::GrpcLibraryInitializer g_gli_initializer; +static LibraryInitializer* g_libraryInitializer; + +LibraryInitializer::LibraryInitializer() { + GPR_ASSERT(g_libraryInitializer == nullptr); + g_libraryInitializer = this; -Library::Library() { g_gli_initializer.summon(); #ifdef GPR_LOW_LEVEL_COUNTERS grpc_memory_counters_init(); @@ -31,6 +35,17 @@ Library::Library() { rq_ = grpc_resource_quota_create("bm"); } +LibraryInitializer::~LibraryInitializer() { + g_libraryInitializer = nullptr; + init_lib_.shutdown(); + grpc_resource_quota_unref(rq_); +} + +LibraryInitializer& LibraryInitializer::get() { + GPR_ASSERT(g_libraryInitializer != nullptr); + return *g_libraryInitializer; +} + void TrackCounters::Finish(benchmark::State& state) { std::ostringstream out; for (const auto& l : labels_) { diff --git a/test/cpp/microbenchmarks/helpers.h b/test/cpp/microbenchmarks/helpers.h index 770966aa189..b712c85d354 100644 --- a/test/cpp/microbenchmarks/helpers.h +++ b/test/cpp/microbenchmarks/helpers.h @@ -29,20 +29,16 @@ #include #include -class Library { +class LibraryInitializer { public: - static Library& get() { - static Library lib; - return lib; - } + LibraryInitializer(); + ~LibraryInitializer(); grpc_resource_quota* rq() { return rq_; } - private: - Library(); - - ~Library() { init_lib_.shutdown(); } + static LibraryInitializer& get(); + private: grpc::internal::GrpcLibrary init_lib_; grpc_resource_quota* rq_; }; diff --git a/test/cpp/naming/BUILD b/test/cpp/naming/BUILD index 58e70480acf..7db435a3fd4 100644 --- a/test/cpp/naming/BUILD +++ b/test/cpp/naming/BUILD @@ -22,7 +22,7 @@ package( licenses(["notice"]) # Apache v2 -load("//bazel:grpc_build_system.bzl", "grpc_py_binary", "grpc_cc_test") +load("//bazel:grpc_build_system.bzl", "grpc_py_binary", "grpc_cc_test", "grpc_cc_library") load(":generate_resolver_component_tests.bzl", "generate_resolver_component_tests") # Meant to be invoked only through the top-level shell script driver. @@ -39,6 +39,7 @@ grpc_cc_test( srcs = ["cancel_ares_query_test.cc"], external_deps = ["gmock"], deps = [ + ":dns_test_util", "//:gpr", "//:grpc", "//:grpc++", @@ -49,4 +50,14 @@ grpc_cc_test( ], ) +grpc_cc_library( + name = "dns_test_util", + hdrs = ["dns_test_util.h"], + srcs = ["dns_test_util.cc"], + deps = [ + "//:gpr", + "//:grpc", + ], +) + generate_resolver_component_tests() diff --git a/test/cpp/naming/address_sorting_test.cc b/test/cpp/naming/address_sorting_test.cc index bd685632c33..affc75bc634 100644 --- a/test/cpp/naming/address_sorting_test.cc +++ b/test/cpp/naming/address_sorting_test.cc @@ -36,10 +36,10 @@ #include "src/core/ext/filters/client_channel/client_channel.h" #include "src/core/ext/filters/client_channel/resolver.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" +#include "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" #include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/iomgr/combiner.h" @@ -829,13 +829,13 @@ TEST_F(AddressSortingTest, TestSorterKnowsIpv6LoopbackIsAvailable) { } // namespace int main(int argc, char** argv) { - char* resolver = gpr_getenv("GRPC_DNS_RESOLVER"); - if (resolver == nullptr || strlen(resolver) == 0) { - gpr_setenv("GRPC_DNS_RESOLVER", "ares"); - } else if (strcmp("ares", resolver)) { - gpr_log(GPR_INFO, "GRPC_DNS_RESOLVER != ares: %s.", resolver); + grpc_core::UniquePtr resolver = + GPR_GLOBAL_CONFIG_GET(grpc_dns_resolver); + if (strlen(resolver.get()) == 0) { + GPR_GLOBAL_CONFIG_SET(grpc_dns_resolver, "ares"); + } else if (strcmp("ares", resolver.get())) { + gpr_log(GPR_INFO, "GRPC_DNS_RESOLVER != ares: %s.", resolver.get()); } - gpr_free(resolver); grpc::testing::TestEnvironment env(argc, argv); ::testing::InitGoogleTest(&argc, argv); auto result = RUN_ALL_TESTS(); diff --git a/test/cpp/naming/cancel_ares_query_test.cc b/test/cpp/naming/cancel_ares_query_test.cc index bcf96aa1dc5..667011ae291 100644 --- a/test/cpp/naming/cancel_ares_query_test.cc +++ b/test/cpp/naming/cancel_ares_query_test.cc @@ -29,10 +29,10 @@ #include #include "include/grpc/support/string_util.h" #include "src/core/ext/filters/client_channel/resolver.h" +#include "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/debug/stats.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gprpp/orphanable.h" @@ -44,6 +44,7 @@ #include "test/core/util/cmdline.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" +#include "test/cpp/naming/dns_test_util.h" #ifdef GPR_WINDOWS #include "src/core/lib/iomgr/sockaddr_windows.h" @@ -76,36 +77,6 @@ void EndTest(grpc_channel* client, grpc_completion_queue* cq) { grpc_completion_queue_destroy(cq); } -class FakeNonResponsiveDNSServer { - public: - FakeNonResponsiveDNSServer(int port) { - socket_ = socket(AF_INET6, SOCK_DGRAM, 0); - if (socket_ == BAD_SOCKET_RETURN_VAL) { - gpr_log(GPR_DEBUG, "Failed to create UDP ipv6 socket"); - abort(); - } - sockaddr_in6 addr; - memset(&addr, 0, sizeof(addr)); - addr.sin6_family = AF_INET6; - addr.sin6_port = htons(port); - ((char*)&addr.sin6_addr)[15] = 1; - if (bind(socket_, (const sockaddr*)&addr, sizeof(addr)) != 0) { - gpr_log(GPR_DEBUG, "Failed to bind UDP ipv6 socket to [::1]:%d", port); - abort(); - } - } - ~FakeNonResponsiveDNSServer() { -#ifdef GPR_WINDOWS - closesocket(socket_); -#else - close(socket_); -#endif - } - - private: - int socket_; -}; - struct ArgsStruct { gpr_atm done_atm; gpr_mu* mu; @@ -184,7 +155,7 @@ class AssertFailureResultHandler : public grpc_core::Resolver::ResultHandler { void TestCancelActiveDNSQuery(ArgsStruct* args) { int fake_dns_port = grpc_pick_unused_port_or_die(); - FakeNonResponsiveDNSServer fake_dns_server(fake_dns_port); + grpc::testing::FakeNonResponsiveDNSServer fake_dns_server(fake_dns_port); char* client_target; GPR_ASSERT(gpr_asprintf( &client_target, @@ -282,7 +253,7 @@ void TestCancelDuringActiveQuery( cancellation_test_query_timeout_setting query_timeout_setting) { // Start up fake non responsive DNS server int fake_dns_port = grpc_pick_unused_port_or_die(); - FakeNonResponsiveDNSServer fake_dns_server(fake_dns_port); + grpc::testing::FakeNonResponsiveDNSServer fake_dns_server(fake_dns_port); // Create a call that will try to use the fake DNS server char* client_target = nullptr; GPR_ASSERT(gpr_asprintf( @@ -403,7 +374,7 @@ TEST( int main(int argc, char** argv) { grpc::testing::TestEnvironment env(argc, argv); ::testing::InitGoogleTest(&argc, argv); - gpr_setenv("GRPC_DNS_RESOLVER", "ares"); + GPR_GLOBAL_CONFIG_SET(grpc_dns_resolver, "ares"); // Sanity check the time that it takes to run the test // including the teardown time (the teardown // part of the test involves cancelling the DNS query, diff --git a/test/cpp/naming/dns_test_util.cc b/test/cpp/naming/dns_test_util.cc new file mode 100644 index 00000000000..1380d0ab423 --- /dev/null +++ b/test/cpp/naming/dns_test_util.cc @@ -0,0 +1,97 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * 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 +#include + +#include +#include + +#include "test/cpp/naming/dns_test_util.h" + +#ifdef GPR_WINDOWS +#include "src/core/lib/iomgr/sockaddr_windows.h" +#include "src/core/lib/iomgr/socket_windows.h" +#define BAD_SOCKET_RETURN_VAL INVALID_SOCKET +#else +#include "src/core/lib/iomgr/sockaddr_posix.h" +#define BAD_SOCKET_RETURN_VAL -1 +#endif + +namespace grpc { +namespace testing { + +FakeNonResponsiveDNSServer::FakeNonResponsiveDNSServer(int port) { + udp_socket_ = socket(AF_INET6, SOCK_DGRAM, 0); + tcp_socket_ = socket(AF_INET6, SOCK_STREAM, 0); + if (udp_socket_ == BAD_SOCKET_RETURN_VAL) { + gpr_log(GPR_DEBUG, "Failed to create UDP ipv6 socket"); + abort(); + } + if (tcp_socket_ == BAD_SOCKET_RETURN_VAL) { + gpr_log(GPR_DEBUG, "Failed to create TCP ipv6 socket"); + abort(); + } + sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(port); + ((char*)&addr.sin6_addr)[15] = 1; + if (bind(udp_socket_, (const sockaddr*)&addr, sizeof(addr)) != 0) { + gpr_log(GPR_DEBUG, "Failed to bind UDP ipv6 socket to [::1]:%d", port); + abort(); + } +#ifdef GPR_WINDOWS + char val = 1; + if (setsockopt(tcp_socket_, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) == + SOCKET_ERROR) { + gpr_log(GPR_DEBUG, + "Failed to set SO_REUSEADDR on TCP ipv6 socket to [::1]:%d", port); + abort(); + } +#else + int val = 1; + if (setsockopt(tcp_socket_, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) != + 0) { + gpr_log(GPR_DEBUG, + "Failed to set SO_REUSEADDR on TCP ipv6 socket to [::1]:%d", port); + abort(); + } +#endif + if (bind(tcp_socket_, (const sockaddr*)&addr, sizeof(addr)) != 0) { + gpr_log(GPR_DEBUG, "Failed to bind TCP ipv6 socket to [::1]:%d", port); + abort(); + } + if (listen(tcp_socket_, 100)) { + gpr_log(GPR_DEBUG, "Failed to listen on TCP ipv6 socket to [::1]:%d", port); + abort(); + } +} + +FakeNonResponsiveDNSServer::~FakeNonResponsiveDNSServer() { +#ifdef GPR_WINDOWS + closesocket(udp_socket_); + closesocket(tcp_socket_); +#else + close(udp_socket_); + close(tcp_socket_); +#endif +} + +} // namespace testing +} // namespace grpc diff --git a/test/cpp/naming/dns_test_util.h b/test/cpp/naming/dns_test_util.h new file mode 100644 index 00000000000..d5e50992672 --- /dev/null +++ b/test/cpp/naming/dns_test_util.h @@ -0,0 +1,38 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * 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_DNS_TEST_UTIL_H +#define GRPC_DNS_TEST_UTIL_H + +namespace grpc { +namespace testing { + +class FakeNonResponsiveDNSServer { + public: + explicit FakeNonResponsiveDNSServer(int port); + virtual ~FakeNonResponsiveDNSServer(); + + private: + int udp_socket_; + int tcp_socket_; +}; + +} // namespace testing +} // namespace grpc + +#endif /* GRPC_DNS_TEST_UTIL_H */ diff --git a/test/cpp/naming/gen_build_yaml.py b/test/cpp/naming/gen_build_yaml.py index 9bf5ae9b2f8..7cbf9163700 100755 --- a/test/cpp/naming/gen_build_yaml.py +++ b/test/cpp/naming/gen_build_yaml.py @@ -47,9 +47,11 @@ def _resolver_test_cases(resolver_component_data): _build_expected_addrs_cmd_arg(test_case['expected_addrs'])), ('expected_chosen_service_config', (test_case['expected_chosen_service_config'] or '')), + ('expected_service_config_error', (test_case['expected_service_config_error'] or '')), ('expected_lb_policy', (test_case['expected_lb_policy'] or '')), ('enable_srv_queries', test_case['enable_srv_queries']), ('enable_txt_queries', test_case['enable_txt_queries']), + ('inject_broken_nameserver_list', test_case['inject_broken_nameserver_list']), ], }) return out @@ -72,6 +74,7 @@ def main(): 'src': ['test/cpp/naming/resolver_component_test.cc'], 'platforms': ['linux', 'posix', 'mac', 'windows'], 'deps': [ + 'dns_test_util', 'grpc++_test_util' + unsecure_build_config_suffix, 'grpc_test_util' + unsecure_build_config_suffix, 'grpc++' + unsecure_build_config_suffix, @@ -130,6 +133,7 @@ def main(): 'src': ['test/cpp/naming/cancel_ares_query_test.cc'], 'platforms': ['linux', 'posix', 'mac', 'windows'], 'deps': [ + 'dns_test_util', 'grpc++_test_util', 'grpc_test_util', 'grpc++', diff --git a/test/cpp/naming/generate_resolver_component_tests.bzl b/test/cpp/naming/generate_resolver_component_tests.bzl index 589176762e6..bcc62f62871 100755 --- a/test/cpp/naming/generate_resolver_component_tests.bzl +++ b/test/cpp/naming/generate_resolver_component_tests.bzl @@ -46,6 +46,7 @@ def generate_resolver_component_tests(): "gmock", ], deps = [ + ":dns_test_util", "//test/cpp/util:test_util%s" % unsecure_build_config_suffix, "//test/core/util:grpc_test_util%s" % unsecure_build_config_suffix, "//:grpc++%s" % unsecure_build_config_suffix, diff --git a/test/cpp/naming/resolver_component_test.cc b/test/cpp/naming/resolver_component_test.cc index 398822d18a4..6cea8143907 100644 --- a/test/cpp/naming/resolver_component_test.cc +++ b/test/cpp/naming/resolver_component_test.cc @@ -39,12 +39,13 @@ #include "test/cpp/util/test_config.h" #include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/ext/filters/client_channel/parse_address.h" #include "src/core/ext/filters/client_channel/resolver.h" +#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h" #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/ext/filters/client_channel/resolver_registry.h" #include "src/core/ext/filters/client_channel/server_address.h" #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gprpp/orphanable.h" @@ -53,9 +54,12 @@ #include "src/core/lib/iomgr/iomgr.h" #include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/iomgr/sockaddr_utils.h" +#include "src/core/lib/iomgr/socket_utils.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" +#include "test/cpp/naming/dns_test_util.h" + // TODO: pull in different headers when enabling this // test on windows. Also set BAD_SOCKET_RETURN_VAL // to INVALID_SOCKET on windows. @@ -89,6 +93,8 @@ DEFINE_string(expected_addrs, "", DEFINE_string(expected_chosen_service_config, "", "Expected service config json string that gets chosen (no " "whitespace). Empty for none."); +DEFINE_string(expected_service_config_error, "", + "Expected service config error. Empty for none."); DEFINE_string( local_dns_server_address, "", "Optional. This address is placed as the uri authority if present."); @@ -106,6 +112,17 @@ DEFINE_string( "generate " "the python script runner doesn't allow us to pass a gflags bool to this " "binary."); +DEFINE_string( + inject_broken_nameserver_list, "", + "Whether or not to configure c-ares to use a broken nameserver list, in " + "which " + "the first nameserver in the list is non-responsive, but the second one " + "works, i.e " + "serves the expected DNS records; using for testing such a real scenario." + "It would be better if this arg could be bool, but the way that we " + "generate " + "the python script runner doesn't allow us to pass a gflags bool to this " + "binary."); DEFINE_string(expected_lb_policy, "", "Expected lb policy name that appears in resolver result channel " "arg. Empty for none."); @@ -146,8 +163,9 @@ vector ParseExpectedAddrs(std::string expected_addrs) { expected_addrs = expected_addrs.substr(next_comma + 1, std::string::npos); // get the next is_balancer 'bool' associated with this address size_t next_semicolon = expected_addrs.find(';'); - bool is_balancer = - gpr_is_true(expected_addrs.substr(0, next_semicolon).c_str()); + bool is_balancer = false; + gpr_parse_bool_value(expected_addrs.substr(0, next_semicolon).c_str(), + &is_balancer); out.emplace_back(GrpcLBAddress(next_addr, is_balancer)); if (next_semicolon == std::string::npos) { break; @@ -178,6 +196,7 @@ struct ArgsStruct { grpc_channel_args* channel_args; vector expected_addrs; std::string expected_service_config_string; + std::string expected_service_config_error; std::string expected_lb_policy; }; @@ -216,7 +235,10 @@ gpr_timespec NSecondDeadline(int seconds) { } void PollPollsetUntilRequestDone(ArgsStruct* args) { - gpr_timespec deadline = NSecondDeadline(10); + // Use a 20-second timeout to give room for the tests that involve + // a non-responsive name server (c-ares uses a ~5 second query timeout + // for that server before succeeding with the healthy one). + gpr_timespec deadline = NSecondDeadline(20); while (true) { bool done = gpr_atm_acq_load(&args->done_atm) != 0; if (done) { @@ -240,13 +262,19 @@ void PollPollsetUntilRequestDone(ArgsStruct* args) { } void CheckServiceConfigResultLocked(const char* service_config_json, + grpc_error* service_config_error, ArgsStruct* args) { if (args->expected_service_config_string != "") { GPR_ASSERT(service_config_json != nullptr); EXPECT_EQ(service_config_json, args->expected_service_config_string); + } + if (args->expected_service_config_error == "") { + EXPECT_EQ(service_config_error, GRPC_ERROR_NONE); } else { - GPR_ASSERT(service_config_json == nullptr); + EXPECT_THAT(grpc_error_string(service_config_error), + testing::HasSubstr(args->expected_service_config_error)); } + GRPC_ERROR_UNREF(service_config_error); } void CheckLBPolicyResultLocked(const grpc_channel_args* channel_args, @@ -461,13 +489,58 @@ class CheckingResultHandler : public ResultHandler { result.service_config == nullptr ? nullptr : result.service_config->service_config_json(); - CheckServiceConfigResultLocked(service_config_json, args); + CheckServiceConfigResultLocked( + service_config_json, GRPC_ERROR_REF(result.service_config_error), args); if (args->expected_service_config_string == "") { CheckLBPolicyResultLocked(result.args, args); } } }; +int g_fake_non_responsive_dns_server_port = -1; + +/* This function will configure any ares_channel created by the c-ares based + * resolver. This is useful to effectively mock /etc/resolv.conf settings + * (and equivalent on Windows), which unit tests don't have write permissions. + */ +void InjectBrokenNameServerList(ares_channel channel) { + struct ares_addr_port_node dns_server_addrs[2]; + memset(dns_server_addrs, 0, sizeof(dns_server_addrs)); + char* unused_host; + char* local_dns_server_port; + GPR_ASSERT(gpr_split_host_port(FLAGS_local_dns_server_address.c_str(), + &unused_host, &local_dns_server_port)); + gpr_log(GPR_DEBUG, + "Injecting broken nameserver list. Bad server address:|[::1]:%d|. " + "Good server address:%s", + g_fake_non_responsive_dns_server_port, + FLAGS_local_dns_server_address.c_str()); + // Put the non-responsive DNS server at the front of c-ares's nameserver list. + dns_server_addrs[0].family = AF_INET6; + ((char*)&dns_server_addrs[0].addr.addr6)[15] = 0x1; + dns_server_addrs[0].tcp_port = g_fake_non_responsive_dns_server_port; + dns_server_addrs[0].udp_port = g_fake_non_responsive_dns_server_port; + dns_server_addrs[0].next = &dns_server_addrs[1]; + // Put the actual healthy DNS server after the first one. The expectation is + // that the resolver will timeout the query to the non-responsive DNS server + // and will skip over to this healthy DNS server, without causing any DNS + // resolution errors. + dns_server_addrs[1].family = AF_INET; + ((char*)&dns_server_addrs[1].addr.addr4)[0] = 0x7f; + ((char*)&dns_server_addrs[1].addr.addr4)[3] = 0x1; + dns_server_addrs[1].tcp_port = atoi(local_dns_server_port); + dns_server_addrs[1].udp_port = atoi(local_dns_server_port); + dns_server_addrs[1].next = nullptr; + GPR_ASSERT(ares_set_servers_ports(channel, dns_server_addrs) == ARES_SUCCESS); + gpr_free(local_dns_server_port); + gpr_free(unused_host); +} + +void StartResolvingLocked(void* arg, grpc_error* unused) { + grpc_core::Resolver* r = static_cast(arg); + r->StartLocked(); +} + void RunResolvesRelevantRecordsTest( grpc_core::UniquePtr ( *CreateResultHandler)(ArgsStruct* args)) { @@ -476,12 +549,33 @@ void RunResolvesRelevantRecordsTest( ArgsInit(&args); args.expected_addrs = ParseExpectedAddrs(FLAGS_expected_addrs); args.expected_service_config_string = FLAGS_expected_chosen_service_config; + args.expected_service_config_error = FLAGS_expected_service_config_error; args.expected_lb_policy = FLAGS_expected_lb_policy; // maybe build the address with an authority char* whole_uri = nullptr; - GPR_ASSERT(gpr_asprintf(&whole_uri, "dns://%s/%s", - FLAGS_local_dns_server_address.c_str(), - FLAGS_target_name.c_str())); + gpr_log(GPR_DEBUG, + "resolver_component_test: --inject_broken_nameserver_list: %s", + FLAGS_inject_broken_nameserver_list.c_str()); + grpc_core::UniquePtr + fake_non_responsive_dns_server; + if (FLAGS_inject_broken_nameserver_list == "True") { + g_fake_non_responsive_dns_server_port = grpc_pick_unused_port_or_die(); + fake_non_responsive_dns_server.reset( + grpc_core::New( + g_fake_non_responsive_dns_server_port)); + grpc_ares_test_only_inject_config = InjectBrokenNameServerList; + GPR_ASSERT( + gpr_asprintf(&whole_uri, "dns:///%s", FLAGS_target_name.c_str())); + } else if (FLAGS_inject_broken_nameserver_list == "False") { + gpr_log(GPR_INFO, "Specifying authority in uris to: %s", + FLAGS_local_dns_server_address.c_str()); + GPR_ASSERT(gpr_asprintf(&whole_uri, "dns://%s/%s", + FLAGS_local_dns_server_address.c_str(), + FLAGS_target_name.c_str())); + } else { + gpr_log(GPR_DEBUG, "Invalid value for --inject_broken_nameserver_list."); + abort(); + } gpr_log(GPR_DEBUG, "resolver_component_test: --enable_srv_queries: %s", FLAGS_enable_srv_queries.c_str()); grpc_channel_args* resolver_args = nullptr; @@ -524,7 +618,9 @@ void RunResolvesRelevantRecordsTest( CreateResultHandler(&args)); grpc_channel_args_destroy(resolver_args); gpr_free(whole_uri); - resolver->StartLocked(); + GRPC_CLOSURE_SCHED(GRPC_CLOSURE_CREATE(StartResolvingLocked, resolver.get(), + grpc_combiner_scheduler(args.lock)), + GRPC_ERROR_NONE); grpc_core::ExecCtx::Get()->Flush(); PollPollsetUntilRequestDone(&args); ArgsFinish(&args); @@ -554,15 +650,11 @@ int main(int argc, char** argv) { grpc_init(); grpc::testing::TestEnvironment env(argc, argv); ::testing::InitGoogleTest(&argc, argv); - ParseCommandLineFlags(&argc, &argv, true); + grpc::testing::InitTest(&argc, &argv, true); if (FLAGS_target_name == "") { gpr_log(GPR_ERROR, "Missing target_name param."); abort(); } - if (FLAGS_local_dns_server_address != "") { - gpr_log(GPR_INFO, "Specifying authority in uris to: %s", - FLAGS_local_dns_server_address.c_str()); - } auto result = RUN_ALL_TESTS(); grpc_shutdown(); return result; diff --git a/test/cpp/naming/resolver_component_tests_runner.py b/test/cpp/naming/resolver_component_tests_runner.py index a0eda79ec62..e767e4cb5b8 100755 --- a/test/cpp/naming/resolver_component_tests_runner.py +++ b/test/cpp/naming/resolver_component_tests_runner.py @@ -124,9 +124,11 @@ current_test_subprocess = subprocess.Popen([ '--target_name', 'no-srv-ipv4-single-target.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '5.5.5.5:443,False', '--expected_chosen_service_config', '', + '--expected_service_config_error', '', '--expected_lb_policy', '', '--enable_srv_queries', 'True', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -138,9 +140,11 @@ current_test_subprocess = subprocess.Popen([ '--target_name', 'srv-ipv4-single-target.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '1.2.3.4:1234,True', '--expected_chosen_service_config', '', + '--expected_service_config_error', '', '--expected_lb_policy', '', '--enable_srv_queries', 'True', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -152,9 +156,11 @@ current_test_subprocess = subprocess.Popen([ '--target_name', 'srv-ipv4-multi-target.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '1.2.3.5:1234,True;1.2.3.6:1234,True;1.2.3.7:1234,True', '--expected_chosen_service_config', '', + '--expected_service_config_error', '', '--expected_lb_policy', '', '--enable_srv_queries', 'True', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -166,9 +172,11 @@ current_test_subprocess = subprocess.Popen([ '--target_name', 'srv-ipv6-single-target.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '[2607:f8b0:400a:801::1001]:1234,True', '--expected_chosen_service_config', '', + '--expected_service_config_error', '', '--expected_lb_policy', '', '--enable_srv_queries', 'True', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -180,9 +188,11 @@ current_test_subprocess = subprocess.Popen([ '--target_name', 'srv-ipv6-multi-target.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '[2607:f8b0:400a:801::1002]:1234,True;[2607:f8b0:400a:801::1003]:1234,True;[2607:f8b0:400a:801::1004]:1234,True', '--expected_chosen_service_config', '', + '--expected_service_config_error', '', '--expected_lb_policy', '', '--enable_srv_queries', 'True', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -193,10 +203,12 @@ current_test_subprocess = subprocess.Popen([ args.test_bin_path, '--target_name', 'srv-ipv4-simple-service-config.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '1.2.3.4:1234,True', - '--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}', + '--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true}]}', + '--expected_service_config_error', '', '--expected_lb_policy', 'round_robin', '--enable_srv_queries', 'True', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -207,10 +219,12 @@ current_test_subprocess = subprocess.Popen([ args.test_bin_path, '--target_name', 'ipv4-no-srv-simple-service-config.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '1.2.3.4:443,False', - '--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NoSrvSimpleService","waitForReady":true}]}]}', + '--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NoSrvSimpleService"}],"waitForReady":true}]}', + '--expected_service_config_error', '', '--expected_lb_policy', 'round_robin', '--enable_srv_queries', 'True', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -222,9 +236,11 @@ current_test_subprocess = subprocess.Popen([ '--target_name', 'ipv4-no-config-for-cpp.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '1.2.3.4:443,False', '--expected_chosen_service_config', '', + '--expected_service_config_error', '', '--expected_lb_policy', '', '--enable_srv_queries', 'True', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -236,9 +252,11 @@ current_test_subprocess = subprocess.Popen([ '--target_name', 'ipv4-cpp-config-has-zero-percentage.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '1.2.3.4:443,False', '--expected_chosen_service_config', '', + '--expected_service_config_error', '', '--expected_lb_policy', '', '--enable_srv_queries', 'True', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -249,10 +267,12 @@ current_test_subprocess = subprocess.Popen([ args.test_bin_path, '--target_name', 'ipv4-second-language-is-cpp.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '1.2.3.4:443,False', - '--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}', + '--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":true}]}', + '--expected_service_config_error', '', '--expected_lb_policy', 'round_robin', '--enable_srv_queries', 'True', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -263,10 +283,12 @@ current_test_subprocess = subprocess.Popen([ args.test_bin_path, '--target_name', 'ipv4-config-with-percentages.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '1.2.3.4:443,False', - '--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"AlwaysPickedService","waitForReady":true}]}]}', + '--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"AlwaysPickedService"}],"waitForReady":true}]}', + '--expected_service_config_error', '', '--expected_lb_policy', 'round_robin', '--enable_srv_queries', 'True', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -278,9 +300,11 @@ current_test_subprocess = subprocess.Popen([ '--target_name', 'srv-ipv4-target-has-backend-and-balancer.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '1.2.3.4:1234,True;1.2.3.4:443,False', '--expected_chosen_service_config', '', + '--expected_service_config_error', '', '--expected_lb_policy', '', '--enable_srv_queries', 'True', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -292,9 +316,11 @@ current_test_subprocess = subprocess.Popen([ '--target_name', 'srv-ipv6-target-has-backend-and-balancer.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '[2607:f8b0:400a:801::1002]:1234,True;[2607:f8b0:400a:801::1002]:443,False', '--expected_chosen_service_config', '', + '--expected_service_config_error', '', '--expected_lb_policy', '', '--enable_srv_queries', 'True', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -305,10 +331,12 @@ current_test_subprocess = subprocess.Popen([ args.test_bin_path, '--target_name', 'ipv4-config-causing-fallback-to-tcp.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '1.2.3.4:443,False', - '--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooThree","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFour","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFive","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSix","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSeven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEight","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooNine","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTen","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEleven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]}]}', + '--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwo","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooThree","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooFour","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooFive","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooSix","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooSeven","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooEight","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooNine","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTen","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooEleven","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true}]}', + '--expected_service_config_error', '', '--expected_lb_policy', '', '--enable_srv_queries', 'True', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -320,9 +348,11 @@ current_test_subprocess = subprocess.Popen([ '--target_name', 'srv-ipv4-single-target-srv-disabled.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '2.3.4.5:443,False', '--expected_chosen_service_config', '', + '--expected_service_config_error', '', '--expected_lb_policy', '', '--enable_srv_queries', 'False', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -334,9 +364,11 @@ current_test_subprocess = subprocess.Popen([ '--target_name', 'srv-ipv4-multi-target-srv-disabled.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '9.2.3.5:443,False;9.2.3.6:443,False;9.2.3.7:443,False', '--expected_chosen_service_config', '', + '--expected_service_config_error', '', '--expected_lb_policy', '', '--enable_srv_queries', 'False', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -348,9 +380,11 @@ current_test_subprocess = subprocess.Popen([ '--target_name', 'srv-ipv6-single-target-srv-disabled.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '[2600::1001]:443,False', '--expected_chosen_service_config', '', + '--expected_service_config_error', '', '--expected_lb_policy', '', '--enable_srv_queries', 'False', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -362,9 +396,11 @@ current_test_subprocess = subprocess.Popen([ '--target_name', 'srv-ipv6-multi-target-srv-disabled.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '[2600::1002]:443,False;[2600::1003]:443,False;[2600::1004]:443,False', '--expected_chosen_service_config', '', + '--expected_service_config_error', '', '--expected_lb_policy', '', '--enable_srv_queries', 'False', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -375,10 +411,12 @@ current_test_subprocess = subprocess.Popen([ args.test_bin_path, '--target_name', 'srv-ipv4-simple-service-config-srv-disabled.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '5.5.3.4:443,False', - '--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}', + '--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true}]}', + '--expected_service_config_error', '', '--expected_lb_policy', 'round_robin', '--enable_srv_queries', 'False', '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -390,9 +428,11 @@ current_test_subprocess = subprocess.Popen([ '--target_name', 'srv-ipv4-simple-service-config-txt-disabled.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '1.2.3.4:1234,True', '--expected_chosen_service_config', '', + '--expected_service_config_error', '', '--expected_lb_policy', '', '--enable_srv_queries', 'True', '--enable_txt_queries', 'False', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -404,9 +444,11 @@ current_test_subprocess = subprocess.Popen([ '--target_name', 'ipv4-cpp-config-has-zero-percentage-txt-disabled.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '1.2.3.4:443,False', '--expected_chosen_service_config', '', + '--expected_service_config_error', '', '--expected_lb_policy', '', '--enable_srv_queries', 'True', '--enable_txt_queries', 'False', + '--inject_broken_nameserver_list', 'False', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: @@ -418,9 +460,107 @@ current_test_subprocess = subprocess.Popen([ '--target_name', 'ipv4-second-language-is-cpp-txt-disabled.resolver-tests-version-4.grpctestingexp.', '--expected_addrs', '1.2.3.4:443,False', '--expected_chosen_service_config', '', + '--expected_service_config_error', '', '--expected_lb_policy', '', '--enable_srv_queries', 'True', '--enable_txt_queries', 'False', + '--inject_broken_nameserver_list', 'False', + '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) +current_test_subprocess.communicate() +if current_test_subprocess.returncode != 0: + num_test_failures += 1 + +test_runner_log('Run test with target: %s' % 'ipv4-svc_cfg_bad_json.resolver-tests-version-4.grpctestingexp.') +current_test_subprocess = subprocess.Popen([ + args.test_bin_path, + '--target_name', 'ipv4-svc_cfg_bad_json.resolver-tests-version-4.grpctestingexp.', + '--expected_addrs', '1.2.3.4:443,False', + '--expected_chosen_service_config', '', + '--expected_service_config_error', 'could not parse', + '--expected_lb_policy', '', + '--enable_srv_queries', 'True', + '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', + '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) +current_test_subprocess.communicate() +if current_test_subprocess.returncode != 0: + num_test_failures += 1 + +test_runner_log('Run test with target: %s' % 'ipv4-svc_cfg_bad_client_language.resolver-tests-version-4.grpctestingexp.') +current_test_subprocess = subprocess.Popen([ + args.test_bin_path, + '--target_name', 'ipv4-svc_cfg_bad_client_language.resolver-tests-version-4.grpctestingexp.', + '--expected_addrs', '1.2.3.4:443,False', + '--expected_chosen_service_config', '', + '--expected_service_config_error', 'field:clientLanguage error:should be of type array', + '--expected_lb_policy', '', + '--enable_srv_queries', 'True', + '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', + '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) +current_test_subprocess.communicate() +if current_test_subprocess.returncode != 0: + num_test_failures += 1 + +test_runner_log('Run test with target: %s' % 'ipv4-svc_cfg_bad_percentage.resolver-tests-version-4.grpctestingexp.') +current_test_subprocess = subprocess.Popen([ + args.test_bin_path, + '--target_name', 'ipv4-svc_cfg_bad_percentage.resolver-tests-version-4.grpctestingexp.', + '--expected_addrs', '1.2.3.4:443,False', + '--expected_chosen_service_config', '', + '--expected_service_config_error', 'field:percentage error:should be of type number', + '--expected_lb_policy', '', + '--enable_srv_queries', 'True', + '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', + '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) +current_test_subprocess.communicate() +if current_test_subprocess.returncode != 0: + num_test_failures += 1 + +test_runner_log('Run test with target: %s' % 'ipv4-svc_cfg_bad_wait_for_ready.resolver-tests-version-4.grpctestingexp.') +current_test_subprocess = subprocess.Popen([ + args.test_bin_path, + '--target_name', 'ipv4-svc_cfg_bad_wait_for_ready.resolver-tests-version-4.grpctestingexp.', + '--expected_addrs', '1.2.3.4:443,False', + '--expected_chosen_service_config', '', + '--expected_service_config_error', 'field:waitForReady error:Type should be true/false', + '--expected_lb_policy', '', + '--enable_srv_queries', 'True', + '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'False', + '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) +current_test_subprocess.communicate() +if current_test_subprocess.returncode != 0: + num_test_failures += 1 + +test_runner_log('Run test with target: %s' % 'no-srv-ipv4-single-target-inject-broken-nameservers.resolver-tests-version-4.grpctestingexp.') +current_test_subprocess = subprocess.Popen([ + args.test_bin_path, + '--target_name', 'no-srv-ipv4-single-target-inject-broken-nameservers.resolver-tests-version-4.grpctestingexp.', + '--expected_addrs', '5.5.5.5:443,False', + '--expected_chosen_service_config', '', + '--expected_service_config_error', '', + '--expected_lb_policy', '', + '--enable_srv_queries', 'True', + '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'True', + '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) +current_test_subprocess.communicate() +if current_test_subprocess.returncode != 0: + num_test_failures += 1 + +test_runner_log('Run test with target: %s' % 'ipv4-config-causing-fallback-to-tcp-inject-broken-nameservers.resolver-tests-version-4.grpctestingexp.') +current_test_subprocess = subprocess.Popen([ + args.test_bin_path, + '--target_name', 'ipv4-config-causing-fallback-to-tcp-inject-broken-nameservers.resolver-tests-version-4.grpctestingexp.', + '--expected_addrs', '1.2.3.4:443,False', + '--expected_chosen_service_config', '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooThree","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFour","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFive","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSix","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSeven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEight","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooNine","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTen","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEleven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]}]}', + '--expected_service_config_error', 'Service config parsing error', + '--expected_lb_policy', '', + '--enable_srv_queries', 'True', + '--enable_txt_queries', 'True', + '--inject_broken_nameserver_list', 'True', '--local_dns_server_address', '127.0.0.1:%d' % args.dns_server_port]) current_test_subprocess.communicate() if current_test_subprocess.returncode != 0: diff --git a/test/cpp/naming/resolver_test_record_groups.yaml b/test/cpp/naming/resolver_test_record_groups.yaml index 738fe658939..f72a7eaf572 100644 --- a/test/cpp/naming/resolver_test_record_groups.yaml +++ b/test/cpp/naming/resolver_test_record_groups.yaml @@ -4,9 +4,11 @@ resolver_component_tests: - expected_addrs: - {address: '5.5.5.5:443', is_balancer: false} expected_chosen_service_config: null + expected_service_config_error: null expected_lb_policy: null enable_srv_queries: true enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: no-srv-ipv4-single-target records: no-srv-ipv4-single-target: @@ -14,9 +16,11 @@ resolver_component_tests: - expected_addrs: - {address: '1.2.3.4:1234', is_balancer: true} expected_chosen_service_config: null + expected_service_config_error: null expected_lb_policy: null enable_srv_queries: true enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: srv-ipv4-single-target records: _grpclb._tcp.srv-ipv4-single-target: @@ -28,9 +32,11 @@ resolver_component_tests: - {address: '1.2.3.6:1234', is_balancer: true} - {address: '1.2.3.7:1234', is_balancer: true} expected_chosen_service_config: null + expected_service_config_error: null expected_lb_policy: null enable_srv_queries: true enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: srv-ipv4-multi-target records: _grpclb._tcp.srv-ipv4-multi-target: @@ -42,9 +48,11 @@ resolver_component_tests: - expected_addrs: - {address: '[2607:f8b0:400a:801::1001]:1234', is_balancer: true} expected_chosen_service_config: null + expected_service_config_error: null expected_lb_policy: null enable_srv_queries: true enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: srv-ipv6-single-target records: _grpclb._tcp.srv-ipv6-single-target: @@ -56,9 +64,11 @@ resolver_component_tests: - {address: '[2607:f8b0:400a:801::1003]:1234', is_balancer: true} - {address: '[2607:f8b0:400a:801::1004]:1234', is_balancer: true} expected_chosen_service_config: null + expected_service_config_error: null expected_lb_policy: null enable_srv_queries: true enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: srv-ipv6-multi-target records: _grpclb._tcp.srv-ipv6-multi-target: @@ -69,10 +79,12 @@ resolver_component_tests: - {TTL: '2100', data: '2607:f8b0:400a:801::1004', type: AAAA} - expected_addrs: - {address: '1.2.3.4:1234', is_balancer: true} - expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}' + expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true}]}' + expected_service_config_error: null expected_lb_policy: round_robin enable_srv_queries: true enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: srv-ipv4-simple-service-config records: _grpclb._tcp.srv-ipv4-simple-service-config: @@ -80,80 +92,92 @@ resolver_component_tests: ipv4-simple-service-config: - {TTL: '2100', data: 1.2.3.4, type: A} _grpc_config.srv-ipv4-simple-service-config: - - {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}}]', + - {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true}]}}]', type: TXT} - expected_addrs: - {address: '1.2.3.4:443', is_balancer: false} - expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NoSrvSimpleService","waitForReady":true}]}]}' + expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NoSrvSimpleService"}],"waitForReady":true}]}' + expected_service_config_error: null expected_lb_policy: round_robin enable_srv_queries: true enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: ipv4-no-srv-simple-service-config records: ipv4-no-srv-simple-service-config: - {TTL: '2100', data: 1.2.3.4, type: A} _grpc_config.ipv4-no-srv-simple-service-config: - - {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NoSrvSimpleService","waitForReady":true}]}]}}]', + - {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NoSrvSimpleService"}],"waitForReady":true}]}}]', type: TXT} - expected_addrs: - {address: '1.2.3.4:443', is_balancer: false} expected_chosen_service_config: null + expected_service_config_error: null expected_lb_policy: null enable_srv_queries: true enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: ipv4-no-config-for-cpp records: ipv4-no-config-for-cpp: - {TTL: '2100', data: 1.2.3.4, type: A} _grpc_config.ipv4-no-config-for-cpp: - - {TTL: '2100', data: 'grpc_config=[{"clientLanguage":["python"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"PythonService","waitForReady":true}]}]}}]', + - {TTL: '2100', data: 'grpc_config=[{"clientLanguage":["python"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"PythonService"}],"waitForReady":true}]}}]', type: TXT} - expected_addrs: - {address: '1.2.3.4:443', is_balancer: false} expected_chosen_service_config: null + expected_service_config_error: null expected_lb_policy: null enable_srv_queries: true enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: ipv4-cpp-config-has-zero-percentage records: ipv4-cpp-config-has-zero-percentage: - {TTL: '2100', data: 1.2.3.4, type: A} _grpc_config.ipv4-cpp-config-has-zero-percentage: - - {TTL: '2100', data: 'grpc_config=[{"percentage":0,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}}]', + - {TTL: '2100', data: 'grpc_config=[{"percentage":0,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":true}]}}]', type: TXT} - expected_addrs: - {address: '1.2.3.4:443', is_balancer: false} - expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}' + expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":true}]}' + expected_service_config_error: null expected_lb_policy: round_robin enable_srv_queries: true enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: ipv4-second-language-is-cpp records: ipv4-second-language-is-cpp: - {TTL: '2100', data: 1.2.3.4, type: A} _grpc_config.ipv4-second-language-is-cpp: - - {TTL: '2100', data: 'grpc_config=[{"clientLanguage":["go"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"GoService","waitForReady":true}]}]}},{"clientLanguage":["c++"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}}]', + - {TTL: '2100', data: 'grpc_config=[{"clientLanguage":["go"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"GoService"}],"waitForReady":true}]}},{"clientLanguage":["c++"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":true}]}}]', type: TXT} - expected_addrs: - {address: '1.2.3.4:443', is_balancer: false} - expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"AlwaysPickedService","waitForReady":true}]}]}' + expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"AlwaysPickedService"}],"waitForReady":true}]}' + expected_service_config_error: null expected_lb_policy: round_robin enable_srv_queries: true enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: ipv4-config-with-percentages records: ipv4-config-with-percentages: - {TTL: '2100', data: 1.2.3.4, type: A} _grpc_config.ipv4-config-with-percentages: - - {TTL: '2100', data: 'grpc_config=[{"percentage":0,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NeverPickedService","waitForReady":true}]}]}},{"percentage":100,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"AlwaysPickedService","waitForReady":true}]}]}}]', + - {TTL: '2100', data: 'grpc_config=[{"percentage":0,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"NeverPickedService"}],"waitForReady":true}]}},{"percentage":100,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"AlwaysPickedService"}],"waitForReady":true}]}}]', type: TXT} - expected_addrs: - {address: '1.2.3.4:1234', is_balancer: true} - {address: '1.2.3.4:443', is_balancer: false} expected_chosen_service_config: null + expected_service_config_error: null expected_lb_policy: null enable_srv_queries: true enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: srv-ipv4-target-has-backend-and-balancer records: _grpclb._tcp.srv-ipv4-target-has-backend-and-balancer: @@ -166,9 +190,11 @@ resolver_component_tests: - {address: '[2607:f8b0:400a:801::1002]:1234', is_balancer: true} - {address: '[2607:f8b0:400a:801::1002]:443', is_balancer: false} expected_chosen_service_config: null + expected_service_config_error: null expected_lb_policy: null enable_srv_queries: true enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: srv-ipv6-target-has-backend-and-balancer records: _grpclb._tcp.srv-ipv6-target-has-backend-and-balancer: @@ -179,24 +205,28 @@ resolver_component_tests: - {TTL: '2100', data: '2607:f8b0:400a:801::1002', type: AAAA} - expected_addrs: - {address: '1.2.3.4:443', is_balancer: false} - expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooThree","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFour","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFive","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSix","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSeven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEight","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooNine","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTen","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEleven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]}]}' + expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwo","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooThree","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooFour","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooFive","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooSix","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooSeven","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooEight","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooNine","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTen","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooEleven","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true}]}' + expected_service_config_error: null expected_lb_policy: null enable_srv_queries: true enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: ipv4-config-causing-fallback-to-tcp records: ipv4-config-causing-fallback-to-tcp: - {TTL: '2100', data: 1.2.3.4, type: A} _grpc_config.ipv4-config-causing-fallback-to-tcp: - - {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooThree","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFour","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFive","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSix","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSeven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEight","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooNine","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTen","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEleven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]}]}}]', + - {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwo","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooThree","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooFour","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooFive","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooSix","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooSeven","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooEight","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooNine","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTen","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooEleven","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true},{"name":[{"method":"FooTwelve","service":"SimpleService"}],"waitForReady":true}]}}]', type: TXT} # Tests for which we don't enable SRV queries - expected_addrs: - {address: '2.3.4.5:443', is_balancer: false} expected_chosen_service_config: null + expected_service_config_error: null expected_lb_policy: null enable_srv_queries: false enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: srv-ipv4-single-target-srv-disabled records: _grpclb._tcp.srv-ipv4-single-target-srv-disabled: @@ -210,9 +240,11 @@ resolver_component_tests: - {address: '9.2.3.6:443', is_balancer: false} - {address: '9.2.3.7:443', is_balancer: false} expected_chosen_service_config: null + expected_service_config_error: null expected_lb_policy: null enable_srv_queries: false enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: srv-ipv4-multi-target-srv-disabled records: _grpclb._tcp.srv-ipv4-multi-target-srv-disabled: @@ -228,9 +260,11 @@ resolver_component_tests: - expected_addrs: - {address: '[2600::1001]:443', is_balancer: false} expected_chosen_service_config: null + expected_service_config_error: null expected_lb_policy: null enable_srv_queries: false enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: srv-ipv6-single-target-srv-disabled records: _grpclb._tcp.srv-ipv6-single-target-srv-disabled: @@ -244,9 +278,11 @@ resolver_component_tests: - {address: '[2600::1003]:443', is_balancer: false} - {address: '[2600::1004]:443', is_balancer: false} expected_chosen_service_config: null + expected_service_config_error: null expected_lb_policy: null enable_srv_queries: false enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: srv-ipv6-multi-target-srv-disabled records: _grpclb._tcp.srv-ipv6-multi-target-srv-disabled: @@ -261,10 +297,12 @@ resolver_component_tests: - {TTL: '2100', data: '2600::1004', type: AAAA} - expected_addrs: - {address: '5.5.3.4:443', is_balancer: false} - expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}' + expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true}]}' + expected_service_config_error: null expected_lb_policy: round_robin enable_srv_queries: false enable_txt_queries: true + inject_broken_nameserver_list: false record_to_resolve: srv-ipv4-simple-service-config-srv-disabled records: _grpclb._tcp.srv-ipv4-simple-service-config-srv-disabled: @@ -274,14 +312,16 @@ resolver_component_tests: srv-ipv4-simple-service-config-srv-disabled: - {TTL: '2100', data: 5.5.3.4, type: A} _grpc_config.srv-ipv4-simple-service-config-srv-disabled: - - {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}}]', + - {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true}]}}]', type: TXT} - expected_addrs: - {address: '1.2.3.4:1234', is_balancer: true} expected_chosen_service_config: null + expected_service_config_error: null expected_lb_policy: null enable_srv_queries: true enable_txt_queries: false + inject_broken_nameserver_list: false record_to_resolve: srv-ipv4-simple-service-config-txt-disabled records: _grpclb._tcp.srv-ipv4-simple-service-config-txt-disabled: @@ -289,31 +329,123 @@ resolver_component_tests: ipv4-simple-service-config-txt-disabled: - {TTL: '2100', data: 1.2.3.4, type: A} _grpc_config.srv-ipv4-simple-service-config-txt-disabled: - - {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]}]}}]', + - {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService"}],"waitForReady":true}]}}]', type: TXT} - expected_addrs: - {address: '1.2.3.4:443', is_balancer: false} expected_chosen_service_config: null + expected_service_config_error: null expected_lb_policy: null enable_srv_queries: true enable_txt_queries: false + inject_broken_nameserver_list: false record_to_resolve: ipv4-cpp-config-has-zero-percentage-txt-disabled records: ipv4-cpp-config-has-zero-percentage-txt-disabled: - {TTL: '2100', data: 1.2.3.4, type: A} _grpc_config.ipv4-cpp-config-has-zero-percentage-txt-disabled: - - {TTL: '2100', data: 'grpc_config=[{"percentage":0,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}}]', + - {TTL: '2100', data: 'grpc_config=[{"percentage":0,"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":true}]}}]', type: TXT} - expected_addrs: - {address: '1.2.3.4:443', is_balancer: false} expected_chosen_service_config: null + expected_service_config_error: null expected_lb_policy: null enable_srv_queries: true enable_txt_queries: false + inject_broken_nameserver_list: false record_to_resolve: ipv4-second-language-is-cpp-txt-disabled records: ipv4-second-language-is-cpp-txt-disabled: - {TTL: '2100', data: 1.2.3.4, type: A} _grpc_config.ipv4-second-language-is-cpp-txt-disabled: - - {TTL: '2100', data: 'grpc_config=[{"clientLanguage":["go"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"GoService","waitForReady":true}]}]}},{"clientLanguage":["c++"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService","waitForReady":true}]}]}}]', + - {TTL: '2100', data: 'grpc_config=[{"clientLanguage":["go"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"GoService"}],"waitForReady":true}]}},{"clientLanguage":["c++"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":true}]}}]', + type: TXT} +- expected_addrs: + - {address: '1.2.3.4:443', is_balancer: false} + expected_chosen_service_config: null + expected_service_config_error: 'could not parse' + expected_lb_policy: null + enable_srv_queries: true + enable_txt_queries: true + inject_broken_nameserver_list: false + record_to_resolve: ipv4-svc_cfg_bad_json + records: + ipv4-svc_cfg_bad_json: + - {TTL: '2100', data: 1.2.3.4, type: A} + _grpc_config.ipv4-svc_cfg_bad_json: + - {TTL: '2100', data: 'grpc_config=[{]', + type: TXT} +- expected_addrs: + - {address: '1.2.3.4:443', is_balancer: false} + expected_chosen_service_config: null + expected_service_config_error: 'field:clientLanguage error:should be of type array' + expected_lb_policy: null + enable_srv_queries: true + enable_txt_queries: true + inject_broken_nameserver_list: false + record_to_resolve: ipv4-svc_cfg_bad_client_language + records: + ipv4-svc_cfg_bad_client_language: + - {TTL: '2100', data: 1.2.3.4, type: A} + _grpc_config.ipv4-svc_cfg_bad_client_language: + - {TTL: '2100', data: 'grpc_config=[{"clientLanguage":"go","serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"GoService"}],"waitForReady":true}]}},{"clientLanguage":["c++"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":true}]}}]', + type: TXT} +- expected_addrs: + - {address: '1.2.3.4:443', is_balancer: false} + expected_chosen_service_config: null + expected_service_config_error: 'field:percentage error:should be of type number' + expected_lb_policy: null + enable_srv_queries: true + enable_txt_queries: true + inject_broken_nameserver_list: false + record_to_resolve: ipv4-svc_cfg_bad_percentage + records: + ipv4-svc_cfg_bad_percentage: + - {TTL: '2100', data: 1.2.3.4, type: A} + _grpc_config.ipv4-svc_cfg_bad_percentage: + - {TTL: '2100', data: 'grpc_config=[{"percentage":"0","serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"GoService"}],"waitForReady":true}]}},{"clientLanguage":["c++"],"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":true}]}}]', + type: TXT} +- expected_addrs: + - {address: '1.2.3.4:443', is_balancer: false} + expected_chosen_service_config: null + expected_service_config_error: 'field:waitForReady error:Type should be true/false' + expected_lb_policy: null + enable_srv_queries: true + enable_txt_queries: true + inject_broken_nameserver_list: false + record_to_resolve: ipv4-svc_cfg_bad_wait_for_ready + records: + ipv4-svc_cfg_bad_wait_for_ready: + - {TTL: '2100', data: 1.2.3.4, type: A} + _grpc_config.ipv4-svc_cfg_bad_wait_for_ready: + - {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"methodConfig":[{"name":[{"method":"Foo","service":"CppService"}],"waitForReady":"true"}]}}]', + type: TXT} +# Tests for which we also exercise the resolver's ability to skip past a broken DNS server in its nameserver list +- expected_addrs: + - {address: '5.5.5.5:443', is_balancer: false} + expected_chosen_service_config: null + expected_service_config_error: null + expected_lb_policy: null + enable_srv_queries: true + enable_txt_queries: true + inject_broken_nameserver_list: true + record_to_resolve: no-srv-ipv4-single-target-inject-broken-nameservers + records: + no-srv-ipv4-single-target-inject-broken-nameservers: + - {TTL: '2100', data: 5.5.5.5, type: A} +- expected_addrs: + - {address: '1.2.3.4:443', is_balancer: false} + expected_chosen_service_config: '{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooThree","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFour","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFive","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSix","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSeven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEight","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooNine","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTen","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEleven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]}]}' + expected_service_config_error: 'Service config parsing error' + expected_lb_policy: null + enable_srv_queries: true + enable_txt_queries: true + inject_broken_nameserver_list: true + record_to_resolve: ipv4-config-causing-fallback-to-tcp-inject-broken-nameservers + records: + ipv4-config-causing-fallback-to-tcp-inject-broken-nameservers: + - {TTL: '2100', data: 1.2.3.4, type: A} + _grpc_config.ipv4-config-causing-fallback-to-tcp-inject-broken-nameservers: + - {TTL: '2100', data: 'grpc_config=[{"serviceConfig":{"loadBalancingPolicy":"round_robin","methodConfig":[{"name":[{"method":"Foo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwo","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooThree","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFour","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooFive","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSix","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooSeven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEight","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooNine","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTen","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooEleven","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]},{"name":[{"method":"FooTwelve","service":"SimpleService","waitForReady":true}]}]}}]', type: TXT} diff --git a/test/cpp/performance/writes_per_rpc_test.cc b/test/cpp/performance/writes_per_rpc_test.cc index 7b22f23cf00..b74f4d0466b 100644 --- a/test/cpp/performance/writes_per_rpc_test.cc +++ b/test/cpp/performance/writes_per_rpc_test.cc @@ -118,7 +118,7 @@ class EndpointPairFixture { "target", &c_args, GRPC_CLIENT_DIRECT_CHANNEL, transport); grpc_chttp2_transport_start_reading(transport, nullptr, nullptr); - channel_ = CreateChannelInternal( + channel_ = ::grpc::CreateChannelInternal( "", channel, std::vector>()); diff --git a/test/cpp/qps/client_callback.cc b/test/cpp/qps/client_callback.cc index 815780e40ff..d22264d21e3 100644 --- a/test/cpp/qps/client_callback.cc +++ b/test/cpp/qps/client_callback.cc @@ -43,13 +43,14 @@ namespace testing { * Maintains context info per RPC */ struct CallbackClientRpcContext { - CallbackClientRpcContext(BenchmarkService::Stub* stub) : stub_(stub) {} + CallbackClientRpcContext(BenchmarkService::Stub* stub) + : alarm_(nullptr), stub_(stub) {} ~CallbackClientRpcContext() {} SimpleResponse response_; ClientContext context_; - Alarm alarm_; + std::unique_ptr alarm_; BenchmarkService::Stub* stub_; }; @@ -169,7 +170,10 @@ class CallbackUnaryClient final : public CallbackClient { gpr_timespec next_issue_time = NextRPCIssueTime(); // Start an alarm callback to run the internal callback after // next_issue_time - ctx_[vector_idx]->alarm_.experimental().Set( + if (ctx_[vector_idx]->alarm_ == nullptr) { + ctx_[vector_idx]->alarm_.reset(new Alarm); + } + ctx_[vector_idx]->alarm_->experimental().Set( next_issue_time, [this, t, vector_idx](bool ok) { IssueUnaryCallbackRpc(t, vector_idx); }); @@ -285,8 +289,18 @@ class CallbackStreamingPingPongReactor final } return; } - write_time_ = UsageTimer::Now(); - StartWrite(client_->request()); + if (!client_->IsClosedLoop()) { + gpr_timespec next_issue_time = client_->NextRPCIssueTime(); + // Start an alarm callback to run the internal callback after + // next_issue_time + ctx_->alarm_->experimental().Set(next_issue_time, [this](bool ok) { + write_time_ = UsageTimer::Now(); + StartWrite(client_->request()); + }); + } else { + write_time_ = UsageTimer::Now(); + StartWrite(client_->request()); + } } void OnDone(const Status& s) override { @@ -303,8 +317,11 @@ class CallbackStreamingPingPongReactor final gpr_timespec next_issue_time = client_->NextRPCIssueTime(); // Start an alarm callback to run the internal callback after // next_issue_time - ctx_->alarm_.experimental().Set(next_issue_time, - [this](bool ok) { StartNewRpc(); }); + if (ctx_->alarm_ == nullptr) { + ctx_->alarm_.reset(new Alarm); + } + ctx_->alarm_->experimental().Set(next_issue_time, + [this](bool ok) { StartNewRpc(); }); } else { StartNewRpc(); } diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc index 181e11f12b2..7d4d5d99446 100644 --- a/test/cpp/qps/driver.cc +++ b/test/cpp/qps/driver.cc @@ -288,7 +288,7 @@ std::unique_ptr RunScenario( gpr_log(GPR_INFO, "Starting server on %s (worker #%" PRIuPTR ")", workers[i].c_str(), i); if (!run_inproc) { - servers[i].stub = WorkerService::NewStub(CreateChannel( + servers[i].stub = WorkerService::NewStub(grpc::CreateChannel( workers[i], GetCredentialsProvider()->GetChannelCredentials( GetCredType(workers[i], per_worker_credential_types, credential_type), @@ -349,7 +349,7 @@ std::unique_ptr RunScenario( gpr_log(GPR_INFO, "Starting client on %s (worker #%" PRIuPTR ")", worker.c_str(), i + num_servers); if (!run_inproc) { - clients[i].stub = WorkerService::NewStub(CreateChannel( + clients[i].stub = WorkerService::NewStub(grpc::CreateChannel( worker, GetCredentialsProvider()->GetChannelCredentials( GetCredType(worker, per_worker_credential_types, credential_type), @@ -557,7 +557,7 @@ bool RunQuit( ChannelArguments channel_args; for (size_t i = 0; i < workers.size(); i++) { - auto stub = WorkerService::NewStub(CreateChannel( + auto stub = WorkerService::NewStub(grpc::CreateChannel( workers[i], GetCredentialsProvider()->GetChannelCredentials( GetCredType(workers[i], per_worker_credential_types, credential_type), diff --git a/test/cpp/server/server_request_call_test.cc b/test/cpp/server/server_request_call_test.cc index 9831c061766..14b735cf13d 100644 --- a/test/cpp/server/server_request_call_test.cc +++ b/test/cpp/server/server_request_call_test.cc @@ -115,7 +115,7 @@ TEST(ServerRequestCallTest, ShortDeadlineDoesNotCauseOkayFalse) { }); auto stub = testing::EchoTestService::NewStub( - CreateChannel(address, InsecureChannelCredentials())); + grpc::CreateChannel(address, InsecureChannelCredentials())); for (int i = 0; i < 100; i++) { gpr_log(GPR_INFO, "Sending %d.", i); diff --git a/test/cpp/util/cli_call_test.cc b/test/cpp/util/cli_call_test.cc index 1d641535e29..a91705bd514 100644 --- a/test/cpp/util/cli_call_test.cc +++ b/test/cpp/util/cli_call_test.cc @@ -74,8 +74,8 @@ class CliCallTest : public ::testing::Test { void TearDown() override { server_->Shutdown(); } void ResetStub() { - channel_ = - CreateChannel(server_address_.str(), InsecureChannelCredentials()); + channel_ = grpc::CreateChannel(server_address_.str(), + InsecureChannelCredentials()); stub_ = grpc::testing::EchoTestService::NewStub(channel_); } diff --git a/test/cpp/util/create_test_channel.cc b/test/cpp/util/create_test_channel.cc index 79a5e13d993..5c32198bc3a 100644 --- a/test/cpp/util/create_test_channel.cc +++ b/test/cpp/util/create_test_channel.cc @@ -34,7 +34,7 @@ class SslCredentialProvider : public testing::CredentialTypeProvider { public: std::shared_ptr GetChannelCredentials( grpc::ChannelArguments* args) override { - return SslCredentials(SslCredentialsOptions()); + return grpc::SslCredentials(SslCredentialsOptions()); } std::shared_ptr GetServerCredentials() override { return nullptr; @@ -116,9 +116,9 @@ std::shared_ptr CreateTestChannel( &channel_args); GPR_ASSERT(channel_creds != nullptr); if (creds.get()) { - channel_creds = CompositeChannelCredentials(channel_creds, creds); + channel_creds = grpc::CompositeChannelCredentials(channel_creds, creds); } - return CreateCustomChannel(server, channel_creds, channel_args); + return ::grpc::CreateCustomChannel(server, channel_creds, channel_args); } std::shared_ptr CreateTestChannel( @@ -132,7 +132,8 @@ std::shared_ptr CreateTestChannel( std::shared_ptr channel_creds; if (cred_type.empty()) { if (interceptor_creators.empty()) { - return CreateCustomChannel(server, InsecureChannelCredentials(), args); + return ::grpc::CreateCustomChannel(server, InsecureChannelCredentials(), + args); } else { return experimental::CreateCustomChannelWithInterceptors( server, InsecureChannelCredentials(), args, @@ -156,10 +157,11 @@ std::shared_ptr CreateTestChannel( const grpc::string& connect_to = server.empty() ? override_hostname : server; if (creds.get()) { - channel_creds = CompositeChannelCredentials(channel_creds, creds); + channel_creds = grpc::CompositeChannelCredentials(channel_creds, creds); } if (interceptor_creators.empty()) { - return CreateCustomChannel(connect_to, channel_creds, channel_args); + return ::grpc::CreateCustomChannel(connect_to, channel_creds, + channel_args); } else { return experimental::CreateCustomChannelWithInterceptors( connect_to, channel_creds, channel_args, @@ -171,7 +173,7 @@ std::shared_ptr CreateTestChannel( GPR_ASSERT(channel_creds != nullptr); if (interceptor_creators.empty()) { - return CreateCustomChannel(server, channel_creds, args); + return ::grpc::CreateCustomChannel(server, channel_creds, args); } else { return experimental::CreateCustomChannelWithInterceptors( server, channel_creds, args, std::move(interceptor_creators)); @@ -220,7 +222,7 @@ std::shared_ptr CreateTestChannel( &channel_args); GPR_ASSERT(channel_creds != nullptr); if (creds.get()) { - channel_creds = CompositeChannelCredentials(channel_creds, creds); + channel_creds = grpc::CompositeChannelCredentials(channel_creds, creds); } return experimental::CreateCustomChannelWithInterceptors( server, channel_creds, channel_args, std::move(interceptor_creators)); diff --git a/test/cpp/util/create_test_channel.h b/test/cpp/util/create_test_channel.h index b50131b385c..42564a31ec8 100644 --- a/test/cpp/util/create_test_channel.h +++ b/test/cpp/util/create_test_channel.h @@ -24,8 +24,12 @@ #include #include -namespace grpc { +namespace grpc_impl { + class Channel; +} + +namespace grpc { namespace testing { @@ -33,31 +37,31 @@ typedef enum { INSECURE = 0, TLS, ALTS } transport_security; } // namespace testing -std::shared_ptr CreateTestChannel( +std::shared_ptr<::grpc_impl::Channel> CreateTestChannel( const grpc::string& server, testing::transport_security security_type); -std::shared_ptr CreateTestChannel( +std::shared_ptr<::grpc_impl::Channel> CreateTestChannel( const grpc::string& server, const grpc::string& override_hostname, testing::transport_security security_type, bool use_prod_roots); -std::shared_ptr CreateTestChannel( +std::shared_ptr<::grpc_impl::Channel> CreateTestChannel( const grpc::string& server, const grpc::string& override_hostname, testing::transport_security security_type, bool use_prod_roots, const std::shared_ptr& creds); -std::shared_ptr CreateTestChannel( +std::shared_ptr<::grpc_impl::Channel> CreateTestChannel( const grpc::string& server, const grpc::string& override_hostname, testing::transport_security security_type, bool use_prod_roots, const std::shared_ptr& creds, const ChannelArguments& args); -std::shared_ptr CreateTestChannel( +std::shared_ptr<::grpc_impl::Channel> CreateTestChannel( const grpc::string& server, const grpc::string& cred_type, const grpc::string& override_hostname, bool use_prod_roots, const std::shared_ptr& creds, const ChannelArguments& args); -std::shared_ptr CreateTestChannel( +std::shared_ptr<::grpc_impl::Channel> CreateTestChannel( const grpc::string& server, const grpc::string& credential_type, const std::shared_ptr& creds); diff --git a/test/cpp/util/grpc_tool.cc b/test/cpp/util/grpc_tool.cc index 44b14bf617f..dbac31170f0 100644 --- a/test/cpp/util/grpc_tool.cc +++ b/test/cpp/util/grpc_tool.cc @@ -217,7 +217,8 @@ std::shared_ptr CreateCliChannel( if (!cred.GetSslTargetNameOverride().empty()) { args.SetSslTargetNameOverride(cred.GetSslTargetNameOverride()); } - return grpc::CreateCustomChannel(server_address, cred.GetCredentials(), args); + return ::grpc::CreateCustomChannel(server_address, cred.GetCredentials(), + args); } struct Command { diff --git a/test/cpp/util/grpc_tool_test.cc b/test/cpp/util/grpc_tool_test.cc index 57cdbeb7b76..e44ada46c24 100644 --- a/test/cpp/util/grpc_tool_test.cc +++ b/test/cpp/util/grpc_tool_test.cc @@ -122,7 +122,7 @@ class TestCliCredentials final : public grpc::testing::CliCredentials { return InsecureChannelCredentials(); } SslCredentialsOptions ssl_opts = {test_root_cert, "", ""}; - return SslCredentials(grpc::SslCredentialsOptions(ssl_opts)); + return grpc::SslCredentials(grpc::SslCredentialsOptions(ssl_opts)); } const grpc::string GetCredentialUsage() const override { return ""; } diff --git a/test/cpp/util/metrics_server.h b/test/cpp/util/metrics_server.h index 2d6ddf08043..08f6034c28e 100644 --- a/test/cpp/util/metrics_server.h +++ b/test/cpp/util/metrics_server.h @@ -21,6 +21,8 @@ #include #include +#include + #include "src/proto/grpc/testing/metrics.grpc.pb.h" #include "src/proto/grpc/testing/metrics.pb.h" diff --git a/test/cpp/util/test_credentials_provider.cc b/test/cpp/util/test_credentials_provider.cc index 49688e5cf9b..455f94e33d4 100644 --- a/test/cpp/util/test_credentials_provider.cc +++ b/test/cpp/util/test_credentials_provider.cc @@ -63,7 +63,7 @@ class DefaultCredentialsProvider : public CredentialsProvider { } else if (type == grpc::testing::kTlsCredentialsType) { SslCredentialsOptions ssl_opts = {test_root_cert, "", ""}; args->SetSslTargetNameOverride("foo.test.google.fr"); - return SslCredentials(ssl_opts); + return grpc::SslCredentials(ssl_opts); } else if (type == grpc::testing::kGoogleDefaultCredentialsType) { return grpc::GoogleDefaultCredentials(); } else { diff --git a/tools/bazel.sh b/tools/bazel.sh new file mode 100755 index 00000000000..37fd2a242bf --- /dev/null +++ b/tools/bazel.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# Copyright 2019 The gRPC Authors +# +# 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. + + +# Keeping up with Bazel's breaking changes is currently difficult. +# This script wraps calling bazel by downloading the currently +# supported version, and then calling it. This way, we can make sure +# that running bazel will always get meaningful results, at least +# until Bazel 1.0 is released. + +set -e + +VERSION=0.24.1 + +CWD=`pwd` +BASEURL=https://github.com/bazelbuild/bazel/releases/download/ +cd `dirname $0` +TOOLDIR=`pwd` + +case `uname -sm` in + "Linux x86_64") + suffix=linux-x86_64 + ;; + "Darwin x86_64") + suffix=darwin-x86_64 + ;; + *) + echo "Unsupported architecture: `uname -sm`" + exit 1 + ;; +esac + +filename=bazel-$VERSION-$suffix + +if [ ! -x $filename ] ; then + curl -L $BASEURL/$VERSION/$filename > $filename + chmod a+x $filename +fi + +cd $CWD +$TOOLDIR/$filename $@ diff --git a/tools/codegen/core/gen_static_metadata.py b/tools/codegen/core/gen_static_metadata.py index 5545e871117..d66fdc3e835 100755 --- a/tools/codegen/core/gen_static_metadata.py +++ b/tools/codegen/core/gen_static_metadata.py @@ -376,6 +376,8 @@ print >> H, '#define GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H' print >> H print >> H, '#include ' print >> H +print >> H, '#include ' +print >> H print >> H, '#include "src/core/lib/transport/metadata.h"' print >> H print >> C, '#include ' @@ -433,8 +435,8 @@ for i, elem in enumerate(all_strs): print >> C, '};' print >> C print >> H, '#define GRPC_STATIC_METADATA_INDEX(static_slice) \\' -print >> H, (' ((int)((static_slice).refcount - ' - 'grpc_static_metadata_refcounts))') +print >> H, (' (static_cast(((static_slice).refcount - ' + 'grpc_static_metadata_refcounts)))') print >> H print >> D, '# hpack fuzzing dictionary' @@ -537,10 +539,10 @@ print >> C, 'static const uint8_t elem_idxs[] = {%s};' % ','.join( '%d' % i for i in idxs) print >> C -print >> H, 'grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b);' -print >> C, 'grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) {' +print >> H, 'grpc_mdelem grpc_static_mdelem_for_static_strings(intptr_t a, intptr_t b);' +print >> C, 'grpc_mdelem grpc_static_mdelem_for_static_strings(intptr_t a, intptr_t b) {' print >> C, ' if (a == -1 || b == -1) return GRPC_MDNULL;' -print >> C, ' uint32_t k = (uint32_t)(a * %d + b);' % len(all_strs) +print >> C, ' uint32_t k = static_cast(a * %d + b);' % len(all_strs) print >> C, ' uint32_t h = elems_phash(k);' print >> C, ' return h < GPR_ARRAY_SIZE(elem_keys) && elem_keys[h] == k && elem_idxs[h] != 255 ? GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[elem_idxs[h]], GRPC_MDELEM_STORAGE_STATIC) : GRPC_MDNULL;' print >> C, '}' @@ -566,7 +568,7 @@ print >> H, ' } named;' print >> H, '} grpc_metadata_batch_callouts;' print >> H print >> H, '#define GRPC_BATCH_INDEX_OF(slice) \\' -print >> H, ' (GRPC_IS_STATIC_METADATA_STRING((slice)) ? (grpc_metadata_batch_callouts_index)GPR_CLAMP(GRPC_STATIC_METADATA_INDEX((slice)), 0, GRPC_BATCH_CALLOUTS_COUNT) : GRPC_BATCH_CALLOUTS_COUNT)' +print >> H, ' (GRPC_IS_STATIC_METADATA_STRING((slice)) ? static_cast(GPR_CLAMP(GRPC_STATIC_METADATA_INDEX((slice)), 0, static_cast(GRPC_BATCH_CALLOUTS_COUNT))) : GRPC_BATCH_CALLOUTS_COUNT)' print >> H print >> H, 'extern const uint8_t grpc_static_accept_encoding_metadata[%d];' % ( diff --git a/tools/distrib/bazel_style.cfg b/tools/distrib/bazel_style.cfg new file mode 100644 index 00000000000..a5a1fea4aba --- /dev/null +++ b/tools/distrib/bazel_style.cfg @@ -0,0 +1,4 @@ +[style] +based_on_style = google +allow_split_before_dict_value = False +spaces_around_default_or_named_assign = True diff --git a/tools/distrib/format_bazel.sh b/tools/distrib/format_bazel.sh new file mode 100755 index 00000000000..ee230118efb --- /dev/null +++ b/tools/distrib/format_bazel.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# Copyright 2019 The gRPC authors. +# +# 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. + +set=-ex + +VIRTUAL_ENV=bazel_format_virtual_environment + +CONFIG_PATH="$(dirname ${0})/bazel_style.cfg" + +python -m virtualenv ${VIRTUAL_ENV} +PYTHON=${VIRTUAL_ENV}/bin/python +"$PYTHON" -m pip install --upgrade pip==10.0.1 +"$PYTHON" -m pip install --upgrade futures +"$PYTHON" -m pip install yapf==0.20.0 + +pushd "$(dirname "${0}")/../.." +FILES=$(find . -path ./third_party -prune -o -name '*.bzl' -print) +echo "${FILES}" | xargs "$PYTHON" -m yapf -i --style="${CONFIG_PATH}" + +if ! which buildifier &>/dev/null; then + echo 'buildifer must be installed.' >/dev/stderr + exit 1 +fi + +echo "${FILES}" | xargs buildifier --type=bzl + +popd diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py index 22d04c5a1af..24ec4301b65 100644 --- a/tools/distrib/python/grpcio_tools/grpc_version.py +++ b/tools/distrib/python/grpcio_tools/grpc_version.py @@ -14,4 +14,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!! -VERSION = '1.21.0.dev0' +VERSION = '1.22.0.dev0' diff --git a/tools/dockerfile/grpc_clang_format/Dockerfile b/tools/dockerfile/grpc_clang_format/Dockerfile index 8e5edf75d52..876992fd99d 100644 --- a/tools/dockerfile/grpc_clang_format/Dockerfile +++ b/tools/dockerfile/grpc_clang_format/Dockerfile @@ -13,7 +13,6 @@ # limitations under the License. FROM debian:jessie -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list RUN apt-get update && apt-get -y install wget xz-utils diff --git a/tools/dockerfile/grpc_clang_tidy/Dockerfile b/tools/dockerfile/grpc_clang_tidy/Dockerfile index 2e0e683c202..a5abca0c6e3 100644 --- a/tools/dockerfile/grpc_clang_tidy/Dockerfile +++ b/tools/dockerfile/grpc_clang_tidy/Dockerfile @@ -13,7 +13,6 @@ # limitations under the License. FROM debian:jessie -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list RUN apt-get update && apt-get -y install wget xz-utils diff --git a/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh index 2a3e6f3a0ee..0b32638b54b 100644 --- a/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh +++ b/tools/dockerfile/interoptest/grpc_interop_aspnetcore/build_interop.sh @@ -37,7 +37,4 @@ then ln -s $(pwd)/.dotnet/dotnet /usr/local/bin/dotnet fi -./build/get-grpc.sh - -cd testassets/InteropTestsWebsite -dotnet build --configuration Debug +dotnet build --configuration Debug Grpc.AspNetCore.sln diff --git a/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile index 1fe64a462aa..e9f2a853344 100644 --- a/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile +++ b/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile @@ -13,7 +13,6 @@ # limitations under the License. FROM debian:jessie -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list # Install Git and basic packages. diff --git a/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile index 217175159df..979c14db3f6 100644 --- a/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile +++ b/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile @@ -13,7 +13,6 @@ # limitations under the License. FROM debian:jessie -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list # Install JDK 8 diff --git a/tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile index 217175159df..979c14db3f6 100644 --- a/tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile +++ b/tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile @@ -13,7 +13,6 @@ # limitations under the License. FROM debian:jessie -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list # Install JDK 8 diff --git a/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile index 96adf6edd86..283a99d0c5f 100644 --- a/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile +++ b/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile @@ -13,7 +13,6 @@ # limitations under the License. FROM debian:jessie -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list # Install Git and basic packages. diff --git a/tools/dockerfile/interoptest/grpc_interop_node/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_node/build_interop.sh index c16efc1d354..aeb82e0c9c3 100755 --- a/tools/dockerfile/interoptest/grpc_interop_node/build_interop.sh +++ b/tools/dockerfile/interoptest/grpc_interop_node/build_interop.sh @@ -29,6 +29,4 @@ cp -r /var/local/jenkins/service_account $HOME || true cd /var/local/git/grpc-node # build Node interop client & server -npm install -g node-gyp gulp -npm install -gulp setup +./setup_interop.sh diff --git a/tools/dockerfile/interoptest/grpc_interop_nodepurejs/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_nodepurejs/Dockerfile index 88e3cfacd97..fd089f1bc4d 100644 --- a/tools/dockerfile/interoptest/grpc_interop_nodepurejs/Dockerfile +++ b/tools/dockerfile/interoptest/grpc_interop_nodepurejs/Dockerfile @@ -13,7 +13,6 @@ # limitations under the License. FROM debian:jessie -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list # Install Git and basic packages. diff --git a/tools/dockerfile/interoptest/grpc_interop_nodepurejs/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_nodepurejs/build_interop.sh index d41ccacd2f9..db55f5a19f3 100755 --- a/tools/dockerfile/interoptest/grpc_interop_nodepurejs/build_interop.sh +++ b/tools/dockerfile/interoptest/grpc_interop_nodepurejs/build_interop.sh @@ -29,8 +29,4 @@ cp -r /var/local/jenkins/service_account $HOME || true cd /var/local/git/grpc-node # build Node interop client & server -npm install -g gulp -npm install -gulp js.core.install -gulp protobuf.install -gulp internal.test.install +./setup_interop_purejs.sh diff --git a/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile index c9c141e5d54..04f0ac2a659 100644 --- a/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile +++ b/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile @@ -13,7 +13,6 @@ # limitations under the License. FROM debian:jessie -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list # Install Git and basic packages. diff --git a/tools/dockerfile/interoptest/grpc_interop_php7/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_php7/Dockerfile index 84241391dfc..01de0eb39e9 100644 --- a/tools/dockerfile/interoptest/grpc_interop_php7/Dockerfile +++ b/tools/dockerfile/interoptest/grpc_interop_php7/Dockerfile @@ -13,7 +13,6 @@ # limitations under the License. FROM debian:jessie -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list #================= diff --git a/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile index cce5e86cd37..8e605a8c341 100644 --- a/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile +++ b/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile @@ -13,7 +13,6 @@ # limitations under the License. FROM debian:jessie -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list # Install Git and basic packages. diff --git a/tools/dockerfile/test/cxx_jessie_x64/Dockerfile b/tools/dockerfile/test/cxx_jessie_x64/Dockerfile index c46f9618b17..b79faa09c05 100644 --- a/tools/dockerfile/test/cxx_jessie_x64/Dockerfile +++ b/tools/dockerfile/test/cxx_jessie_x64/Dockerfile @@ -13,7 +13,6 @@ # limitations under the License. FROM debian:jessie -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list # Install Git and basic packages. diff --git a/tools/dockerfile/test/fuzzer/Dockerfile b/tools/dockerfile/test/fuzzer/Dockerfile index 14e447891da..f9dd948a1b3 100644 --- a/tools/dockerfile/test/fuzzer/Dockerfile +++ b/tools/dockerfile/test/fuzzer/Dockerfile @@ -13,7 +13,6 @@ # limitations under the License. FROM debian:jessie -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list # Install Git and basic packages. diff --git a/tools/dockerfile/test/node_jessie_x64/Dockerfile b/tools/dockerfile/test/node_jessie_x64/Dockerfile index 0ef32109ded..7c0b86acc0c 100644 --- a/tools/dockerfile/test/node_jessie_x64/Dockerfile +++ b/tools/dockerfile/test/node_jessie_x64/Dockerfile @@ -13,7 +13,6 @@ # limitations under the License. FROM debian:jessie -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list # Install Git and basic packages. diff --git a/tools/dockerfile/test/php7_jessie_x64/Dockerfile b/tools/dockerfile/test/php7_jessie_x64/Dockerfile index a32b764cfb9..5cca63d4f02 100644 --- a/tools/dockerfile/test/php7_jessie_x64/Dockerfile +++ b/tools/dockerfile/test/php7_jessie_x64/Dockerfile @@ -13,7 +13,6 @@ # limitations under the License. FROM debian:jessie -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list #================= diff --git a/tools/dockerfile/test/php_jessie_x64/Dockerfile b/tools/dockerfile/test/php_jessie_x64/Dockerfile index ebbbcf524cd..ee54263f96a 100644 --- a/tools/dockerfile/test/php_jessie_x64/Dockerfile +++ b/tools/dockerfile/test/php_jessie_x64/Dockerfile @@ -13,7 +13,6 @@ # limitations under the License. FROM debian:jessie -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list # Install Git and basic packages. diff --git a/tools/dockerfile/test/python_jessie_x64/Dockerfile b/tools/dockerfile/test/python_jessie_x64/Dockerfile index 5ac3af8b26d..367785f42fd 100644 --- a/tools/dockerfile/test/python_jessie_x64/Dockerfile +++ b/tools/dockerfile/test/python_jessie_x64/Dockerfile @@ -13,7 +13,6 @@ # limitations under the License. FROM debian:jessie -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list # Install Git and basic packages. diff --git a/tools/dockerfile/test/ruby_jessie_x64/Dockerfile b/tools/dockerfile/test/ruby_jessie_x64/Dockerfile index ae460756f88..767040907b2 100644 --- a/tools/dockerfile/test/ruby_jessie_x64/Dockerfile +++ b/tools/dockerfile/test/ruby_jessie_x64/Dockerfile @@ -13,7 +13,6 @@ # limitations under the License. FROM debian:jessie -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list # Install Git and basic packages. diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 6902c3aa38b..667b9b3541e 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.21.0-dev +PROJECT_NUMBER = 1.22.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 @@ -927,6 +927,7 @@ include/grpc/support/workaround_list.h \ include/grpcpp/alarm.h \ include/grpcpp/alarm_impl.h \ include/grpcpp/channel.h \ +include/grpcpp/channel_impl.h \ include/grpcpp/client_context.h \ include/grpcpp/completion_queue.h \ include/grpcpp/create_channel.h \ @@ -958,6 +959,7 @@ include/grpcpp/impl/codegen/client_context.h \ include/grpcpp/impl/codegen/client_interceptor.h \ include/grpcpp/impl/codegen/client_unary_call.h \ include/grpcpp/impl/codegen/completion_queue.h \ +include/grpcpp/impl/codegen/completion_queue_impl.h \ include/grpcpp/impl/codegen/completion_queue_tag.h \ include/grpcpp/impl/codegen/config.h \ include/grpcpp/impl/codegen/config_protobuf.h \ @@ -1008,18 +1010,21 @@ include/grpcpp/security/auth_context.h \ include/grpcpp/security/auth_metadata_processor.h \ include/grpcpp/security/auth_metadata_processor_impl.h \ include/grpcpp/security/credentials.h \ +include/grpcpp/security/credentials_impl.h \ include/grpcpp/security/server_credentials.h \ include/grpcpp/security/server_credentials_impl.h \ include/grpcpp/server.h \ include/grpcpp/server_builder.h \ include/grpcpp/server_builder_impl.h \ include/grpcpp/server_context.h \ +include/grpcpp/server_impl.h \ include/grpcpp/server_posix.h \ include/grpcpp/server_posix_impl.h \ include/grpcpp/support/async_stream.h \ include/grpcpp/support/async_unary_call.h \ include/grpcpp/support/byte_buffer.h \ include/grpcpp/support/channel_arguments.h \ +include/grpcpp/support/channel_arguments_impl.h \ include/grpcpp/support/client_callback.h \ include/grpcpp/support/client_interceptor.h \ include/grpcpp/support/config.h \ diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index ed0974fdb2b..f4e6caa418a 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.21.0-dev +PROJECT_NUMBER = 1.22.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 @@ -928,6 +928,7 @@ include/grpc/support/workaround_list.h \ include/grpcpp/alarm.h \ include/grpcpp/alarm_impl.h \ include/grpcpp/channel.h \ +include/grpcpp/channel_impl.h \ include/grpcpp/client_context.h \ include/grpcpp/completion_queue.h \ include/grpcpp/create_channel.h \ @@ -959,6 +960,7 @@ include/grpcpp/impl/codegen/client_context.h \ include/grpcpp/impl/codegen/client_interceptor.h \ include/grpcpp/impl/codegen/client_unary_call.h \ include/grpcpp/impl/codegen/completion_queue.h \ +include/grpcpp/impl/codegen/completion_queue_impl.h \ include/grpcpp/impl/codegen/completion_queue_tag.h \ include/grpcpp/impl/codegen/config.h \ include/grpcpp/impl/codegen/config_protobuf.h \ @@ -1010,18 +1012,21 @@ include/grpcpp/security/auth_context.h \ include/grpcpp/security/auth_metadata_processor.h \ include/grpcpp/security/auth_metadata_processor_impl.h \ include/grpcpp/security/credentials.h \ +include/grpcpp/security/credentials_impl.h \ include/grpcpp/security/server_credentials.h \ include/grpcpp/security/server_credentials_impl.h \ include/grpcpp/server.h \ include/grpcpp/server_builder.h \ include/grpcpp/server_builder_impl.h \ include/grpcpp/server_context.h \ +include/grpcpp/server_impl.h \ include/grpcpp/server_posix.h \ include/grpcpp/server_posix_impl.h \ include/grpcpp/support/async_stream.h \ include/grpcpp/support/async_unary_call.h \ include/grpcpp/support/byte_buffer.h \ include/grpcpp/support/channel_arguments.h \ +include/grpcpp/support/channel_arguments_impl.h \ include/grpcpp/support/client_callback.h \ include/grpcpp/support/client_interceptor.h \ include/grpcpp/support/config.h \ @@ -1082,9 +1087,14 @@ src/core/lib/gpr/tls_pthread.h \ src/core/lib/gpr/tmpfile.h \ src/core/lib/gpr/useful.h \ src/core/lib/gprpp/abstract.h \ +src/core/lib/gprpp/arena.h \ src/core/lib/gprpp/atomic.h \ src/core/lib/gprpp/debug_location.h \ src/core/lib/gprpp/fork.h \ +src/core/lib/gprpp/global_config.h \ +src/core/lib/gprpp/global_config_custom.h \ +src/core/lib/gprpp/global_config_env.h \ +src/core/lib/gprpp/global_config_generic.h \ src/core/lib/gprpp/inlined_vector.h \ src/core/lib/gprpp/manual_constructor.h \ src/core/lib/gprpp/map.h \ @@ -1102,12 +1112,15 @@ src/core/lib/http/parser.h \ src/core/lib/iomgr/block_annotate.h \ src/core/lib/iomgr/buffer_list.h \ src/core/lib/iomgr/call_combiner.h \ +src/core/lib/iomgr/cfstream_handle.h \ src/core/lib/iomgr/closure.h \ src/core/lib/iomgr/combiner.h \ src/core/lib/iomgr/dynamic_annotations.h \ src/core/lib/iomgr/endpoint.h \ +src/core/lib/iomgr/endpoint_cfstream.h \ src/core/lib/iomgr/endpoint_pair.h \ src/core/lib/iomgr/error.h \ +src/core/lib/iomgr/error_cfstream.h \ src/core/lib/iomgr/error_internal.h \ src/core/lib/iomgr/ev_epoll1_linux.h \ src/core/lib/iomgr/ev_epollex_linux.h \ @@ -1175,6 +1188,7 @@ src/core/lib/slice/percent_encoding.h \ src/core/lib/slice/slice_hash_table.h \ src/core/lib/slice/slice_internal.h \ src/core/lib/slice/slice_string_helpers.h \ +src/core/lib/slice/slice_utils.h \ src/core/lib/slice/slice_weak_hash_table.h \ src/core/lib/surface/api_trace.h \ src/core/lib/surface/call.h \ @@ -1237,6 +1251,8 @@ src/cpp/server/channel_argument_option.cc \ src/cpp/server/create_default_thread_pool.cc \ src/cpp/server/dynamic_thread_pool.cc \ src/cpp/server/dynamic_thread_pool.h \ +src/cpp/server/external_connection_acceptor_impl.cc \ +src/cpp/server/external_connection_acceptor_impl.h \ src/cpp/server/health/default_health_check_service.cc \ src/cpp/server/health/default_health_check_service.h \ src/cpp/server/health/health_check_service.cc \ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index dad6c98269d..2c20d69e6e3 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -942,13 +942,17 @@ src/core/ext/filters/client_channel/resolver/README.md \ src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h \ +src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc \ +src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc \ +src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc \ +src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h \ src/core/ext/filters/client_channel/resolver/dns/native/README.md \ src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc \ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \ @@ -1110,7 +1114,6 @@ src/core/lib/debug/trace.h \ src/core/lib/gpr/README.md \ src/core/lib/gpr/alloc.cc \ src/core/lib/gpr/alloc.h \ -src/core/lib/gpr/arena.cc \ src/core/lib/gpr/arena.h \ src/core/lib/gpr/atm.cc \ src/core/lib/gpr/cpu_iphone.cc \ @@ -1160,10 +1163,17 @@ src/core/lib/gpr/useful.h \ src/core/lib/gpr/wrap_memcpy.cc \ src/core/lib/gprpp/README.md \ src/core/lib/gprpp/abstract.h \ +src/core/lib/gprpp/arena.cc \ +src/core/lib/gprpp/arena.h \ src/core/lib/gprpp/atomic.h \ src/core/lib/gprpp/debug_location.h \ src/core/lib/gprpp/fork.cc \ src/core/lib/gprpp/fork.h \ +src/core/lib/gprpp/global_config.h \ +src/core/lib/gprpp/global_config_custom.h \ +src/core/lib/gprpp/global_config_env.cc \ +src/core/lib/gprpp/global_config_env.h \ +src/core/lib/gprpp/global_config_generic.h \ src/core/lib/gprpp/inlined_vector.h \ src/core/lib/gprpp/manual_constructor.h \ src/core/lib/gprpp/map.h \ @@ -1190,18 +1200,24 @@ src/core/lib/iomgr/buffer_list.cc \ src/core/lib/iomgr/buffer_list.h \ src/core/lib/iomgr/call_combiner.cc \ src/core/lib/iomgr/call_combiner.h \ +src/core/lib/iomgr/cfstream_handle.cc \ +src/core/lib/iomgr/cfstream_handle.h \ src/core/lib/iomgr/closure.h \ src/core/lib/iomgr/combiner.cc \ src/core/lib/iomgr/combiner.h \ src/core/lib/iomgr/dynamic_annotations.h \ src/core/lib/iomgr/endpoint.cc \ src/core/lib/iomgr/endpoint.h \ +src/core/lib/iomgr/endpoint_cfstream.cc \ +src/core/lib/iomgr/endpoint_cfstream.h \ src/core/lib/iomgr/endpoint_pair.h \ src/core/lib/iomgr/endpoint_pair_posix.cc \ src/core/lib/iomgr/endpoint_pair_uv.cc \ src/core/lib/iomgr/endpoint_pair_windows.cc \ src/core/lib/iomgr/error.cc \ src/core/lib/iomgr/error.h \ +src/core/lib/iomgr/error_cfstream.cc \ +src/core/lib/iomgr/error_cfstream.h \ src/core/lib/iomgr/error_internal.h \ src/core/lib/iomgr/ev_epoll1_linux.cc \ src/core/lib/iomgr/ev_epoll1_linux.h \ @@ -1237,6 +1253,7 @@ src/core/lib/iomgr/iomgr_internal.cc \ src/core/lib/iomgr/iomgr_internal.h \ src/core/lib/iomgr/iomgr_posix.cc \ src/core/lib/iomgr/iomgr_posix.h \ +src/core/lib/iomgr/iomgr_posix_cfstream.cc \ src/core/lib/iomgr/iomgr_uv.cc \ src/core/lib/iomgr/iomgr_windows.cc \ src/core/lib/iomgr/is_epollexclusive_available.cc \ @@ -1292,6 +1309,7 @@ src/core/lib/iomgr/socket_windows.h \ src/core/lib/iomgr/sys_epoll_wrapper.h \ src/core/lib/iomgr/tcp_client.cc \ src/core/lib/iomgr/tcp_client.h \ +src/core/lib/iomgr/tcp_client_cfstream.cc \ src/core/lib/iomgr/tcp_client_custom.cc \ src/core/lib/iomgr/tcp_client_posix.cc \ src/core/lib/iomgr/tcp_client_posix.h \ @@ -1431,6 +1449,7 @@ src/core/lib/slice/slice_intern.cc \ src/core/lib/slice/slice_internal.h \ src/core/lib/slice/slice_string_helpers.cc \ src/core/lib/slice/slice_string_helpers.h \ +src/core/lib/slice/slice_utils.h \ src/core/lib/slice/slice_weak_hash_table.h \ src/core/lib/surface/README.md \ src/core/lib/surface/api_trace.cc \ diff --git a/tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc b/tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc index ff5593e031a..bd8c30041c2 100644 --- a/tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc +++ b/tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc @@ -19,12 +19,6 @@ ulimit -n 32768 ulimit -c unlimited -# Performance PR testing needs GH API key and PR metadata to comment results -if [ -n "$KOKORO_GITHUB_PULL_REQUEST_NUMBER" ]; then - sudo apt-get install -y jq - export ghprbTargetBranch=$(curl -s https://api.github.com/repos/grpc/grpc/pulls/$KOKORO_GITHUB_PULL_REQUEST_NUMBER | jq -r .base.ref) -fi - sudo pip install tabulate # Python dependencies for tools/run_tests/python_utils/check_on_pr.py diff --git a/tools/internal_ci/helper_scripts/prepare_build_macos_rc b/tools/internal_ci/helper_scripts/prepare_build_macos_rc index e9ec07cd0f9..b8f37560148 100644 --- a/tools/internal_ci/helper_scripts/prepare_build_macos_rc +++ b/tools/internal_ci/helper_scripts/prepare_build_macos_rc @@ -25,10 +25,7 @@ export GOOGLE_APPLICATION_CREDENTIALS=${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db3 # If this is a PR using RUN_TESTS_FLAGS var, then add flags to filter tests if [ -n "$KOKORO_GITHUB_PULL_REQUEST_NUMBER" ]; then - brew update - brew install jq || brew upgrade jq - ghprbTargetBranch=$(curl -s https://api.github.com/repos/grpc/grpc/pulls/$KOKORO_GITHUB_PULL_REQUEST_NUMBER | jq -r .base.ref) - export RUN_TESTS_FLAGS="$RUN_TESTS_FLAGS --filter_pr_tests --base_branch origin/$ghprbTargetBranch" + export RUN_TESTS_FLAGS="$RUN_TESTS_FLAGS --filter_pr_tests --base_branch origin/$KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH" fi set +ex # rvm script is very verbose and exits with errorcode diff --git a/tools/internal_ci/helper_scripts/prepare_build_windows.bat b/tools/internal_ci/helper_scripts/prepare_build_windows.bat index bee59159331..c27710ffba4 100644 --- a/tools/internal_ci/helper_scripts/prepare_build_windows.bat +++ b/tools/internal_ci/helper_scripts/prepare_build_windows.bat @@ -18,10 +18,7 @@ set PATH=C:\tools\msys64\usr\bin;C:\Python27;%PATH% @rem If this is a PR using RUN_TESTS_FLAGS var, then add flags to filter tests if defined KOKORO_GITHUB_PULL_REQUEST_NUMBER if defined RUN_TESTS_FLAGS ( - chocolatey install -y jq - for /f "usebackq delims=" %%x in (`curl -s https://api.github.com/repos/grpc/grpc/pulls/%KOKORO_GITHUB_PULL_REQUEST_NUMBER% ^| jq -r .base.ref`) do ( - set RUN_TESTS_FLAGS=%RUN_TESTS_FLAGS% --filter_pr_tests --base_branch origin/%%x - ) + set RUN_TESTS_FLAGS=%RUN_TESTS_FLAGS% --filter_pr_tests --base_branch origin/%KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH% ) @rem Update DNS settings to: diff --git a/tools/internal_ci/linux/grpc_basictests_csharp.cfg b/tools/internal_ci/linux/grpc_basictests_csharp.cfg new file mode 100644 index 00000000000..017e929beff --- /dev/null +++ b/tools/internal_ci/linux/grpc_basictests_csharp.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests linux csharp --inner_jobs 16 -j 2 --internal_ci --bq_result_table aggregate_results" +} diff --git a/tools/internal_ci/linux/grpc_basictests_node.cfg b/tools/internal_ci/linux/grpc_basictests_node.cfg new file mode 100644 index 00000000000..d7b35a04719 --- /dev/null +++ b/tools/internal_ci/linux/grpc_basictests_node.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests linux grpc-node --inner_jobs 16 -j 2 --internal_ci --bq_result_table aggregate_results" +} diff --git a/tools/internal_ci/linux/grpc_basictests_php.cfg b/tools/internal_ci/linux/grpc_basictests_php.cfg new file mode 100644 index 00000000000..80aa0dc87bb --- /dev/null +++ b/tools/internal_ci/linux/grpc_basictests_php.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests linux php --inner_jobs 16 -j 2 --internal_ci --bq_result_table aggregate_results" +} diff --git a/tools/internal_ci/linux/grpc_basictests_python.cfg b/tools/internal_ci/linux/grpc_basictests_python.cfg new file mode 100644 index 00000000000..444dba9f4df --- /dev/null +++ b/tools/internal_ci/linux/grpc_basictests_python.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests linux python --inner_jobs 16 -j 2 --internal_ci --bq_result_table aggregate_results" +} diff --git a/tools/internal_ci/linux/grpc_basictests_ruby.cfg b/tools/internal_ci/linux/grpc_basictests_ruby.cfg new file mode 100644 index 00000000000..336aa469958 --- /dev/null +++ b/tools/internal_ci/linux/grpc_basictests_ruby.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests linux ruby --inner_jobs 16 -j 2 --internal_ci --bq_result_table aggregate_results" +} diff --git a/tools/internal_ci/linux/grpc_bazel_build_in_docker.sh b/tools/internal_ci/linux/grpc_bazel_build_in_docker.sh index 3dd0167b7c0..24598f43f02 100755 --- a/tools/internal_ci/linux/grpc_bazel_build_in_docker.sh +++ b/tools/internal_ci/linux/grpc_bazel_build_in_docker.sh @@ -24,5 +24,4 @@ git clone /var/local/jenkins/grpc /var/local/git/grpc && git submodule update --init --reference /var/local/jenkins/grpc/${name} \ ${name}') cd /var/local/git/grpc -#TODO(yfen): add back examples/... to build targets once python rules issues are resolved -bazel build --spawn_strategy=standalone --genrule_strategy=standalone :all test/... +bazel build --spawn_strategy=standalone --genrule_strategy=standalone :all test/... examples/... diff --git a/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh b/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh index dd34eac7b38..93399f81e79 100755 --- a/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh +++ b/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh @@ -15,12 +15,6 @@ set -ex -# A temporary solution to give Kokoro credentials. -# The file name 4321_grpc-testing-service needs to match auth_credential in -# the build config. -mkdir -p ${KOKORO_KEYSTORE_DIR} -cp ${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json ${KOKORO_KEYSTORE_DIR}/4321_grpc-testing-service - # Download bazel temp_dir="$(mktemp -d)" wget -q https://github.com/bazelbuild/bazel/releases/download/0.23.2/bazel-0.23.2-linux-x86_64 -O "${temp_dir}/bazel" @@ -45,6 +39,7 @@ bazel \ test \ --invocation_id="${BAZEL_INVOCATION_ID}" \ --workspace_status_command=tools/remote_build/workspace_status_kokoro.sh \ + --google_credentials="${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json" \ $@ \ -- //test/... || FAILED="true" diff --git a/tools/internal_ci/linux/grpc_bazel_rbe_asan.cfg b/tools/internal_ci/linux/grpc_bazel_rbe_asan.cfg new file mode 100644 index 00000000000..21afbd04ee3 --- /dev/null +++ b/tools/internal_ci/linux/grpc_bazel_rbe_asan.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/grpc_asan_on_foundry.sh" +timeout_mins: 60 + +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/resultstore_api_key" + +bazel_setting { + # In order for Kokoro to recognize this as a bazel build and publish the bazel resultstore link, + # the bazel_setting section needs to be present and "upsalite_frontend_address" needs to be + # set. The rest of configuration from bazel_setting is unused (we configure everything when bazel + # command is invoked). + upsalite_frontend_address: "https://source.cloud.google.com" +} diff --git a/tools/internal_ci/linux/grpc_bazel_rbe_dbg.cfg b/tools/internal_ci/linux/grpc_bazel_rbe_dbg.cfg new file mode 100644 index 00000000000..e80321b9a8a --- /dev/null +++ b/tools/internal_ci/linux/grpc_bazel_rbe_dbg.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh" +timeout_mins: 60 + +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/resultstore_api_key" + +bazel_setting { + # In order for Kokoro to recognize this as a bazel build and publish the bazel resultstore link, + # the bazel_setting section needs to be present and "upsalite_frontend_address" needs to be + # set. The rest of configuration from bazel_setting is unused (we configure everything when bazel + # command is invoked). + upsalite_frontend_address: "https://source.cloud.google.com" +} diff --git a/tools/internal_ci/linux/grpc_bazel_rbe_incompatible_changes.cfg b/tools/internal_ci/linux/grpc_bazel_rbe_incompatible_changes.cfg new file mode 100644 index 00000000000..ee883392f4b --- /dev/null +++ b/tools/internal_ci/linux/grpc_bazel_rbe_incompatible_changes.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/grpc_bazel_rbe_incompatible_changes.sh" +timeout_mins: 60 + +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/resultstore_api_key" + +bazel_setting { + # In order for Kokoro to recognize this as a bazel build and publish the bazel resultstore link, + # the bazel_setting section needs to be present and "upsalite_frontend_address" needs to be + # set. The rest of configuration from bazel_setting is unused (we configure everything when bazel + # command is invoked). + upsalite_frontend_address: "https://source.cloud.google.com" +} diff --git a/tools/internal_ci/linux/grpc_bazel_rbe_msan.cfg b/tools/internal_ci/linux/grpc_bazel_rbe_msan.cfg new file mode 100644 index 00000000000..be939bbff55 --- /dev/null +++ b/tools/internal_ci/linux/grpc_bazel_rbe_msan.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/grpc_msan_on_foundry.sh" +timeout_mins: 60 + +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/resultstore_api_key" + +bazel_setting { + # In order for Kokoro to recognize this as a bazel build and publish the bazel resultstore link, + # the bazel_setting section needs to be present and "upsalite_frontend_address" needs to be + # set. The rest of configuration from bazel_setting is unused (we configure everything when bazel + # command is invoked). + upsalite_frontend_address: "https://source.cloud.google.com" +} diff --git a/tools/internal_ci/linux/grpc_bazel_rbe_opt.cfg b/tools/internal_ci/linux/grpc_bazel_rbe_opt.cfg new file mode 100644 index 00000000000..48a6d91f123 --- /dev/null +++ b/tools/internal_ci/linux/grpc_bazel_rbe_opt.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh" +timeout_mins: 60 + +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/resultstore_api_key" + +bazel_setting { + # In order for Kokoro to recognize this as a bazel build and publish the bazel resultstore link, + # the bazel_setting section needs to be present and "upsalite_frontend_address" needs to be + # set. The rest of configuration from bazel_setting is unused (we configure everything when bazel + # command is invoked). + upsalite_frontend_address: "https://source.cloud.google.com" +} \ No newline at end of file diff --git a/tools/internal_ci/linux/grpc_bazel_rbe_tsan.cfg b/tools/internal_ci/linux/grpc_bazel_rbe_tsan.cfg new file mode 100644 index 00000000000..f45a4c2da2d --- /dev/null +++ b/tools/internal_ci/linux/grpc_bazel_rbe_tsan.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/grpc_tsan_on_foundry.sh" +timeout_mins: 60 + +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/resultstore_api_key" + +bazel_setting { + # In order for Kokoro to recognize this as a bazel build and publish the bazel resultstore link, + # the bazel_setting section needs to be present and "upsalite_frontend_address" needs to be + # set. The rest of configuration from bazel_setting is unused (we configure everything when bazel + # command is invoked). + upsalite_frontend_address: "https://source.cloud.google.com" +} diff --git a/tools/internal_ci/linux/grpc_bazel_rbe_ubsan.cfg b/tools/internal_ci/linux/grpc_bazel_rbe_ubsan.cfg new file mode 100644 index 00000000000..f0cf94ad142 --- /dev/null +++ b/tools/internal_ci/linux/grpc_bazel_rbe_ubsan.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh" +timeout_mins: 60 + +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/resultstore_api_key" + +bazel_setting { + # In order for Kokoro to recognize this as a bazel build and publish the bazel resultstore link, + # the bazel_setting section needs to be present and "upsalite_frontend_address" needs to be + # set. The rest of configuration from bazel_setting is unused (we configure everything when bazel + # command is invoked). + upsalite_frontend_address: "https://source.cloud.google.com" +} diff --git a/tools/internal_ci/linux/grpc_flaky_network_in_docker.sh b/tools/internal_ci/linux/grpc_flaky_network_in_docker.sh index 7fc8f146727..d574638d3ef 100755 --- a/tools/internal_ci/linux/grpc_flaky_network_in_docker.sh +++ b/tools/internal_ci/linux/grpc_flaky_network_in_docker.sh @@ -28,4 +28,4 @@ cd /var/local/git/grpc/test/cpp/end2end # iptables is used to drop traffic between client and server apt-get install -y iptables -bazel test --spawn_strategy=standalone --genrule_strategy=standalone --test_output=all :flaky_network_test --test_env=GRPC_VERBOSITY=debug --test_env=GRPC_TRACE=channel,client_channel,call_error,connectivity_state,tcp +bazel test --spawn_strategy=standalone --genrule_strategy=standalone --test_output=all --test_timeout=1200 :flaky_network_test --test_env=GRPC_TRACE=http --test_env=GRPC_VERBOSITY=DEBUG diff --git a/tools/internal_ci/linux/grpc_microbenchmark_diff.sh b/tools/internal_ci/linux/grpc_microbenchmark_diff.sh index 9834aaa0534..c03383d1461 100755 --- a/tools/internal_ci/linux/grpc_microbenchmark_diff.sh +++ b/tools/internal_ci/linux/grpc_microbenchmark_diff.sh @@ -26,9 +26,9 @@ source tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc tools/run_tests/start_port_server.py tools/internal_ci/linux/run_if_c_cpp_modified.sh tools/profiling/bloat/bloat_diff.py \ - -d origin/$ghprbTargetBranch || FAILED="true" + -d "origin/$KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH" || FAILED="true" tools/internal_ci/linux/run_if_c_cpp_modified.sh tools/profiling/microbenchmarks/bm_diff/bm_main.py \ - -d origin/$ghprbTargetBranch \ + -d "origin/$KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH" \ -b $BENCHMARKS_TO_RUN || FAILED="true" # kill port_server.py to prevent the build from hanging diff --git a/tools/internal_ci/linux/grpc_publish_packages.cfg b/tools/internal_ci/linux/grpc_publish_packages.cfg index dc9fe7d0a7a..54e03a94b60 100644 --- a/tools/internal_ci/linux/grpc_publish_packages.cfg +++ b/tools/internal_ci/linux/grpc_publish_packages.cfg @@ -24,3 +24,5 @@ action { regex: "github/grpc/artifacts/**" } } + +gfile_resources: "/bigstore/grpc-testing-secrets/nuget_credentials/artifactory_grpc_nuget_dev_api_key" diff --git a/tools/internal_ci/linux/grpc_publish_packages.sh b/tools/internal_ci/linux/grpc_publish_packages.sh index 14492301cc9..87684214d84 100755 --- a/tools/internal_ci/linux/grpc_publish_packages.sh +++ b/tools/internal_ci/linux/grpc_publish_packages.sh @@ -233,3 +233,16 @@ gsutil -m cp -r "$LOCAL_STAGING_TEMPDIR/${BUILD_RELPATH%%/*}" "$GCS_ARCHIVE_ROOT ) # Upload the new /index.xml gsutil -h "Content-Type:application/xml" cp "$NEW_INDEX" "$GCS_INDEX" + +# Upload C# nugets to the dev nuget feed +pushd "$UNZIPPED_CSHARP_PACKAGES" +docker pull mcr.microsoft.com/dotnet/core/sdk:2.1 +for nugetfile in *.nupkg +do + echo "Going to push $nugetfile" + # use nuget from a docker container to push the nupkg + set +x # IMPORTANT: avoid revealing the nuget api key by the command echo + docker run -v "$(pwd):/nugets:ro" --rm=true mcr.microsoft.com/dotnet/core/sdk:2.1 bash -c "dotnet nuget push /nugets/$nugetfile -k $(cat ${KOKORO_GFILE_DIR}/artifactory_grpc_nuget_dev_api_key) --source https://grpc.jfrog.io/grpc/api/nuget/v3/grpc-nuget-dev" + set -ex +done +popd diff --git a/tools/internal_ci/linux/grpc_python_bazel_test_in_docker.sh b/tools/internal_ci/linux/grpc_python_bazel_test_in_docker.sh index 3ca4673ca08..d844cff7f9a 100755 --- a/tools/internal_ci/linux/grpc_python_bazel_test_in_docker.sh +++ b/tools/internal_ci/linux/grpc_python_bazel_test_in_docker.sh @@ -23,10 +23,9 @@ git clone /var/local/jenkins/grpc /var/local/git/grpc (cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \ && git submodule update --init --reference /var/local/jenkins/grpc/${name} \ ${name}') -#TODO(yfen): temporarily disabled all python bazel tests due to incompatibility with bazel 0.23.2 -#cd /var/local/git/grpc/test -#bazel test --spawn_strategy=standalone --genrule_strategy=standalone --test_output=errors //src/python/... -#bazel test --spawn_strategy=standalone --genrule_strategy=standalone --test_output=errors //examples/python/... -#bazel clean --expunge -#bazel test --config=python3 --spawn_strategy=standalone --genrule_strategy=standalone --test_output=errors //src/python/... -#bazel test --config=python3 --spawn_strategy=standalone --genrule_strategy=standalone --test_output=errors //examples/python/... +cd /var/local/git/grpc/test +bazel test --spawn_strategy=standalone --genrule_strategy=standalone --test_output=errors //src/python/... +bazel test --spawn_strategy=standalone --genrule_strategy=standalone --test_output=errors //examples/python/... +bazel clean --expunge +bazel test --config=python3 --spawn_strategy=standalone --genrule_strategy=standalone --test_output=errors //src/python/... +bazel test --config=python3 --spawn_strategy=standalone --genrule_strategy=standalone --test_output=errors //examples/python/... diff --git a/tools/internal_ci/linux/grpc_run_tests_matrix.sh b/tools/internal_ci/linux/grpc_run_tests_matrix.sh index f9acd814ae8..a0ce71aeb7d 100755 --- a/tools/internal_ci/linux/grpc_run_tests_matrix.sh +++ b/tools/internal_ci/linux/grpc_run_tests_matrix.sh @@ -22,10 +22,7 @@ source tools/internal_ci/helper_scripts/prepare_build_linux_rc # If this is a PR using RUN_TESTS_FLAGS var, then add flags to filter tests if [ -n "$KOKORO_GITHUB_PULL_REQUEST_NUMBER" ] && [ -n "$RUN_TESTS_FLAGS" ]; then - sudo apt-get update - sudo apt-get install -y jq - ghprbTargetBranch=$(curl -s https://api.github.com/repos/grpc/grpc/pulls/$KOKORO_GITHUB_PULL_REQUEST_NUMBER | jq -r .base.ref) - export RUN_TESTS_FLAGS="$RUN_TESTS_FLAGS --filter_pr_tests --base_branch origin/$ghprbTargetBranch" + export RUN_TESTS_FLAGS="$RUN_TESTS_FLAGS --filter_pr_tests --base_branch origin/$KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH" fi tools/run_tests/run_tests_matrix.py $RUN_TESTS_FLAGS || FAILED="true" diff --git a/tools/internal_ci/linux/grpc_trickle_diff.sh b/tools/internal_ci/linux/grpc_trickle_diff.sh index 4ed1b73f9e8..49c3d4b2db0 100755 --- a/tools/internal_ci/linux/grpc_trickle_diff.sh +++ b/tools/internal_ci/linux/grpc_trickle_diff.sh @@ -26,7 +26,7 @@ source tools/internal_ci/helper_scripts/prepare_build_linux_perf_rc tools/run_tests/start_port_server.py tools/internal_ci/linux/run_if_c_cpp_modified.sh tools/profiling/microbenchmarks/bm_diff/bm_main.py \ - -d origin/$ghprbTargetBranch \ + -d "origin/$KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH" \ -b bm_fullstack_trickle \ -l 4 \ -t $BENCHMARKS_TO_RUN \ diff --git a/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_dbg.cfg b/tools/internal_ci/linux/pull_request/grpc_basictests_csharp.cfg similarity index 85% rename from tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_dbg.cfg rename to tools/internal_ci/linux/pull_request/grpc_basictests_csharp.cfg index 8a67d28ce4c..6a7029d9f83 100644 --- a/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_dbg.cfg +++ b/tools/internal_ci/linux/pull_request/grpc_basictests_csharp.cfg @@ -1,4 +1,4 @@ -# Copyright 2017 gRPC authors. +# Copyright 2019 The gRPC Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ # Location of the continuous shell script in repository. build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh" -timeout_mins: 240 +timeout_mins: 60 action { define_artifacts { regex: "**/*sponge_log.*" @@ -26,5 +26,5 @@ action { env_vars { key: "RUN_TESTS_FLAGS" - value: "-f basictests linux corelang dbg --inner_jobs 16 -j 1 --internal_ci --max_time=3600" + value: "-f basictests linux csharp --inner_jobs 16 -j 2 --internal_ci --max_time=3600" } diff --git a/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_opt.cfg b/tools/internal_ci/linux/pull_request/grpc_basictests_node.cfg similarity index 85% rename from tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_opt.cfg rename to tools/internal_ci/linux/pull_request/grpc_basictests_node.cfg index a681978b6e2..a0c67cc136c 100644 --- a/tools/internal_ci/linux/pull_request/grpc_basictests_c_cpp_opt.cfg +++ b/tools/internal_ci/linux/pull_request/grpc_basictests_node.cfg @@ -1,4 +1,4 @@ -# Copyright 2017 gRPC authors. +# Copyright 2019 The gRPC Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ # Location of the continuous shell script in repository. build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh" -timeout_mins: 240 +timeout_mins: 60 action { define_artifacts { regex: "**/*sponge_log.*" @@ -26,5 +26,5 @@ action { env_vars { key: "RUN_TESTS_FLAGS" - value: "-f basictests linux corelang opt --inner_jobs 16 -j 1 --internal_ci --max_time=3600" + value: "-f basictests linux grpc-node --inner_jobs 16 -j 2 --internal_ci --max_time=3600" } diff --git a/tools/internal_ci/linux/pull_request/grpc_basictests_php.cfg b/tools/internal_ci/linux/pull_request/grpc_basictests_php.cfg new file mode 100644 index 00000000000..c844fcfae00 --- /dev/null +++ b/tools/internal_ci/linux/pull_request/grpc_basictests_php.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests linux php --inner_jobs 16 -j 2 --internal_ci --max_time=3600" +} diff --git a/tools/internal_ci/linux/pull_request/grpc_basictests_python.cfg b/tools/internal_ci/linux/pull_request/grpc_basictests_python.cfg new file mode 100644 index 00000000000..b4e91c2a7e2 --- /dev/null +++ b/tools/internal_ci/linux/pull_request/grpc_basictests_python.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests linux python --inner_jobs 16 -j 2 --internal_ci --max_time=3600" +} diff --git a/tools/internal_ci/linux/pull_request/grpc_basictests_ruby.cfg b/tools/internal_ci/linux/pull_request/grpc_basictests_ruby.cfg new file mode 100644 index 00000000000..49d3dad592e --- /dev/null +++ b/tools/internal_ci/linux/pull_request/grpc_basictests_ruby.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/grpc_run_tests_matrix.sh" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests linux ruby --inner_jobs 16 -j 2 --internal_ci --max_time=3600" +} diff --git a/tools/internal_ci/linux/pull_request/grpc_bazel_rbe_asan.cfg b/tools/internal_ci/linux/pull_request/grpc_bazel_rbe_asan.cfg new file mode 100644 index 00000000000..f978c730b7c --- /dev/null +++ b/tools/internal_ci/linux/pull_request/grpc_bazel_rbe_asan.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/pull_request/grpc_asan_on_foundry.sh" +timeout_mins: 60 + +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/resultstore_api_key" + +bazel_setting { + # In order for Kokoro to recognize this as a bazel build and publish the bazel resultstore link, + # the bazel_setting section needs to be present and "upsalite_frontend_address" needs to be + # set. The rest of configuration from bazel_setting is unused (we configure everything when bazel + # command is invoked). + upsalite_frontend_address: "https://source.cloud.google.com" +} diff --git a/tools/internal_ci/linux/pull_request/grpc_bazel_rbe_dbg.cfg b/tools/internal_ci/linux/pull_request/grpc_bazel_rbe_dbg.cfg new file mode 100644 index 00000000000..ab47a30b247 --- /dev/null +++ b/tools/internal_ci/linux/pull_request/grpc_bazel_rbe_dbg.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_dbg.sh" +timeout_mins: 60 + +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/resultstore_api_key" + +bazel_setting { + # In order for Kokoro to recognize this as a bazel build and publish the bazel resultstore link, + # the bazel_setting section needs to be present and "upsalite_frontend_address" needs to be + # set. The rest of configuration from bazel_setting is unused (we configure everything when bazel + # command is invoked). + upsalite_frontend_address: "https://source.cloud.google.com" +} \ No newline at end of file diff --git a/tools/internal_ci/linux/pull_request/grpc_bazel_rbe_msan.cfg b/tools/internal_ci/linux/pull_request/grpc_bazel_rbe_msan.cfg new file mode 100644 index 00000000000..24b19f23e62 --- /dev/null +++ b/tools/internal_ci/linux/pull_request/grpc_bazel_rbe_msan.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/pull_request/grpc_msan_on_foundry.sh" +timeout_mins: 60 + +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/resultstore_api_key" + +bazel_setting { + # In order for Kokoro to recognize this as a bazel build and publish the bazel resultstore link, + # the bazel_setting section needs to be present and "upsalite_frontend_address" needs to be + # set. The rest of configuration from bazel_setting is unused (we configure everything when bazel + # command is invoked). + upsalite_frontend_address: "https://source.cloud.google.com" +} diff --git a/tools/internal_ci/linux/pull_request/grpc_bazel_rbe_opt.cfg b/tools/internal_ci/linux/pull_request/grpc_bazel_rbe_opt.cfg new file mode 100644 index 00000000000..65395f0bf6f --- /dev/null +++ b/tools/internal_ci/linux/pull_request/grpc_bazel_rbe_opt.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/pull_request/grpc_bazel_on_foundry_opt.sh" +timeout_mins: 60 + +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/resultstore_api_key" + +bazel_setting { + # In order for Kokoro to recognize this as a bazel build and publish the bazel resultstore link, + # the bazel_setting section needs to be present and "upsalite_frontend_address" needs to be + # set. The rest of configuration from bazel_setting is unused (we configure everything when bazel + # command is invoked). + upsalite_frontend_address: "https://source.cloud.google.com" +} \ No newline at end of file diff --git a/tools/internal_ci/linux/pull_request/grpc_bazel_rbe_tsan.cfg b/tools/internal_ci/linux/pull_request/grpc_bazel_rbe_tsan.cfg new file mode 100644 index 00000000000..cf65606f3cd --- /dev/null +++ b/tools/internal_ci/linux/pull_request/grpc_bazel_rbe_tsan.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/pull_request/grpc_tsan_on_foundry.sh" +timeout_mins: 60 + +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/resultstore_api_key" + +bazel_setting { + # In order for Kokoro to recognize this as a bazel build and publish the bazel resultstore link, + # the bazel_setting section needs to be present and "upsalite_frontend_address" needs to be + # set. The rest of configuration from bazel_setting is unused (we configure everything when bazel + # command is invoked). + upsalite_frontend_address: "https://source.cloud.google.com" +} diff --git a/tools/internal_ci/linux/pull_request/grpc_bazel_rbe_ubsan.cfg b/tools/internal_ci/linux/pull_request/grpc_bazel_rbe_ubsan.cfg new file mode 100644 index 00000000000..a943b89509d --- /dev/null +++ b/tools/internal_ci/linux/pull_request/grpc_bazel_rbe_ubsan.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/pull_request/grpc_ubsan_on_foundry.sh" +timeout_mins: 60 + +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/resultstore_api_key" + +bazel_setting { + # In order for Kokoro to recognize this as a bazel build and publish the bazel resultstore link, + # the bazel_setting section needs to be present and "upsalite_frontend_address" needs to be + # set. The rest of configuration from bazel_setting is unused (we configure everything when bazel + # command is invoked). + upsalite_frontend_address: "https://source.cloud.google.com" +} diff --git a/tools/internal_ci/linux/run_if_c_cpp_modified.sh b/tools/internal_ci/linux/run_if_c_cpp_modified.sh index 736d7594234..2414dcca7c9 100755 --- a/tools/internal_ci/linux/run_if_c_cpp_modified.sh +++ b/tools/internal_ci/linux/run_if_c_cpp_modified.sh @@ -20,13 +20,11 @@ set -ex # Enter the gRPC repo root cd $(dirname $0)/../../.. -# TODO(jtattermusch): the "ghprbTargetBranch" is Jenkins specific and probably -# does not work on kokoro? AFFECTS_C_CPP=`python -c 'import os; \ import sys; \ sys.path.insert(0, "tools/run_tests/python_utils"); \ import filter_pull_request_tests as filter; \ - github_target_branch = os.environ.get("ghprbTargetBranch"); \ + github_target_branch = os.environ.get("KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH"); \ print(filter.affects_c_cpp("origin/%s" % github_target_branch))'` if [ $AFFECTS_C_CPP == "False" ] ; then diff --git a/tools/internal_ci/macos/grpc_basictests_c_cpp.cfg b/tools/internal_ci/macos/grpc_basictests_c_cpp.cfg new file mode 100644 index 00000000000..f16e3e8ee68 --- /dev/null +++ b/tools/internal_ci/macos/grpc_basictests_c_cpp.cfg @@ -0,0 +1,31 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +timeout_mins: 120 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests macos corelang --internal_ci -j 1 --inner_jobs 4 --bq_result_table aggregate_results" +} diff --git a/tools/internal_ci/macos/grpc_basictests_csharp.cfg b/tools/internal_ci/macos/grpc_basictests_csharp.cfg new file mode 100644 index 00000000000..d3e04e71f71 --- /dev/null +++ b/tools/internal_ci/macos/grpc_basictests_csharp.cfg @@ -0,0 +1,31 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests macos csharp --internal_ci -j 1 --inner_jobs 4 --bq_result_table aggregate_results" +} diff --git a/tools/internal_ci/macos/grpc_basictests_node.cfg b/tools/internal_ci/macos/grpc_basictests_node.cfg new file mode 100644 index 00000000000..9dfd6a7b9e8 --- /dev/null +++ b/tools/internal_ci/macos/grpc_basictests_node.cfg @@ -0,0 +1,31 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests macos grpc-node --internal_ci -j 1 --inner_jobs 4 --bq_result_table aggregate_results" +} diff --git a/tools/internal_ci/macos/grpc_basictests_php.cfg b/tools/internal_ci/macos/grpc_basictests_php.cfg new file mode 100644 index 00000000000..091f68efaba --- /dev/null +++ b/tools/internal_ci/macos/grpc_basictests_php.cfg @@ -0,0 +1,31 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests macos php --internal_ci -j 1 --inner_jobs 4 --bq_result_table aggregate_results" +} diff --git a/tools/internal_ci/macos/grpc_basictests_python.cfg b/tools/internal_ci/macos/grpc_basictests_python.cfg new file mode 100644 index 00000000000..ae80ac317ff --- /dev/null +++ b/tools/internal_ci/macos/grpc_basictests_python.cfg @@ -0,0 +1,31 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests macos python --internal_ci -j 1 --inner_jobs 4 --bq_result_table aggregate_results" +} diff --git a/tools/internal_ci/macos/grpc_basictests_ruby.cfg b/tools/internal_ci/macos/grpc_basictests_ruby.cfg new file mode 100644 index 00000000000..3a28f97a54b --- /dev/null +++ b/tools/internal_ci/macos/grpc_basictests_ruby.cfg @@ -0,0 +1,31 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests macos ruby --internal_ci -j 1 --inner_jobs 4 --bq_result_table aggregate_results" +} diff --git a/tools/internal_ci/macos/grpc_ios_binary_size.sh b/tools/internal_ci/macos/grpc_ios_binary_size.sh index ea39b0d6e94..17937a30d41 100755 --- a/tools/internal_ci/macos/grpc_ios_binary_size.sh +++ b/tools/internal_ci/macos/grpc_ios_binary_size.sh @@ -24,4 +24,4 @@ cd $(dirname $0)/../../.. source tools/internal_ci/helper_scripts/prepare_build_macos_rc tools/profiling/ios_bin/binary_size.py \ - -d origin/$ghprbTargetBranch + -d "origin/$KOKORO_GITHUB_PULL_REQUEST_TARGET_BRANCH" diff --git a/tools/internal_ci/macos/pull_request/grpc_basictests_c_cpp.cfg b/tools/internal_ci/macos/pull_request/grpc_basictests_c_cpp.cfg new file mode 100644 index 00000000000..00f402d389b --- /dev/null +++ b/tools/internal_ci/macos/pull_request/grpc_basictests_c_cpp.cfg @@ -0,0 +1,31 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +timeout_mins: 120 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests macos corelang --internal_ci -j 1 --inner_jobs 4 --max_time=3600" +} diff --git a/tools/internal_ci/macos/pull_request/grpc_basictests_csharp.cfg b/tools/internal_ci/macos/pull_request/grpc_basictests_csharp.cfg new file mode 100644 index 00000000000..c9c1403693c --- /dev/null +++ b/tools/internal_ci/macos/pull_request/grpc_basictests_csharp.cfg @@ -0,0 +1,31 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests macos csharp --internal_ci -j 1 --inner_jobs 4 --max_time=3600" +} diff --git a/tools/internal_ci/macos/pull_request/grpc_basictests_node.cfg b/tools/internal_ci/macos/pull_request/grpc_basictests_node.cfg new file mode 100644 index 00000000000..ed729ef5a91 --- /dev/null +++ b/tools/internal_ci/macos/pull_request/grpc_basictests_node.cfg @@ -0,0 +1,31 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests macos grpc-node --internal_ci -j 1 --inner_jobs 4 --max_time=3600" +} diff --git a/tools/internal_ci/macos/pull_request/grpc_basictests_php.cfg b/tools/internal_ci/macos/pull_request/grpc_basictests_php.cfg new file mode 100644 index 00000000000..11b17874c28 --- /dev/null +++ b/tools/internal_ci/macos/pull_request/grpc_basictests_php.cfg @@ -0,0 +1,31 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests macos php --internal_ci -j 1 --inner_jobs 4 --max_time=3600" +} diff --git a/tools/internal_ci/macos/pull_request/grpc_basictests_python.cfg b/tools/internal_ci/macos/pull_request/grpc_basictests_python.cfg new file mode 100644 index 00000000000..c86871f80cb --- /dev/null +++ b/tools/internal_ci/macos/pull_request/grpc_basictests_python.cfg @@ -0,0 +1,31 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests macos python --internal_ci -j 1 --inner_jobs 4 --max_time=3600" +} diff --git a/tools/internal_ci/macos/pull_request/grpc_basictests_ruby.cfg b/tools/internal_ci/macos/pull_request/grpc_basictests_ruby.cfg new file mode 100644 index 00000000000..5729bf8f751 --- /dev/null +++ b/tools/internal_ci/macos/pull_request/grpc_basictests_ruby.cfg @@ -0,0 +1,31 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests macos ruby --internal_ci -j 1 --inner_jobs 4 --max_time=3600" +} diff --git a/tools/internal_ci/windows/bazel_rbe.bat b/tools/internal_ci/windows/bazel_rbe.bat index e15bce48f0e..8f2c534c5ef 100644 --- a/tools/internal_ci/windows/bazel_rbe.bat +++ b/tools/internal_ci/windows/bazel_rbe.bat @@ -12,7 +12,20 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. -choco install bazel -y --version 0.23.2 +@rem TODO(jtattermusch): make this generate less output +choco install bazel -y --version 0.23.2 --limit-output + cd github/grpc -set PATH=%PATH%;C:\python27\ -bazel --bazelrc=tools/remote_build/windows.bazelrc build :all --incompatible_disallow_filetype=false --google_credentials=%KOKORO_GFILE_DIR%/rbe-windows-credentials.json \ No newline at end of file +set PATH=C:\tools\msys64\usr\bin;C:\Python27;%PATH% + +@rem Generate a random UUID and store in "bazel_invocation_ids" artifact file +powershell -Command "[guid]::NewGuid().ToString()" >%KOKORO_ARTIFACTS_DIR%/bazel_invocation_ids +set /p BAZEL_INVOCATION_ID=<%KOKORO_ARTIFACTS_DIR%/bazel_invocation_ids + +@rem TODO(jtattermusch): windows RBE should be able to use the same credentials as Linux RBE. +bazel --bazelrc=tools/remote_build/windows.bazelrc build --invocation_id="%BAZEL_INVOCATION_ID%" --workspace_status_command=tools/remote_build/workspace_status_kokoro.sh :all --incompatible_disallow_filetype=false --google_credentials=%KOKORO_GFILE_DIR%/rbe-windows-credentials.json +set BAZEL_EXITCODE=%errorlevel% + +@rem TODO(jtattermusch): upload results to bigquery + +exit /b %BAZEL_EXITCODE% diff --git a/tools/internal_ci/windows/grpc_basictests_c.cfg b/tools/internal_ci/windows/grpc_basictests_c.cfg new file mode 100644 index 00000000000..223cf389d0e --- /dev/null +++ b/tools/internal_ci/windows/grpc_basictests_c.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat" +timeout_mins: 120 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests windows c -j 1 --inner_jobs 8 --internal_ci --bq_result_table aggregate_results" +} diff --git a/tools/internal_ci/windows/grpc_basictests_csharp.cfg b/tools/internal_ci/windows/grpc_basictests_csharp.cfg new file mode 100644 index 00000000000..17a362fb32a --- /dev/null +++ b/tools/internal_ci/windows/grpc_basictests_csharp.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests windows csharp -j 1 --inner_jobs 8 --internal_ci --bq_result_table aggregate_results" +} diff --git a/tools/internal_ci/windows/grpc_basictests_python.cfg b/tools/internal_ci/windows/grpc_basictests_python.cfg new file mode 100644 index 00000000000..b0f6f6772d3 --- /dev/null +++ b/tools/internal_ci/windows/grpc_basictests_python.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests windows python -j 1 --inner_jobs 8 --internal_ci --bq_result_table aggregate_results" +} diff --git a/tools/internal_ci/windows/grpc_bazel_rbe_dbg.cfg b/tools/internal_ci/windows/grpc_bazel_rbe_dbg.cfg new file mode 100644 index 00000000000..f958fed33dd --- /dev/null +++ b/tools/internal_ci/windows/grpc_bazel_rbe_dbg.cfg @@ -0,0 +1,32 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/windows/bazel_rbe.bat" + +timeout_mins: 60 + +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/resultstore_api_key" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/rbe-windows-credentials.json" + +bazel_setting { + # In order for Kokoro to recognize this as a bazel build and publish the bazel resultstore link, + # the bazel_setting section needs to be present and "upsalite_frontend_address" needs to be + # set. The rest of configuration from bazel_setting is unused (we configure everything when bazel + # command is invoked). + upsalite_frontend_address: "https://source.cloud.google.com" +} diff --git a/tools/internal_ci/windows/pull_request/grpc_basictests_c.cfg b/tools/internal_ci/windows/pull_request/grpc_basictests_c.cfg new file mode 100644 index 00000000000..4cedcae9a87 --- /dev/null +++ b/tools/internal_ci/windows/pull_request/grpc_basictests_c.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat" +timeout_mins: 120 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests windows c -j 1 --inner_jobs 8 --internal_ci --max_time=3600" +} diff --git a/tools/internal_ci/windows/pull_request/grpc_basictests_csharp.cfg b/tools/internal_ci/windows/pull_request/grpc_basictests_csharp.cfg new file mode 100644 index 00000000000..e1c5af108ec --- /dev/null +++ b/tools/internal_ci/windows/pull_request/grpc_basictests_csharp.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests windows csharp -j 1 --inner_jobs 8 --internal_ci --max_time=3600" +} diff --git a/tools/internal_ci/windows/pull_request/grpc_basictests_python.cfg b/tools/internal_ci/windows/pull_request/grpc_basictests_python.cfg new file mode 100644 index 00000000000..6947e8e1b4e --- /dev/null +++ b/tools/internal_ci/windows/pull_request/grpc_basictests_python.cfg @@ -0,0 +1,30 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat" +timeout_mins: 60 +action { + define_artifacts { + regex: "**/*sponge_log.*" + regex: "github/grpc/reports/**" + } +} + +env_vars { + key: "RUN_TESTS_FLAGS" + value: "-f basictests windows python -j 1 --inner_jobs 8 --internal_ci --max_time=3600" +} diff --git a/tools/internal_ci/windows/pull_request/grpc_bazel_rbe_dbg.cfg b/tools/internal_ci/windows/pull_request/grpc_bazel_rbe_dbg.cfg new file mode 100644 index 00000000000..f958fed33dd --- /dev/null +++ b/tools/internal_ci/windows/pull_request/grpc_bazel_rbe_dbg.cfg @@ -0,0 +1,32 @@ +# Copyright 2019 The gRPC Authors +# +# 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. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/windows/bazel_rbe.bat" + +timeout_mins: 60 + +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/resultstore_api_key" +gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/rbe-windows-credentials.json" + +bazel_setting { + # In order for Kokoro to recognize this as a bazel build and publish the bazel resultstore link, + # the bazel_setting section needs to be present and "upsalite_frontend_address" needs to be + # set. The rest of configuration from bazel_setting is unused (we configure everything when bazel + # command is invoked). + upsalite_frontend_address: "https://source.cloud.google.com" +} diff --git a/tools/interop_matrix/client_matrix.py b/tools/interop_matrix/client_matrix.py index 67b6832c8b2..234c71295b3 100644 --- a/tools/interop_matrix/client_matrix.py +++ b/tools/interop_matrix/client_matrix.py @@ -100,6 +100,7 @@ LANG_RELEASE_MATRIX = { ('v1.17.1', ReleaseInfo()), ('v1.18.0', ReleaseInfo()), ('v1.19.0', ReleaseInfo()), + ('v1.20.0', ReleaseInfo()), ]), 'go': OrderedDict([ @@ -121,6 +122,8 @@ LANG_RELEASE_MATRIX = { ('v1.16.0', ReleaseInfo(runtime_subset=['go1.8'])), ('v1.17.0', ReleaseInfo(runtime_subset=['go1.11'])), ('v1.18.0', ReleaseInfo(runtime_subset=['go1.11'])), + ('v1.19.0', ReleaseInfo(runtime_subset=['go1.11'])), + ('v1.20.0', ReleaseInfo(runtime_subset=['go1.11'])), ]), 'java': OrderedDict([ @@ -167,6 +170,7 @@ LANG_RELEASE_MATRIX = { ('v1.17.1', ReleaseInfo(testcases_file='python__v1.11.1')), ('v1.18.0', ReleaseInfo()), ('v1.19.0', ReleaseInfo()), + ('v1.20.0', ReleaseInfo()), ]), 'node': OrderedDict([ @@ -265,7 +269,8 @@ LANG_RELEASE_MATRIX = { ('v1.15.0', ReleaseInfo(testcases_file='csharp__v1.3.9')), ('v1.16.0', ReleaseInfo(testcases_file='csharp__v1.3.9')), ('v1.17.1', ReleaseInfo(testcases_file='csharp__v1.3.9')), - ('v1.18.0', ReleaseInfo()), - ('v1.19.0', ReleaseInfo()), + ('v1.18.0', ReleaseInfo(testcases_file='csharp__v1.18.0')), + ('v1.19.0', ReleaseInfo(testcases_file='csharp__v1.18.0')), + ('v1.20.0', ReleaseInfo()), ]), } diff --git a/tools/interop_matrix/testcases/csharp__master b/tools/interop_matrix/testcases/csharp__master index 9f1cd05b177..e526b3c1cfd 100755 --- a/tools/interop_matrix/testcases/csharp__master +++ b/tools/interop_matrix/testcases/csharp__master @@ -1,7 +1,7 @@ #!/bin/bash # DO NOT MODIFY # This file is generated by run_interop_tests.py/create_testcases.sh -echo "Testing ${docker_image:=grpc_interop_csharp:71b05977-476b-4e57-9752-dd211c9e3741}" +echo "Testing ${docker_image:=grpc_interop_csharp:9296f21a-f657-4bb0-82a7-24fc527abcbd}" docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true" docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true" docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true" diff --git a/tools/interop_matrix/testcases/csharp__v1.18.0 b/tools/interop_matrix/testcases/csharp__v1.18.0 new file mode 100644 index 00000000000..34444c71025 --- /dev/null +++ b/tools/interop_matrix/testcases/csharp__v1.18.0 @@ -0,0 +1,23 @@ +#!/bin/bash +# DO NOT MODIFY +# This file is generated by run_interop_tests.py/create_testcases.sh +echo "Testing ${docker_image:=grpc_interop_csharp:71b05977-476b-4e57-9752-dd211c9e3741}" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_stream --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=client_streaming --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=server_streaming --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_begin --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_first_response --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=timeout_on_sleeping_server --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=empty_stream --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=client_streaming --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=server_streaming --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_begin --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_first_response --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45 --net=host $docker_image bash -c "mono Grpc.IntegrationTesting.Client.exe --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=timeout_on_sleeping_server --use_tls=true" + diff --git a/tools/interop_matrix/testcases/csharpcoreclr__master b/tools/interop_matrix/testcases/csharpcoreclr__master index 3ca145e4c11..e14ec047630 100755 --- a/tools/interop_matrix/testcases/csharpcoreclr__master +++ b/tools/interop_matrix/testcases/csharpcoreclr__master @@ -1,22 +1,22 @@ #!/bin/bash # DO NOT MODIFY # This file is generated by run_interop_tests.py/create_testcases.sh -echo "Testing ${docker_image:=grpc_interop_csharpcoreclr:bae17a7e-5450-4781-8982-e82cb89db6dd}" -docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true" -docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true" -docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true" -docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_stream --use_tls=true" -docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=client_streaming --use_tls=true" -docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=server_streaming --use_tls=true" -docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_begin --use_tls=true" -docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_first_response --use_tls=true" -docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=timeout_on_sleeping_server --use_tls=true" -docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true" -docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true" -docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true" -docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=empty_stream --use_tls=true" -docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=client_streaming --use_tls=true" -docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=server_streaming --use_tls=true" -docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_begin --use_tls=true" -docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_first_response --use_tls=true" -docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=timeout_on_sleeping_server --use_tls=true" +echo "Testing ${docker_image:=grpc_interop_csharpcoreclr:33395965-11d7-4b12-bcd6-a272d4015207}" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp2.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp2.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp2.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp2.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_stream --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp2.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=client_streaming --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp2.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=server_streaming --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp2.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_begin --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp2.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_first_response --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp2.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=timeout_on_sleeping_server --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp2.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp2.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp2.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp2.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=empty_stream --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp2.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=client_streaming --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp2.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=server_streaming --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp2.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_begin --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp2.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_first_response --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp2.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=timeout_on_sleeping_server --use_tls=true" diff --git a/tools/interop_matrix/testcases/csharpcoreclr__v1.18.0 b/tools/interop_matrix/testcases/csharpcoreclr__v1.18.0 new file mode 100755 index 00000000000..3ca145e4c11 --- /dev/null +++ b/tools/interop_matrix/testcases/csharpcoreclr__v1.18.0 @@ -0,0 +1,22 @@ +#!/bin/bash +# DO NOT MODIFY +# This file is generated by run_interop_tests.py/create_testcases.sh +echo "Testing ${docker_image:=grpc_interop_csharpcoreclr:bae17a7e-5450-4781-8982-e82cb89db6dd}" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=empty_stream --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=client_streaming --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=server_streaming --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_begin --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_first_response --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test.sandbox.googleapis.com --server_port=443 --test_case=timeout_on_sleeping_server --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=large_unary --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=empty_unary --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=ping_pong --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=empty_stream --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=client_streaming --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=server_streaming --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_begin --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=cancel_after_first_response --use_tls=true" +docker run -i --rm=true -w /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/netcoreapp1.1 --net=host $docker_image bash -c "dotnet exec Grpc.IntegrationTesting.Client.dll --server_host=grpc-test4.sandbox.googleapis.com --server_port=443 --test_case=timeout_on_sleeping_server --use_tls=true" diff --git a/tools/remote_build/kokoro.bazelrc b/tools/remote_build/kokoro.bazelrc index 2fbdd3ce020..064e94b2e15 100644 --- a/tools/remote_build/kokoro.bazelrc +++ b/tools/remote_build/kokoro.bazelrc @@ -21,9 +21,6 @@ build --remote_executor=remotebuildexecution.googleapis.com build --tls_enabled=true build --auth_enabled=true -# magic location where kokoro script puts the credentials -build --auth_credentials=/tmpfs/src/keystore/4321_grpc-testing-service -build --auth_scope=https://www.googleapis.com/auth/cloud-source-tools build --bes_backend=buildeventservice.googleapis.com build --bes_timeout=600s diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 9b9ad7d430c..dd4341c2736 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -2776,6 +2776,56 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "benchmark", + "bm_callback_test_service_impl", + "gpr", + "grpc++_test_config", + "grpc++_test_util_unsecure", + "grpc++_unsecure", + "grpc_benchmark", + "grpc_test_util_unsecure", + "grpc_unsecure" + ], + "headers": [ + "test/cpp/microbenchmarks/callback_streaming_ping_pong.h" + ], + "is_filegroup": false, + "language": "c++", + "name": "bm_callback_streaming_ping_pong", + "src": [ + "test/cpp/microbenchmarks/bm_callback_streaming_ping_pong.cc", + "test/cpp/microbenchmarks/callback_streaming_ping_pong.h" + ], + "third_party": false, + "type": "target" + }, + { + "deps": [ + "benchmark", + "bm_callback_test_service_impl", + "gpr", + "grpc++_test_config", + "grpc++_test_util_unsecure", + "grpc++_unsecure", + "grpc_benchmark", + "grpc_test_util_unsecure", + "grpc_unsecure" + ], + "headers": [ + "test/cpp/microbenchmarks/callback_unary_ping_pong.h" + ], + "is_filegroup": false, + "language": "c++", + "name": "bm_callback_unary_ping_pong", + "src": [ + "test/cpp/microbenchmarks/bm_callback_unary_ping_pong.cc", + "test/cpp/microbenchmarks/callback_unary_ping_pong.h" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "benchmark", @@ -3335,6 +3385,7 @@ "gpr", "grpc", "grpc++", + "grpc++_test_config", "grpc++_test_util", "grpc_test_util" ], @@ -3661,11 +3712,42 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "gpr", + "grpc_test_util_unsecure" + ], + "headers": [], + "is_filegroup": false, + "language": "c++", + "name": "global_config_env_test", + "src": [ + "test/core/gprpp/global_config_env_test.cc" + ], + "third_party": false, + "type": "target" + }, + { + "deps": [ + "gpr", + "grpc_test_util_unsecure" + ], + "headers": [], + "is_filegroup": false, + "language": "c++", + "name": "global_config_test", + "src": [ + "test/core/gprpp/global_config_test.cc" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "gpr", "grpc", - "grpc++" + "grpc++", + "grpc++_test_config" ], "headers": [ "src/proto/grpc/testing/compiler_test.grpc.pb.h", @@ -4281,6 +4363,25 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "gpr", + "grpc", + "grpc++", + "grpc++_test_util", + "grpc_test_util", + "test_tcp_server" + ], + "headers": [], + "is_filegroup": false, + "language": "c++", + "name": "port_sharing_end2end_test", + "src": [ + "test/cpp/end2end/port_sharing_end2end_test.cc" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "gpr", @@ -4684,6 +4785,7 @@ "gpr", "grpc", "grpc++", + "grpc++_test_config", "grpc++_test_util", "grpc_test_util" ], @@ -4762,6 +4864,24 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "gpr", + "grpc", + "grpc++", + "grpc++_test_util", + "grpc_test_util" + ], + "headers": [], + "is_filegroup": false, + "language": "c++", + "name": "service_config_end2end_test", + "src": [ + "test/cpp/end2end/service_config_end2end_test.cc" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "gpr", @@ -5981,6 +6101,7 @@ }, { "deps": [ + "dns_test_util", "gpr", "grpc++_test_config", "grpc++_test_util_unsecure", @@ -6000,6 +6121,7 @@ }, { "deps": [ + "dns_test_util", "gpr", "grpc", "grpc++", @@ -6095,6 +6217,7 @@ }, { "deps": [ + "dns_test_util", "gpr", "grpc", "grpc++", @@ -6570,6 +6693,48 @@ "third_party": false, "type": "lib" }, + { + "deps": [ + "benchmark", + "gpr", + "grpc++_test_config", + "grpc++_test_util_unsecure", + "grpc++_unsecure", + "grpc_benchmark", + "grpc_test_util_unsecure", + "grpc_unsecure" + ], + "headers": [ + "src/proto/grpc/testing/echo.grpc.pb.h", + "src/proto/grpc/testing/echo.pb.h", + "src/proto/grpc/testing/echo_mock.grpc.pb.h", + "test/cpp/microbenchmarks/callback_test_service.h" + ], + "is_filegroup": false, + "language": "c++", + "name": "bm_callback_test_service_impl", + "src": [ + "test/cpp/microbenchmarks/callback_test_service.cc", + "test/cpp/microbenchmarks/callback_test_service.h" + ], + "third_party": false, + "type": "lib" + }, + { + "deps": [], + "headers": [ + "test/cpp/naming/dns_test_util.h" + ], + "is_filegroup": false, + "language": "c++", + "name": "dns_test_util", + "src": [ + "test/cpp/naming/dns_test_util.cc", + "test/cpp/naming/dns_test_util.h" + ], + "third_party": false, + "type": "lib" + }, { "deps": [ "gpr", @@ -7982,7 +8147,6 @@ "name": "gpr_base", "src": [ "src/core/lib/gpr/alloc.cc", - "src/core/lib/gpr/arena.cc", "src/core/lib/gpr/atm.cc", "src/core/lib/gpr/cpu_iphone.cc", "src/core/lib/gpr/cpu_linux.cc", @@ -8015,7 +8179,9 @@ "src/core/lib/gpr/tmpfile_posix.cc", "src/core/lib/gpr/tmpfile_windows.cc", "src/core/lib/gpr/wrap_memcpy.cc", + "src/core/lib/gprpp/arena.cc", "src/core/lib/gprpp/fork.cc", + "src/core/lib/gprpp/global_config_env.cc", "src/core/lib/gprpp/thd_posix.cc", "src/core/lib/gprpp/thd_windows.cc", "src/core/lib/profiling/basic_timers.cc", @@ -8063,8 +8229,13 @@ "src/core/lib/gpr/tmpfile.h", "src/core/lib/gpr/useful.h", "src/core/lib/gprpp/abstract.h", + "src/core/lib/gprpp/arena.h", "src/core/lib/gprpp/atomic.h", "src/core/lib/gprpp/fork.h", + "src/core/lib/gprpp/global_config.h", + "src/core/lib/gprpp/global_config_custom.h", + "src/core/lib/gprpp/global_config_env.h", + "src/core/lib/gprpp/global_config_generic.h", "src/core/lib/gprpp/manual_constructor.h", "src/core/lib/gprpp/map.h", "src/core/lib/gprpp/memory.h", @@ -8111,8 +8282,13 @@ "src/core/lib/gpr/tmpfile.h", "src/core/lib/gpr/useful.h", "src/core/lib/gprpp/abstract.h", + "src/core/lib/gprpp/arena.h", "src/core/lib/gprpp/atomic.h", "src/core/lib/gprpp/fork.h", + "src/core/lib/gprpp/global_config.h", + "src/core/lib/gprpp/global_config_custom.h", + "src/core/lib/gprpp/global_config_env.h", + "src/core/lib/gprpp/global_config_generic.h", "src/core/lib/gprpp/manual_constructor.h", "src/core/lib/gprpp/map.h", "src/core/lib/gprpp/memory.h", @@ -8232,12 +8408,15 @@ "src/core/lib/http/parser.cc", "src/core/lib/iomgr/buffer_list.cc", "src/core/lib/iomgr/call_combiner.cc", + "src/core/lib/iomgr/cfstream_handle.cc", "src/core/lib/iomgr/combiner.cc", "src/core/lib/iomgr/endpoint.cc", + "src/core/lib/iomgr/endpoint_cfstream.cc", "src/core/lib/iomgr/endpoint_pair_posix.cc", "src/core/lib/iomgr/endpoint_pair_uv.cc", "src/core/lib/iomgr/endpoint_pair_windows.cc", "src/core/lib/iomgr/error.cc", + "src/core/lib/iomgr/error_cfstream.cc", "src/core/lib/iomgr/ev_epoll1_linux.cc", "src/core/lib/iomgr/ev_epollex_linux.cc", "src/core/lib/iomgr/ev_poll_posix.cc", @@ -8258,6 +8437,7 @@ "src/core/lib/iomgr/iomgr_custom.cc", "src/core/lib/iomgr/iomgr_internal.cc", "src/core/lib/iomgr/iomgr_posix.cc", + "src/core/lib/iomgr/iomgr_posix_cfstream.cc", "src/core/lib/iomgr/iomgr_uv.cc", "src/core/lib/iomgr/iomgr_windows.cc", "src/core/lib/iomgr/is_epollexclusive_available.cc", @@ -8286,6 +8466,7 @@ "src/core/lib/iomgr/socket_utils_windows.cc", "src/core/lib/iomgr/socket_windows.cc", "src/core/lib/iomgr/tcp_client.cc", + "src/core/lib/iomgr/tcp_client_cfstream.cc", "src/core/lib/iomgr/tcp_client_custom.cc", "src/core/lib/iomgr/tcp_client_posix.cc", "src/core/lib/iomgr/tcp_client_windows.cc", @@ -8414,12 +8595,15 @@ "src/core/lib/iomgr/block_annotate.h", "src/core/lib/iomgr/buffer_list.h", "src/core/lib/iomgr/call_combiner.h", + "src/core/lib/iomgr/cfstream_handle.h", "src/core/lib/iomgr/closure.h", "src/core/lib/iomgr/combiner.h", "src/core/lib/iomgr/dynamic_annotations.h", "src/core/lib/iomgr/endpoint.h", + "src/core/lib/iomgr/endpoint_cfstream.h", "src/core/lib/iomgr/endpoint_pair.h", "src/core/lib/iomgr/error.h", + "src/core/lib/iomgr/error_cfstream.h", "src/core/lib/iomgr/error_internal.h", "src/core/lib/iomgr/ev_epoll1_linux.h", "src/core/lib/iomgr/ev_epollex_linux.h", @@ -8486,6 +8670,7 @@ "src/core/lib/slice/slice_hash_table.h", "src/core/lib/slice/slice_internal.h", "src/core/lib/slice/slice_string_helpers.h", + "src/core/lib/slice/slice_utils.h", "src/core/lib/slice/slice_weak_hash_table.h", "src/core/lib/surface/api_trace.h", "src/core/lib/surface/call.h", @@ -8567,12 +8752,15 @@ "src/core/lib/iomgr/block_annotate.h", "src/core/lib/iomgr/buffer_list.h", "src/core/lib/iomgr/call_combiner.h", + "src/core/lib/iomgr/cfstream_handle.h", "src/core/lib/iomgr/closure.h", "src/core/lib/iomgr/combiner.h", "src/core/lib/iomgr/dynamic_annotations.h", "src/core/lib/iomgr/endpoint.h", + "src/core/lib/iomgr/endpoint_cfstream.h", "src/core/lib/iomgr/endpoint_pair.h", "src/core/lib/iomgr/error.h", + "src/core/lib/iomgr/error_cfstream.h", "src/core/lib/iomgr/error_internal.h", "src/core/lib/iomgr/ev_epoll1_linux.h", "src/core/lib/iomgr/ev_epollex_linux.h", @@ -8639,6 +8827,7 @@ "src/core/lib/slice/slice_hash_table.h", "src/core/lib/slice/slice_internal.h", "src/core/lib/slice/slice_string_helpers.h", + "src/core/lib/slice/slice_utils.h", "src/core/lib/slice/slice_weak_hash_table.h", "src/core/lib/surface/api_trace.h", "src/core/lib/surface/call.h", @@ -8672,33 +8861,6 @@ "third_party": false, "type": "filegroup" }, - { - "deps": [ - "gpr", - "gpr_base_headers", - "grpc_base_headers" - ], - "headers": [ - "src/core/lib/iomgr/cfstream_handle.h", - "src/core/lib/iomgr/endpoint_cfstream.h", - "src/core/lib/iomgr/error_cfstream.h" - ], - "is_filegroup": true, - "language": "c", - "name": "grpc_cfstream", - "src": [ - "src/core/lib/iomgr/cfstream_handle.cc", - "src/core/lib/iomgr/cfstream_handle.h", - "src/core/lib/iomgr/endpoint_cfstream.cc", - "src/core/lib/iomgr/endpoint_cfstream.h", - "src/core/lib/iomgr/error_cfstream.cc", - "src/core/lib/iomgr/error_cfstream.h", - "src/core/lib/iomgr/iomgr_posix_cfstream.cc", - "src/core/lib/iomgr/tcp_client_cfstream.cc" - ], - "third_party": false, - "type": "filegroup" - }, { "deps": [ "gpr", @@ -9109,7 +9271,8 @@ "deps": [ "gpr", "grpc_base", - "grpc_client_channel" + "grpc_client_channel", + "grpc_resolver_dns_selection" ], "headers": [ "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h", @@ -9122,11 +9285,13 @@ "src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h", + "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc", + "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc", "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc" ], @@ -9137,7 +9302,8 @@ "deps": [ "gpr", "grpc_base", - "grpc_client_channel" + "grpc_client_channel", + "grpc_resolver_dns_selection" ], "headers": [], "is_filegroup": true, @@ -9149,6 +9315,24 @@ "third_party": false, "type": "filegroup" }, + { + "deps": [ + "gpr", + "grpc_base" + ], + "headers": [ + "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h" + ], + "is_filegroup": true, + "language": "c", + "name": "grpc_resolver_dns_selection", + "src": [ + "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc", + "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h" + ], + "third_party": false, + "type": "filegroup" + }, { "deps": [ "gpr", @@ -9947,6 +10131,7 @@ "include/grpcpp/impl/codegen/client_interceptor.h", "include/grpcpp/impl/codegen/client_unary_call.h", "include/grpcpp/impl/codegen/completion_queue.h", + "include/grpcpp/impl/codegen/completion_queue_impl.h", "include/grpcpp/impl/codegen/completion_queue_tag.h", "include/grpcpp/impl/codegen/config.h", "include/grpcpp/impl/codegen/core_codegen_interface.h", @@ -10024,6 +10209,7 @@ "include/grpcpp/impl/codegen/client_interceptor.h", "include/grpcpp/impl/codegen/client_unary_call.h", "include/grpcpp/impl/codegen/completion_queue.h", + "include/grpcpp/impl/codegen/completion_queue_impl.h", "include/grpcpp/impl/codegen/completion_queue_tag.h", "include/grpcpp/impl/codegen/config.h", "include/grpcpp/impl/codegen/core_codegen_interface.h", @@ -10152,6 +10338,7 @@ "include/grpcpp/alarm.h", "include/grpcpp/alarm_impl.h", "include/grpcpp/channel.h", + "include/grpcpp/channel_impl.h", "include/grpcpp/client_context.h", "include/grpcpp/completion_queue.h", "include/grpcpp/create_channel.h", @@ -10186,18 +10373,21 @@ "include/grpcpp/security/auth_metadata_processor.h", "include/grpcpp/security/auth_metadata_processor_impl.h", "include/grpcpp/security/credentials.h", + "include/grpcpp/security/credentials_impl.h", "include/grpcpp/security/server_credentials.h", "include/grpcpp/security/server_credentials_impl.h", "include/grpcpp/server.h", "include/grpcpp/server_builder.h", "include/grpcpp/server_builder_impl.h", "include/grpcpp/server_context.h", + "include/grpcpp/server_impl.h", "include/grpcpp/server_posix.h", "include/grpcpp/server_posix_impl.h", "include/grpcpp/support/async_stream.h", "include/grpcpp/support/async_unary_call.h", "include/grpcpp/support/byte_buffer.h", "include/grpcpp/support/channel_arguments.h", + "include/grpcpp/support/channel_arguments_impl.h", "include/grpcpp/support/client_callback.h", "include/grpcpp/support/client_interceptor.h", "include/grpcpp/support/config.h", @@ -10217,6 +10407,7 @@ "src/cpp/client/create_channel_internal.h", "src/cpp/common/channel_filter.h", "src/cpp/server/dynamic_thread_pool.h", + "src/cpp/server/external_connection_acceptor_impl.h", "src/cpp/server/health/default_health_check_service.h", "src/cpp/server/thread_pool_interface.h", "src/cpp/thread_manager/thread_manager.h" @@ -10273,6 +10464,7 @@ "include/grpcpp/alarm.h", "include/grpcpp/alarm_impl.h", "include/grpcpp/channel.h", + "include/grpcpp/channel_impl.h", "include/grpcpp/client_context.h", "include/grpcpp/completion_queue.h", "include/grpcpp/create_channel.h", @@ -10307,18 +10499,21 @@ "include/grpcpp/security/auth_metadata_processor.h", "include/grpcpp/security/auth_metadata_processor_impl.h", "include/grpcpp/security/credentials.h", + "include/grpcpp/security/credentials_impl.h", "include/grpcpp/security/server_credentials.h", "include/grpcpp/security/server_credentials_impl.h", "include/grpcpp/server.h", "include/grpcpp/server_builder.h", "include/grpcpp/server_builder_impl.h", "include/grpcpp/server_context.h", + "include/grpcpp/server_impl.h", "include/grpcpp/server_posix.h", "include/grpcpp/server_posix_impl.h", "include/grpcpp/support/async_stream.h", "include/grpcpp/support/async_unary_call.h", "include/grpcpp/support/byte_buffer.h", "include/grpcpp/support/channel_arguments.h", + "include/grpcpp/support/channel_arguments_impl.h", "include/grpcpp/support/client_callback.h", "include/grpcpp/support/client_interceptor.h", "include/grpcpp/support/config.h", @@ -10358,6 +10553,8 @@ "src/cpp/server/create_default_thread_pool.cc", "src/cpp/server/dynamic_thread_pool.cc", "src/cpp/server/dynamic_thread_pool.h", + "src/cpp/server/external_connection_acceptor_impl.cc", + "src/cpp/server/external_connection_acceptor_impl.h", "src/cpp/server/health/default_health_check_service.cc", "src/cpp/server/health/default_health_check_service.h", "src/cpp/server/health/health_check_service.cc", diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index ec2e570bea7..473e2e26c3a 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -3479,6 +3479,50 @@ ], "uses_polling": false }, + { + "args": [], + "benchmark": true, + "ci_platforms": [ + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": false, + "language": "c++", + "name": "bm_callback_streaming_ping_pong", + "platforms": [ + "linux", + "mac", + "posix" + ], + "uses_polling": true + }, + { + "args": [], + "benchmark": true, + "ci_platforms": [ + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": false, + "language": "c++", + "name": "bm_callback_unary_ping_pong", + "platforms": [ + "linux", + "mac", + "posix" + ], + "uses_polling": true + }, { "args": [], "benchmark": true, @@ -4499,6 +4543,54 @@ ], "uses_polling": true }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": false, + "language": "c++", + "name": "global_config_env_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": false + }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": false, + "language": "c++", + "name": "global_config_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": false + }, { "args": [ "--generated_file_path=gens/src/proto/grpc/testing/" @@ -5001,6 +5093,30 @@ ], "uses_polling": true }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "port_sharing_end2end_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": true + }, { "args": [], "benchmark": false, @@ -5397,6 +5513,30 @@ ], "uses_polling": true }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "service_config_end2end_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": true + }, { "args": [], "benchmark": false, diff --git a/tools/run_tests/python_utils/upload_rbe_results.py b/tools/run_tests/python_utils/upload_rbe_results.py index bda567e977e..e6504799d66 100755 --- a/tools/run_tests/python_utils/upload_rbe_results.py +++ b/tools/run_tests/python_utils/upload_rbe_results.py @@ -146,6 +146,8 @@ if __name__ == "__main__": invocation_id = args.invocation_id or _get_invocation_id() resultstore_actions = _get_resultstore_data(api_key, invocation_id) + # google.devtools.resultstore.v2.Action schema: + # https://github.com/googleapis/googleapis/blob/master/google/devtools/resultstore/v2/action.proto bq_rows = [] for index, action in enumerate(resultstore_actions): # Filter out non-test related data, such as build results. @@ -187,6 +189,8 @@ if __name__ == "__main__": } elif 'testSuite' not in action['testAction']: continue + elif 'tests' not in action['testAction']['testSuite']: + continue else: test_cases = action['testAction']['testSuite']['tests'][0][ 'testSuite']['tests'] diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 567c628d8e0..cc6901bdebe 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -192,7 +192,7 @@ class CSharpCoreCLRLanguage: class AspNetCoreLanguage: def __init__(self): - self.client_cwd = '../grpc-dotnet' + self.client_cwd = '../grpc-dotnet/testassets/InteropTestsClient/bin/Debug/netcoreapp3.0' self.server_cwd = '../grpc-dotnet/testassets/InteropTestsWebsite/bin/Debug/netcoreapp3.0' self.safename = str(self) @@ -200,8 +200,7 @@ class AspNetCoreLanguage: return {} def client_cmd(self, args): - # attempt to run client should fail - return ['dotnet' 'exec', 'CLIENT_NOT_SUPPORTED'] + args + return ['dotnet', 'exec', 'InteropTestsClient.dll'] + args def server_cmd(self, args): return ['dotnet', 'exec', 'InteropTestsWebsite.dll'] + args @@ -210,8 +209,10 @@ class AspNetCoreLanguage: return {} def unimplemented_test_cases(self): - # aspnetcore doesn't have a client so ignore all test cases. - return _TEST_CASES + _AUTH_TEST_CASES + return _SKIP_COMPRESSION + \ + _SKIP_SPECIAL_STATUS_MESSAGE + \ + _AUTH_TEST_CASES + \ + ['cancel_after_first_response', 'ping_pong'] def unimplemented_test_cases_server(self): return _SKIP_COMPRESSION + _SKIP_SPECIAL_STATUS_MESSAGE diff --git a/tools/run_tests/run_microbenchmark.py b/tools/run_tests/run_microbenchmark.py index 4e4d05cdcd4..a7fde3007af 100755 --- a/tools/run_tests/run_microbenchmark.py +++ b/tools/run_tests/run_microbenchmark.py @@ -96,7 +96,7 @@ def collect_latency(bm_name, args): '--benchmark_filter=^%s$' % line, '--benchmark_min_time=0.05' ], - environ={'LATENCY_TRACE': '%s.trace' % fnize(line)}, + environ={'GRPC_LATENCY_TRACE': '%s.trace' % fnize(line)}, shortname='profile-%s' % fnize(line))) profile_analysis.append( jobset.JobSpec( diff --git a/tools/run_tests/sanity/core_banned_functions.py b/tools/run_tests/sanity/core_banned_functions.py index 549ae14f5ab..ce9ff0dae21 100755 --- a/tools/run_tests/sanity/core_banned_functions.py +++ b/tools/run_tests/sanity/core_banned_functions.py @@ -45,10 +45,6 @@ BANNED_EXCEPT = { 'grpc_closure_sched(': ['src/core/lib/iomgr/closure.cc'], 'grpc_closure_run(': ['src/core/lib/iomgr/closure.cc'], 'grpc_closure_list_sched(': ['src/core/lib/iomgr/closure.cc'], - 'gpr_getenv_silent(': [ - 'src/core/lib/gpr/log.cc', 'src/core/lib/gpr/env_linux.cc', - 'src/core/lib/gpr/env_posix.cc', 'src/core/lib/gpr/env_windows.cc' - ], } errors = 0