Merge branch 'master' into revert-18717-grpc_namespace_server_revert

pull/18720/head
Karthik Ravi Shankar 6 years ago
commit c8a6841dfc
  1. 7
      BUILD
  2. 5
      BUILD.gn
  3. 91
      CMakeLists.txt
  4. 106
      Makefile
  5. 26
      WORKSPACE
  6. 5
      bazel/grpc_build_system.bzl
  7. 29
      bazel/grpc_deps.bzl
  8. 17
      build.yaml
  9. 1
      config.m4
  10. 1
      config.w32
  11. 2
      doc/core/grpc-polling-engines.md
  12. 11
      doc/environment_variables.md
  13. 2
      examples/csharp/HelloworldXamarin/iOS/AppDelegate.cs
  14. 48
      examples/objective-c/auth_sample/MakeRPCViewController.m
  15. 35
      examples/objective-c/helloworld/main.m
  16. 33
      examples/objective-c/helloworld_macos/main.m
  17. 247
      examples/objective-c/route_guide/ViewControllers.m
  18. 32
      examples/python/wait_for_ready/BUILD.bazel
  19. 32
      examples/python/wait_for_ready/README.md
  20. 26
      examples/python/wait_for_ready/test/_wait_for_ready_example_test.py
  21. 114
      examples/python/wait_for_ready/wait_for_ready_example.py
  22. 2
      examples/ruby/without_protobuf/echo_client.rb
  23. 4
      gRPC-C++.podspec
  24. 3
      gRPC-Core.podspec
  25. 2
      grpc.gemspec
  26. 4
      grpc.gyp
  27. 2
      include/grpc/grpc_security.h
  28. 10
      include/grpc/impl/codegen/port_platform.h
  29. 22
      include/grpc/impl/codegen/slice.h
  30. 2
      include/grpc/slice.h
  31. 6
      include/grpcpp/generic/generic_stub_impl.h
  32. 12
      include/grpcpp/impl/codegen/async_stream.h
  33. 2
      include/grpcpp/impl/codegen/channel_interface.h
  34. 155
      include/grpcpp/impl/codegen/client_callback.h
  35. 2
      include/grpcpp/impl/codegen/client_context.h
  36. 10
      include/grpcpp/impl/codegen/completion_queue.h
  37. 55
      include/grpcpp/impl/codegen/message_allocator.h
  38. 12
      include/grpcpp/impl/codegen/method_handler_impl.h
  39. 8
      include/grpcpp/impl/codegen/rpc_service_method.h
  40. 152
      include/grpcpp/impl/codegen/server_callback.h
  41. 2
      include/grpcpp/impl/codegen/server_interface.h
  42. 5
      include/grpcpp/impl/codegen/service_type.h
  43. 17
      include/grpcpp/impl/codegen/sync.h
  44. 6
      include/grpcpp/impl/codegen/sync_stream.h
  45. 4
      include/grpcpp/security/credentials.h
  46. 24
      include/grpcpp/support/message_allocator.h
  47. 2
      package.xml
  48. 105
      src/compiler/cpp_generator.cc
  49. 4
      src/compiler/cpp_generator.h
  50. 10
      src/compiler/cpp_plugin.cc
  51. 16
      src/compiler/objective_c_generator.cc
  52. 30
      src/compiler/protobuf_plugin.h
  53. 36
      src/compiler/python_generator.cc
  54. 2
      src/compiler/python_generator.h
  55. 34
      src/compiler/python_generator_helpers.h
  56. 7
      src/compiler/schema_interface.h
  57. 3203
      src/core/ext/filters/client_channel/client_channel.cc
  58. 5
      src/core/ext/filters/client_channel/client_channel_channelz.cc
  59. 2
      src/core/ext/filters/client_channel/http_connect_handshaker.h
  60. 1
      src/core/ext/filters/client_channel/lb_policy.h
  61. 24
      src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
  62. 67
      src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
  63. 48
      src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
  64. 12
      src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
  65. 179
      src/core/ext/filters/client_channel/lb_policy/xds/xds.cc
  66. 8
      src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
  67. 24
      src/core/ext/filters/client_channel/resolving_lb_policy.cc
  68. 40
      src/core/ext/filters/client_channel/subchannel.cc
  69. 5
      src/core/ext/filters/client_channel/subchannel.h
  70. 2
      src/core/ext/filters/deadline/deadline_filter.cc
  71. 10
      src/core/ext/filters/http/client/http_client_filter.cc
  72. 2
      src/core/ext/filters/http/client/http_client_filter.h
  73. 1
      src/core/ext/filters/http/message_compress/message_compress_filter.cc
  74. 28
      src/core/ext/filters/http/server/http_server_filter.cc
  75. 2
      src/core/ext/transport/chttp2/alpn/alpn.h
  76. 24
      src/core/ext/transport/chttp2/transport/chttp2_transport.cc
  77. 2
      src/core/ext/transport/chttp2/transport/hpack_encoder.cc
  78. 11
      src/core/ext/transport/chttp2/transport/writing.cc
  79. 19
      src/core/ext/transport/cronet/transport/cronet_transport.cc
  80. 6
      src/core/ext/transport/inproc/inproc_transport.cc
  81. 101
      src/core/lib/channel/channel_args.cc
  82. 37
      src/core/lib/channel/channel_args.h
  83. 127
      src/core/lib/compression/compression_args.cc
  84. 55
      src/core/lib/compression/compression_args.h
  85. 50
      src/core/lib/gpr/arena.cc
  86. 2
      src/core/lib/gpr/arena.h
  87. 16
      src/core/lib/gprpp/ref_counted.h
  88. 4
      src/core/lib/iomgr/cfstream_handle.h
  89. 2
      src/core/lib/iomgr/ev_epoll1_linux.cc
  90. 3
      src/core/lib/iomgr/iomgr_custom.cc
  91. 2
      src/core/lib/iomgr/iomgr_custom.h
  92. 9
      src/core/lib/iomgr/port.h
  93. 57
      src/core/lib/iomgr/resource_quota.cc
  94. 4
      src/core/lib/iomgr/socket_utils_common_posix.cc
  95. 5
      src/core/lib/security/security_connector/ssl/ssl_security_connector.cc
  96. 215
      src/core/lib/slice/slice.cc
  97. 133
      src/core/lib/slice/slice_intern.cc
  98. 204
      src/core/lib/slice/slice_internal.h
  99. 1
      src/core/lib/surface/init.cc
  100. 2
      src/core/lib/surface/server.cc
  101. Some files were not shown because too many files have changed in this diff Show More

@ -269,6 +269,7 @@ GRPCXX_PUBLIC_HDRS = [
"include/grpcpp/support/client_interceptor.h",
"include/grpcpp/support/config.h",
"include/grpcpp/support/interceptor.h",
"include/grpcpp/support/message_allocator.h",
"include/grpcpp/support/proto_buffer_reader.h",
"include/grpcpp/support/proto_buffer_writer.h",
"include/grpcpp/support/server_callback.h",
@ -737,6 +738,7 @@ grpc_cc_library(
"src/core/lib/channel/handshaker_registry.cc",
"src/core/lib/channel/status_util.cc",
"src/core/lib/compression/compression.cc",
"src/core/lib/compression/compression_args.cc",
"src/core/lib/compression/compression_internal.cc",
"src/core/lib/compression/message_compress.cc",
"src/core/lib/compression/stream_compression.cc",
@ -892,6 +894,7 @@ grpc_cc_library(
"src/core/lib/channel/handshaker_registry.h",
"src/core/lib/channel/status_util.h",
"src/core/lib/compression/algorithm_metadata.h",
"src/core/lib/compression/compression_args.h",
"src/core/lib/compression/compression_internal.h",
"src/core/lib/compression/message_compress.h",
"src/core/lib/compression/stream_compression.h",
@ -2137,6 +2140,7 @@ grpc_cc_library(
"include/grpcpp/impl/codegen/intercepted_channel.h",
"include/grpcpp/impl/codegen/interceptor.h",
"include/grpcpp/impl/codegen/interceptor_common.h",
"include/grpcpp/impl/codegen/message_allocator.h",
"include/grpcpp/impl/codegen/metadata_map.h",
"include/grpcpp/impl/codegen/method_handler_impl.h",
"include/grpcpp/impl/codegen/rpc_method.h",
@ -2347,7 +2351,8 @@ grpc_cc_library(
":envoy_core_upb",
":google_api_upb",
":proto_gen_validate_upb",
]
],
tags = ["no_windows"],
)
grpc_cc_library(

@ -445,6 +445,8 @@ config("grpc_config") {
"src/core/lib/channel/status_util.h",
"src/core/lib/compression/algorithm_metadata.h",
"src/core/lib/compression/compression.cc",
"src/core/lib/compression/compression_args.cc",
"src/core/lib/compression/compression_args.h",
"src/core/lib/compression/compression_internal.cc",
"src/core/lib/compression/compression_internal.h",
"src/core/lib/compression/message_compress.cc",
@ -1045,6 +1047,7 @@ config("grpc_config") {
"include/grpcpp/impl/codegen/intercepted_channel.h",
"include/grpcpp/impl/codegen/interceptor.h",
"include/grpcpp/impl/codegen/interceptor_common.h",
"include/grpcpp/impl/codegen/message_allocator.h",
"include/grpcpp/impl/codegen/metadata_map.h",
"include/grpcpp/impl/codegen/method_handler_impl.h",
"include/grpcpp/impl/codegen/proto_buffer_reader.h",
@ -1101,6 +1104,7 @@ config("grpc_config") {
"include/grpcpp/support/client_interceptor.h",
"include/grpcpp/support/config.h",
"include/grpcpp/support/interceptor.h",
"include/grpcpp/support/message_allocator.h",
"include/grpcpp/support/proto_buffer_reader.h",
"include/grpcpp/support/proto_buffer_writer.h",
"include/grpcpp/support/server_callback.h",
@ -1128,6 +1132,7 @@ config("grpc_config") {
"src/core/lib/channel/handshaker_registry.h",
"src/core/lib/channel/status_util.h",
"src/core/lib/compression/algorithm_metadata.h",
"src/core/lib/compression/compression_args.h",
"src/core/lib/compression/compression_internal.h",
"src/core/lib/compression/message_compress.h",
"src/core/lib/compression/stream_compression.h",

@ -484,6 +484,7 @@ add_dependencies(buildtests_c h2_sockpair+trace_test)
add_dependencies(buildtests_c h2_sockpair_1byte_test)
add_dependencies(buildtests_c h2_spiffe_test)
add_dependencies(buildtests_c h2_ssl_test)
add_dependencies(buildtests_c h2_ssl_cred_reload_test)
add_dependencies(buildtests_c h2_ssl_proxy_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c h2_uds_test)
@ -660,6 +661,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx json_run_localhost)
endif()
add_dependencies(buildtests_cxx memory_test)
add_dependencies(buildtests_cxx message_allocator_end2end_test)
add_dependencies(buildtests_cxx metrics_client)
add_dependencies(buildtests_cxx mock_test)
add_dependencies(buildtests_cxx nonblocking_test)
@ -982,6 +984,7 @@ add_library(grpc
src/core/lib/channel/handshaker_registry.cc
src/core/lib/channel/status_util.cc
src/core/lib/compression/compression.cc
src/core/lib/compression/compression_args.cc
src/core/lib/compression/compression_internal.cc
src/core/lib/compression/message_compress.cc
src/core/lib/compression/stream_compression.cc
@ -1408,6 +1411,7 @@ add_library(grpc_cronet
src/core/lib/channel/handshaker_registry.cc
src/core/lib/channel/status_util.cc
src/core/lib/compression/compression.cc
src/core/lib/compression/compression_args.cc
src/core/lib/compression/compression_internal.cc
src/core/lib/compression/message_compress.cc
src/core/lib/compression/stream_compression.cc
@ -1819,6 +1823,7 @@ add_library(grpc_test_util
src/core/lib/channel/handshaker_registry.cc
src/core/lib/channel/status_util.cc
src/core/lib/compression/compression.cc
src/core/lib/compression/compression_args.cc
src/core/lib/compression/compression_internal.cc
src/core/lib/compression/message_compress.cc
src/core/lib/compression/stream_compression.cc
@ -2143,6 +2148,7 @@ add_library(grpc_test_util_unsecure
src/core/lib/channel/handshaker_registry.cc
src/core/lib/channel/status_util.cc
src/core/lib/compression/compression.cc
src/core/lib/compression/compression_args.cc
src/core/lib/compression/compression_internal.cc
src/core/lib/compression/message_compress.cc
src/core/lib/compression/stream_compression.cc
@ -2443,6 +2449,7 @@ add_library(grpc_unsecure
src/core/lib/channel/handshaker_registry.cc
src/core/lib/channel/status_util.cc
src/core/lib/compression/compression.cc
src/core/lib/compression/compression_args.cc
src/core/lib/compression/compression_internal.cc
src/core/lib/compression/message_compress.cc
src/core/lib/compression/stream_compression.cc
@ -3049,6 +3056,7 @@ foreach(_hdr
include/grpcpp/support/client_interceptor.h
include/grpcpp/support/config.h
include/grpcpp/support/interceptor.h
include/grpcpp/support/message_allocator.h
include/grpcpp/support/proto_buffer_reader.h
include/grpcpp/support/proto_buffer_writer.h
include/grpcpp/support/server_callback.h
@ -3164,6 +3172,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/intercepted_channel.h
include/grpcpp/impl/codegen/interceptor.h
include/grpcpp/impl/codegen/interceptor_common.h
include/grpcpp/impl/codegen/message_allocator.h
include/grpcpp/impl/codegen/metadata_map.h
include/grpcpp/impl/codegen/method_handler_impl.h
include/grpcpp/impl/codegen/rpc_method.h
@ -3343,6 +3352,7 @@ add_library(grpc++_cronet
src/core/lib/channel/handshaker_registry.cc
src/core/lib/channel/status_util.cc
src/core/lib/compression/compression.cc
src/core/lib/compression/compression_args.cc
src/core/lib/compression/compression_internal.cc
src/core/lib/compression/message_compress.cc
src/core/lib/compression/stream_compression.cc
@ -3653,6 +3663,7 @@ foreach(_hdr
include/grpcpp/support/client_interceptor.h
include/grpcpp/support/config.h
include/grpcpp/support/interceptor.h
include/grpcpp/support/message_allocator.h
include/grpcpp/support/proto_buffer_reader.h
include/grpcpp/support/proto_buffer_writer.h
include/grpcpp/support/server_callback.h
@ -3768,6 +3779,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/intercepted_channel.h
include/grpcpp/impl/codegen/interceptor.h
include/grpcpp/impl/codegen/interceptor_common.h
include/grpcpp/impl/codegen/message_allocator.h
include/grpcpp/impl/codegen/metadata_map.h
include/grpcpp/impl/codegen/method_handler_impl.h
include/grpcpp/impl/codegen/rpc_method.h
@ -4201,6 +4213,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/intercepted_channel.h
include/grpcpp/impl/codegen/interceptor.h
include/grpcpp/impl/codegen/interceptor_common.h
include/grpcpp/impl/codegen/message_allocator.h
include/grpcpp/impl/codegen/metadata_map.h
include/grpcpp/impl/codegen/method_handler_impl.h
include/grpcpp/impl/codegen/rpc_method.h
@ -4398,6 +4411,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/intercepted_channel.h
include/grpcpp/impl/codegen/interceptor.h
include/grpcpp/impl/codegen/interceptor_common.h
include/grpcpp/impl/codegen/message_allocator.h
include/grpcpp/impl/codegen/metadata_map.h
include/grpcpp/impl/codegen/method_handler_impl.h
include/grpcpp/impl/codegen/rpc_method.h
@ -4633,6 +4647,7 @@ foreach(_hdr
include/grpcpp/support/client_interceptor.h
include/grpcpp/support/config.h
include/grpcpp/support/interceptor.h
include/grpcpp/support/message_allocator.h
include/grpcpp/support/proto_buffer_reader.h
include/grpcpp/support/proto_buffer_writer.h
include/grpcpp/support/server_callback.h
@ -4748,6 +4763,7 @@ foreach(_hdr
include/grpcpp/impl/codegen/intercepted_channel.h
include/grpcpp/impl/codegen/interceptor.h
include/grpcpp/impl/codegen/interceptor_common.h
include/grpcpp/impl/codegen/message_allocator.h
include/grpcpp/impl/codegen/metadata_map.h
include/grpcpp/impl/codegen/method_handler_impl.h
include/grpcpp/impl/codegen/rpc_method.h
@ -14497,6 +14513,46 @@ target_link_libraries(memory_test
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(message_allocator_end2end_test
test/cpp/end2end/message_allocator_end2end_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(message_allocator_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(message_allocator_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)
@ -17681,6 +17737,41 @@ target_link_libraries(h2_ssl_test
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(h2_ssl_cred_reload_test
test/core/end2end/fixtures/h2_ssl_cred_reload.cc
)
target_include_directories(h2_ssl_cred_reload_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}
)
target_link_libraries(h2_ssl_cred_reload_test
${_gRPC_ALLTARGETS_LIBRARIES}
end2end_tests
grpc_test_util
grpc
gpr
)
# avoid dependency on libstdc++
if (_gRPC_CORE_NOSTDCXX_FLAGS)
set_target_properties(h2_ssl_cred_reload_test PROPERTIES LINKER_LANGUAGE C)
target_compile_options(h2_ssl_cred_reload_test PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${_gRPC_CORE_NOSTDCXX_FLAGS}>)
endif()
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(h2_ssl_proxy_test
test/core/end2end/fixtures/h2_ssl_proxy.cc
)

@ -478,11 +478,11 @@ LDFLAGS += $(EXTRA_LDFLAGS)
DEFINES += $(EXTRA_DEFINES)
LDLIBS += $(EXTRA_LDLIBS)
HOST_CPPFLAGS = $(CPPFLAGS)
HOST_CFLAGS = $(CFLAGS)
HOST_CXXFLAGS = $(CXXFLAGS)
HOST_LDFLAGS = $(LDFLAGS)
HOST_LDLIBS = $(LDLIBS)
HOST_CPPFLAGS += $(CPPFLAGS)
HOST_CFLAGS += $(CFLAGS)
HOST_CXXFLAGS += $(CXXFLAGS)
HOST_LDFLAGS += $(LDFLAGS)
HOST_LDLIBS += $(LDLIBS)
# These are automatically computed variables.
# There shouldn't be any need to change anything from now on.
@ -1233,6 +1233,7 @@ interop_server: $(BINDIR)/$(CONFIG)/interop_server
interop_test: $(BINDIR)/$(CONFIG)/interop_test
json_run_localhost: $(BINDIR)/$(CONFIG)/json_run_localhost
memory_test: $(BINDIR)/$(CONFIG)/memory_test
message_allocator_end2end_test: $(BINDIR)/$(CONFIG)/message_allocator_end2end_test
metrics_client: $(BINDIR)/$(CONFIG)/metrics_client
mock_test: $(BINDIR)/$(CONFIG)/mock_test
nonblocking_test: $(BINDIR)/$(CONFIG)/nonblocking_test
@ -1316,6 +1317,7 @@ h2_sockpair+trace_test: $(BINDIR)/$(CONFIG)/h2_sockpair+trace_test
h2_sockpair_1byte_test: $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_test
h2_spiffe_test: $(BINDIR)/$(CONFIG)/h2_spiffe_test
h2_ssl_test: $(BINDIR)/$(CONFIG)/h2_ssl_test
h2_ssl_cred_reload_test: $(BINDIR)/$(CONFIG)/h2_ssl_cred_reload_test
h2_ssl_proxy_test: $(BINDIR)/$(CONFIG)/h2_ssl_proxy_test
h2_uds_test: $(BINDIR)/$(CONFIG)/h2_uds_test
inproc_test: $(BINDIR)/$(CONFIG)/inproc_test
@ -1579,6 +1581,7 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/h2_sockpair_1byte_test \
$(BINDIR)/$(CONFIG)/h2_spiffe_test \
$(BINDIR)/$(CONFIG)/h2_ssl_test \
$(BINDIR)/$(CONFIG)/h2_ssl_cred_reload_test \
$(BINDIR)/$(CONFIG)/h2_ssl_proxy_test \
$(BINDIR)/$(CONFIG)/h2_uds_test \
$(BINDIR)/$(CONFIG)/inproc_test \
@ -1699,6 +1702,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/interop_test \
$(BINDIR)/$(CONFIG)/json_run_localhost \
$(BINDIR)/$(CONFIG)/memory_test \
$(BINDIR)/$(CONFIG)/message_allocator_end2end_test \
$(BINDIR)/$(CONFIG)/metrics_client \
$(BINDIR)/$(CONFIG)/mock_test \
$(BINDIR)/$(CONFIG)/nonblocking_test \
@ -1842,6 +1846,7 @@ buildtests_cxx: privatelibs_cxx \
$(BINDIR)/$(CONFIG)/interop_test \
$(BINDIR)/$(CONFIG)/json_run_localhost \
$(BINDIR)/$(CONFIG)/memory_test \
$(BINDIR)/$(CONFIG)/message_allocator_end2end_test \
$(BINDIR)/$(CONFIG)/metrics_client \
$(BINDIR)/$(CONFIG)/mock_test \
$(BINDIR)/$(CONFIG)/nonblocking_test \
@ -2341,6 +2346,8 @@ test_cxx: buildtests_cxx
$(Q) $(BINDIR)/$(CONFIG)/interop_test || ( echo test interop_test failed ; exit 1 )
$(E) "[RUN] Testing memory_test"
$(Q) $(BINDIR)/$(CONFIG)/memory_test || ( echo test memory_test failed ; exit 1 )
$(E) "[RUN] Testing message_allocator_end2end_test"
$(Q) $(BINDIR)/$(CONFIG)/message_allocator_end2end_test || ( echo test message_allocator_end2end_test failed ; exit 1 )
$(E) "[RUN] Testing mock_test"
$(Q) $(BINDIR)/$(CONFIG)/mock_test || ( echo test mock_test failed ; exit 1 )
$(E) "[RUN] Testing nonblocking_test"
@ -3437,6 +3444,7 @@ LIBGRPC_SRC = \
src/core/lib/channel/handshaker_registry.cc \
src/core/lib/channel/status_util.cc \
src/core/lib/compression/compression.cc \
src/core/lib/compression/compression_args.cc \
src/core/lib/compression/compression_internal.cc \
src/core/lib/compression/message_compress.cc \
src/core/lib/compression/stream_compression.cc \
@ -3857,6 +3865,7 @@ LIBGRPC_CRONET_SRC = \
src/core/lib/channel/handshaker_registry.cc \
src/core/lib/channel/status_util.cc \
src/core/lib/compression/compression.cc \
src/core/lib/compression/compression_args.cc \
src/core/lib/compression/compression_internal.cc \
src/core/lib/compression/message_compress.cc \
src/core/lib/compression/stream_compression.cc \
@ -4261,6 +4270,7 @@ LIBGRPC_TEST_UTIL_SRC = \
src/core/lib/channel/handshaker_registry.cc \
src/core/lib/channel/status_util.cc \
src/core/lib/compression/compression.cc \
src/core/lib/compression/compression_args.cc \
src/core/lib/compression/compression_internal.cc \
src/core/lib/compression/message_compress.cc \
src/core/lib/compression/stream_compression.cc \
@ -4572,6 +4582,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
src/core/lib/channel/handshaker_registry.cc \
src/core/lib/channel/status_util.cc \
src/core/lib/compression/compression.cc \
src/core/lib/compression/compression_args.cc \
src/core/lib/compression/compression_internal.cc \
src/core/lib/compression/message_compress.cc \
src/core/lib/compression/stream_compression.cc \
@ -4846,6 +4857,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/channel/handshaker_registry.cc \
src/core/lib/channel/status_util.cc \
src/core/lib/compression/compression.cc \
src/core/lib/compression/compression_args.cc \
src/core/lib/compression/compression_internal.cc \
src/core/lib/compression/message_compress.cc \
src/core/lib/compression/stream_compression.cc \
@ -5384,6 +5396,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/client_interceptor.h \
include/grpcpp/support/config.h \
include/grpcpp/support/interceptor.h \
include/grpcpp/support/message_allocator.h \
include/grpcpp/support/proto_buffer_reader.h \
include/grpcpp/support/proto_buffer_writer.h \
include/grpcpp/support/server_callback.h \
@ -5499,6 +5512,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/intercepted_channel.h \
include/grpcpp/impl/codegen/interceptor.h \
include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/message_allocator.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
include/grpcpp/impl/codegen/rpc_method.h \
@ -5722,6 +5736,7 @@ LIBGRPC++_CRONET_SRC = \
src/core/lib/channel/handshaker_registry.cc \
src/core/lib/channel/status_util.cc \
src/core/lib/compression/compression.cc \
src/core/lib/compression/compression_args.cc \
src/core/lib/compression/compression_internal.cc \
src/core/lib/compression/message_compress.cc \
src/core/lib/compression/stream_compression.cc \
@ -5996,6 +6011,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/client_interceptor.h \
include/grpcpp/support/config.h \
include/grpcpp/support/interceptor.h \
include/grpcpp/support/message_allocator.h \
include/grpcpp/support/proto_buffer_reader.h \
include/grpcpp/support/proto_buffer_writer.h \
include/grpcpp/support/server_callback.h \
@ -6111,6 +6127,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/intercepted_channel.h \
include/grpcpp/impl/codegen/interceptor.h \
include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/message_allocator.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
include/grpcpp/impl/codegen/rpc_method.h \
@ -6516,6 +6533,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/intercepted_channel.h \
include/grpcpp/impl/codegen/interceptor.h \
include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/message_allocator.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
include/grpcpp/impl/codegen/rpc_method.h \
@ -6684,6 +6702,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/intercepted_channel.h \
include/grpcpp/impl/codegen/interceptor.h \
include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/message_allocator.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
include/grpcpp/impl/codegen/rpc_method.h \
@ -6925,6 +6944,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/support/client_interceptor.h \
include/grpcpp/support/config.h \
include/grpcpp/support/interceptor.h \
include/grpcpp/support/message_allocator.h \
include/grpcpp/support/proto_buffer_reader.h \
include/grpcpp/support/proto_buffer_writer.h \
include/grpcpp/support/server_callback.h \
@ -7040,6 +7060,7 @@ PUBLIC_HEADERS_CXX += \
include/grpcpp/impl/codegen/intercepted_channel.h \
include/grpcpp/impl/codegen/interceptor.h \
include/grpcpp/impl/codegen/interceptor_common.h \
include/grpcpp/impl/codegen/message_allocator.h \
include/grpcpp/impl/codegen/metadata_map.h \
include/grpcpp/impl/codegen/method_handler_impl.h \
include/grpcpp/impl/codegen/rpc_method.h \
@ -17402,6 +17423,49 @@ endif
endif
MESSAGE_ALLOCATOR_END2END_TEST_SRC = \
test/cpp/end2end/message_allocator_end2end_test.cc \
MESSAGE_ALLOCATOR_END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MESSAGE_ALLOCATOR_END2END_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/message_allocator_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)/message_allocator_end2end_test: protobuf_dep_error
else
$(BINDIR)/$(CONFIG)/message_allocator_end2end_test: $(PROTOBUF_DEP) $(MESSAGE_ALLOCATOR_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) $(MESSAGE_ALLOCATOR_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)/message_allocator_end2end_test
endif
endif
$(OBJDIR)/$(CONFIG)/test/cpp/end2end/message_allocator_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_message_allocator_end2end_test: $(MESSAGE_ALLOCATOR_END2END_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(MESSAGE_ALLOCATOR_END2END_TEST_OBJS:.o=.dep)
endif
endif
METRICS_CLIENT_SRC = \
$(GENDIR)/src/proto/grpc/testing/metrics.pb.cc $(GENDIR)/src/proto/grpc/testing/metrics.grpc.pb.cc \
test/cpp/interop/metrics_client.cc \
@ -20669,6 +20733,38 @@ endif
endif
H2_SSL_CRED_RELOAD_TEST_SRC = \
test/core/end2end/fixtures/h2_ssl_cred_reload.cc \
H2_SSL_CRED_RELOAD_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(H2_SSL_CRED_RELOAD_TEST_SRC))))
ifeq ($(NO_SECURE),true)
# You can't build secure targets if you don't have OpenSSL.
$(BINDIR)/$(CONFIG)/h2_ssl_cred_reload_test: openssl_dep_error
else
$(BINDIR)/$(CONFIG)/h2_ssl_cred_reload_test: $(H2_SSL_CRED_RELOAD_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(H2_SSL_CRED_RELOAD_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/h2_ssl_cred_reload_test
endif
$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_ssl_cred_reload.o: $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_h2_ssl_cred_reload_test: $(H2_SSL_CRED_RELOAD_TEST_OBJS:.o=.dep)
ifneq ($(NO_SECURE),true)
ifneq ($(NO_DEPS),true)
-include $(H2_SSL_CRED_RELOAD_TEST_OBJS:.o=.dep)
endif
endif
H2_SSL_PROXY_TEST_SRC = \
test/core/end2end/fixtures/h2_ssl_proxy.cc \

@ -9,13 +9,12 @@ grpc_deps()
grpc_test_only_deps()
register_execution_platforms(
"//third_party/toolchains:rbe_ubuntu1604",
"//third_party/toolchains:rbe_ubuntu1604_large",
"//third_party/toolchains:local",
"//third_party/toolchains:local_large",
"//third_party/toolchains:rbe_windows",
)
register_toolchains(
"//third_party/toolchains:cc-toolchain-clang-x86_64-default",
"//third_party/toolchains/bazel_0.23.2_rbe_windows:cc-toolchain-x64_windows",
)
@ -52,3 +51,24 @@ http_archive(
load("//bazel:grpc_python_deps.bzl", "grpc_python_deps")
grpc_python_deps()
load("@bazel_toolchains//rules:rbe_repo.bzl", "rbe_autoconfig")
# Create toolchain configuration for remote execution.
rbe_autoconfig(
name = "rbe_default",
)
load("@bazel_toolchains//rules:environments.bzl", "clang_env")
load("@bazel_skylib//lib:dicts.bzl", "dicts")
# Create msan toolchain configuration for remote execution.
rbe_autoconfig(
name = "rbe_msan",
env = dicts.add(
clang_env(),
{
"BAZEL_LINKOPTS": "-lc++:-lc++abi:-lm",
},
),
)

@ -112,10 +112,7 @@ def grpc_cc_library(
visibility = visibility,
testonly = testonly,
linkopts = linkopts,
includes = [
"include",
"src/core/ext/upb-generated",
],
includes = ["include"] + if_not_windows(["src/core/ext/upb-generated"]),
alwayslink = alwayslink,
data = data,
tags = tags,

@ -110,6 +110,8 @@ def grpc_deps():
http_archive(
name = "boringssl",
# on the chromium-stable-with-bazel branch
# NOTE: This URL generates a tarball containing dynamic date
# information, so the sha256 is not consistent.
url = "https://boringssl.googlesource.com/boringssl/+archive/afc30d43eef92979b05776ec0963c9cede5fb80f.tar.gz",
)
@ -117,6 +119,7 @@ def grpc_deps():
http_archive(
name = "com_github_madler_zlib",
build_file = "@com_github_grpc_grpc//third_party:zlib.BUILD",
sha256 = "6d4d6640ca3121620995ee255945161821218752b551a1a180f4215f7d124d45",
strip_prefix = "zlib-cacf7f1d4e3d44d871b605da3b647f07d718623f",
url = "https://github.com/madler/zlib/archive/cacf7f1d4e3d44d871b605da3b647f07d718623f.tar.gz",
)
@ -124,6 +127,7 @@ def grpc_deps():
if "com_google_protobuf" not in native.existing_rules():
http_archive(
name = "com_google_protobuf",
sha256 = "cf9e2fb1d2cd30ec9d51ff1749045208bd641f290f64b85046485934b0e03783",
strip_prefix = "protobuf-582743bf40c5d3639a70f98f183914a2c0cd0680",
url = "https://github.com/google/protobuf/archive/582743bf40c5d3639a70f98f183914a2c0cd0680.tar.gz",
)
@ -132,6 +136,7 @@ def grpc_deps():
http_archive(
name = "com_github_nanopb_nanopb",
build_file = "@com_github_grpc_grpc//third_party:nanopb.BUILD",
sha256 = "8bbbb1e78d4ddb0a1919276924ab10d11b631df48b657d960e0c795a25515735",
strip_prefix = "nanopb-f8ac463766281625ad710900479130c7fcb4d63b",
url = "https://github.com/nanopb/nanopb/archive/f8ac463766281625ad710900479130c7fcb4d63b.tar.gz",
)
@ -140,6 +145,7 @@ def grpc_deps():
http_archive(
name = "com_github_google_googletest",
build_file = "@com_github_grpc_grpc//third_party:gtest.BUILD",
sha256 = "175a22300b3450e27e5f2e6f95cc9abca74617cbc21a1e0ed19bdfbd22ea0305",
strip_prefix = "googletest-ec44c6c1675c25b9827aacd08c02433cccde7780",
url = "https://github.com/google/googletest/archive/ec44c6c1675c25b9827aacd08c02433cccde7780.tar.gz",
)
@ -147,6 +153,7 @@ def grpc_deps():
if "com_github_gflags_gflags" not in native.existing_rules():
http_archive(
name = "com_github_gflags_gflags",
sha256 = "63ae70ea3e05780f7547d03503a53de3a7d2d83ad1caaa443a31cb20aea28654",
strip_prefix = "gflags-28f50e0fed19872e0fd50dd23ce2ee8cd759338e",
url = "https://github.com/gflags/gflags/archive/28f50e0fed19872e0fd50dd23ce2ee8cd759338e.tar.gz",
)
@ -154,6 +161,7 @@ def grpc_deps():
if "com_github_google_benchmark" not in native.existing_rules():
http_archive(
name = "com_github_google_benchmark",
sha256 = "c7682e9007ddfd94072647abab3e89ffd9084089460ae47d67060974467b58bf",
strip_prefix = "benchmark-e776aa0275e293707b6a0901e0e8d8a8a3679508",
url = "https://github.com/google/benchmark/archive/e776aa0275e293707b6a0901e0e8d8a8a3679508.tar.gz",
)
@ -162,6 +170,7 @@ def grpc_deps():
http_archive(
name = "com_github_cares_cares",
build_file = "@com_github_grpc_grpc//third_party:cares/cares.BUILD",
sha256 = "e8c2751ddc70fed9dc6f999acd92e232d5846f009ee1674f8aee81f19b2b915a",
strip_prefix = "c-ares-e982924acee7f7313b4baa4ee5ec000c5e373c30",
url = "https://github.com/c-ares/c-ares/archive/e982924acee7f7313b4baa4ee5ec000c5e373c30.tar.gz",
)
@ -169,19 +178,20 @@ def grpc_deps():
if "com_google_absl" not in native.existing_rules():
http_archive(
name = "com_google_absl",
sha256 = "5fe2a3a8f8378e81d4d3db6541f48030e04233ccd2d6c7e9d981ed577b314ae8",
strip_prefix = "abseil-cpp-308ce31528a7edfa39f5f6d36142278a0ae1bf45",
url = "https://github.com/abseil/abseil-cpp/archive/308ce31528a7edfa39f5f6d36142278a0ae1bf45.tar.gz",
)
if "com_github_bazelbuild_bazeltoolchains" not in native.existing_rules():
if "bazel_toolchains" not in native.existing_rules():
http_archive(
name = "com_github_bazelbuild_bazeltoolchains",
strip_prefix = "bazel-toolchains-37419a124bdb9af2fec5b99a973d359b6b899b61",
name = "bazel_toolchains",
sha256 = "67335b3563d9b67dc2550b8f27cc689b64fadac491e69ce78763d9ba894cc5cc",
strip_prefix = "bazel-toolchains-cddc376d428ada2927ad359211c3e356bd9c9fbb",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/37419a124bdb9af2fec5b99a973d359b6b899b61.tar.gz",
"https://github.com/bazelbuild/bazel-toolchains/archive/37419a124bdb9af2fec5b99a973d359b6b899b61.tar.gz",
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/cddc376d428ada2927ad359211c3e356bd9c9fbb.tar.gz",
"https://github.com/bazelbuild/bazel-toolchains/archive/cddc376d428ada2927ad359211c3e356bd9c9fbb.tar.gz",
],
sha256 = "ee854b5de299138c1f4a2edb5573d22b21d975acfc7aa938f36d30b49ef97498",
)
if "bazel_skylib" not in native.existing_rules():
@ -195,6 +205,7 @@ def grpc_deps():
if "io_opencensus_cpp" not in native.existing_rules():
http_archive(
name = "io_opencensus_cpp",
sha256 = "3436ca23dc1b3345186defd0f46d64244079ba3d3234a0c5d6ef5e8d5d06c8b5",
strip_prefix = "opencensus-cpp-9b1e354e89bf3d92aedc00af45b418ce870f3d77",
url = "https://github.com/census-instrumentation/opencensus-cpp/archive/9b1e354e89bf3d92aedc00af45b418ce870f3d77.tar.gz",
)
@ -202,6 +213,7 @@ def grpc_deps():
if "upb" not in native.existing_rules():
http_archive(
name = "upb",
sha256 = "0e749a8973968397f849a3b42e28ee9c85dc418c2477954c2a6a4495f323241d",
strip_prefix = "upb-ed9faae0993704b033c594b072d65e1bf19207fa",
url = "https://github.com/google/upb/archive/ed9faae0993704b033c594b072d65e1bf19207fa.tar.gz",
)
@ -223,6 +235,7 @@ def grpc_test_only_deps():
if "com_github_twisted_twisted" not in native.existing_rules():
http_archive(
name = "com_github_twisted_twisted",
sha256 = "ca17699d0d62eafc5c28daf2c7d0a18e62ae77b4137300b6c7d7868b39b06139",
strip_prefix = "twisted-twisted-17.5.0",
url = "https://github.com/twisted/twisted/archive/twisted-17.5.0.zip",
build_file = "@com_github_grpc_grpc//third_party:twisted.BUILD",
@ -231,6 +244,7 @@ def grpc_test_only_deps():
if "com_github_yaml_pyyaml" not in native.existing_rules():
http_archive(
name = "com_github_yaml_pyyaml",
sha256 = "6b4314b1b2051ddb9d4fcd1634e1fa9c1bb4012954273c9ff3ef689f6ec6c93e",
strip_prefix = "pyyaml-3.12",
url = "https://github.com/yaml/pyyaml/archive/3.12.zip",
build_file = "@com_github_grpc_grpc//third_party:yaml.BUILD",
@ -239,6 +253,7 @@ def grpc_test_only_deps():
if "com_github_twisted_incremental" not in native.existing_rules():
http_archive(
name = "com_github_twisted_incremental",
sha256 = "f0ca93359ee70243ff7fbf2d904a6291810bd88cb80ed4aca6fa77f318a41a36",
strip_prefix = "incremental-incremental-17.5.0",
url = "https://github.com/twisted/incremental/archive/incremental-17.5.0.zip",
build_file = "@com_github_grpc_grpc//third_party:incremental.BUILD",
@ -247,6 +262,7 @@ def grpc_test_only_deps():
if "com_github_zopefoundation_zope_interface" not in native.existing_rules():
http_archive(
name = "com_github_zopefoundation_zope_interface",
sha256 = "e9579fc6149294339897be3aa9ecd8a29217c0b013fe6f44fcdae00e3204198a",
strip_prefix = "zope.interface-4.4.3",
url = "https://github.com/zopefoundation/zope.interface/archive/4.4.3.zip",
build_file = "@com_github_grpc_grpc//third_party:zope_interface.BUILD",
@ -255,6 +271,7 @@ def grpc_test_only_deps():
if "com_github_twisted_constantly" not in native.existing_rules():
http_archive(
name = "com_github_twisted_constantly",
sha256 = "2702cd322161a579d2c0dbf94af4e57712eedc7bd7bbbdc554a230544f7d346c",
strip_prefix = "constantly-15.1.0",
url = "https://github.com/twisted/constantly/archive/15.1.0.zip",
build_file = "@com_github_grpc_grpc//third_party:constantly.BUILD",

@ -245,6 +245,7 @@ filegroups:
- src/core/lib/channel/handshaker_registry.cc
- src/core/lib/channel/status_util.cc
- src/core/lib/compression/compression.cc
- src/core/lib/compression/compression_args.cc
- src/core/lib/compression/compression_internal.cc
- src/core/lib/compression/message_compress.cc
- src/core/lib/compression/stream_compression.cc
@ -418,6 +419,7 @@ filegroups:
- src/core/lib/channel/handshaker_registry.h
- src/core/lib/channel/status_util.h
- src/core/lib/compression/algorithm_metadata.h
- src/core/lib/compression/compression_args.h
- src/core/lib/compression/compression_internal.h
- src/core/lib/compression/message_compress.h
- src/core/lib/compression/stream_compression.h
@ -1256,6 +1258,7 @@ filegroups:
- include/grpcpp/impl/codegen/intercepted_channel.h
- include/grpcpp/impl/codegen/interceptor.h
- include/grpcpp/impl/codegen/interceptor_common.h
- include/grpcpp/impl/codegen/message_allocator.h
- include/grpcpp/impl/codegen/metadata_map.h
- include/grpcpp/impl/codegen/method_handler_impl.h
- include/grpcpp/impl/codegen/rpc_method.h
@ -1395,6 +1398,7 @@ filegroups:
- include/grpcpp/support/client_interceptor.h
- include/grpcpp/support/config.h
- include/grpcpp/support/interceptor.h
- include/grpcpp/support/message_allocator.h
- include/grpcpp/support/proto_buffer_reader.h
- include/grpcpp/support/proto_buffer_writer.h
- include/grpcpp/support/server_callback.h
@ -5068,6 +5072,19 @@ targets:
uses:
- grpc++_test
uses_polling: false
- name: message_allocator_end2end_test
gtest: true
cpu_cost: 0.5
build: test
language: c++
src:
- test/cpp/end2end/message_allocator_end2end_test.cc
deps:
- grpc++_test_util
- grpc_test_util
- grpc++
- grpc
- gpr
- name: metrics_client
build: test
run: false

@ -97,6 +97,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/channel/handshaker_registry.cc \
src/core/lib/channel/status_util.cc \
src/core/lib/compression/compression.cc \
src/core/lib/compression/compression_args.cc \
src/core/lib/compression/compression_internal.cc \
src/core/lib/compression/message_compress.cc \
src/core/lib/compression/stream_compression.cc \

@ -72,6 +72,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\channel\\handshaker_registry.cc " +
"src\\core\\lib\\channel\\status_util.cc " +
"src\\core\\lib\\compression\\compression.cc " +
"src\\core\\lib\\compression\\compression_args.cc " +
"src\\core\\lib\\compression\\compression_internal.cc " +
"src\\core\\lib\\compression\\message_compress.cc " +
"src\\core\\lib\\compression\\stream_compression.cc " +

@ -135,7 +135,7 @@ Code at `src/core/lib/iomgr/ev_epollex_posix.cc`
- The same FD can be in multiple `Pollable`s (even if one of the `Pollable`s is of type PO_FD)
- There cannot be two `Pollable`s of type PO_FD for the same fd
- Why do we need `Pollable` of type PO_FD and PO_EMTPY ?
- Why do we need `Pollable` of type PO_FD and PO_EMPTY ?
- The main reason is the Sync client API
- We create one new completion queue per call. If we didn’t have PO_EMPTY and PO_FD type pollables, then every call on a given channel will effectively have to create a `Pollable` and hence an epollset. This is because every completion queue automatically creates a pollset and the channel fd will have to be put in that pollset. This clearly requires an epollset to put that fd. Creating an epollset per call (even if we delete the epollset once the call is completed) would mean a lot of sys calls to create/delete epoll fds. This is clearly not a good idea.
- With these new types of `Pollable`s, all pollsets (corresponding to the new per-call completion queue) will initially point to PO_EMPTY global epollset. Then once the channel fd is added to the pollset, the pollset will point to the `Pollable` of type PO_FD containing just that fd (i.e it will reuse the existing `Pollable`). This way, the epoll fd creation/deletion churn is avoided.

@ -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
@ -145,13 +146,3 @@ some configuration as environment variables that can be set.
* grpc_cfstream
set to 1 to turn on CFStream experiment. With this experiment gRPC uses CFStream API to make TCP
connections. The option is only available on iOS platform and when macro GRPC_CFSTREAM is defined.
* GRPC_ARENA_INIT_STRATEGY
Selects the initialization strategy for blocks allocated in the arena. Valid
values are:
- no_init (default): Do not initialize the arena block.
- zero_init: Initialize the arena blocks with 0.
- non_zero_init: Initialize the arena blocks with a non-zero value.
NOTE: This environment variable is experimental and will be removed. Thus, it
should not be relied upon.

@ -53,7 +53,7 @@ namespace HelloworldXamarin.iOS
public override void DidEnterBackground(UIApplication application)
{
// Use this method to release shared resources, save user data, invalidate timers and store the application state.
// If your application supports background exection this method is called instead of WillTerminate when the user quits.
// If your application supports background execution this method is called instead of WillTerminate when the user quits.
}
public override void WillEnterForeground(UIApplication application)

@ -46,8 +46,16 @@ static NSString * const kTestHostAddress = @"grpc-test.sandbox.googleapis.com";
}
@end
@interface MakeRPCViewController ()<GRPCProtoResponseHandler>
@end
@implementation MakeRPCViewController
- (dispatch_queue_t)dispatchQueue {
return dispatch_get_main_queue();
}
- (void)viewWillAppear:(BOOL)animated {
// Create a service client and a proto request as usual.
@ -57,28 +65,30 @@ static NSString * const kTestHostAddress = @"grpc-test.sandbox.googleapis.com";
request.fillUsername = YES;
request.fillOauthScope = YES;
// Create a not-yet-started RPC. We want to set the request headers on this object before starting
// it.
ProtoRPC *call =
[client RPCToUnaryCallWithRequest:request handler:^(AUTHResponse *response, NSError *error) {
if (response) {
// This test server responds with the email and scope of the access token it receives.
self.mainLabel.text = [NSString stringWithFormat:@"Used scope: %@ on behalf of user %@",
response.oauthScope, response.username];
} else {
self.mainLabel.text = error.UIDescription;
}
}];
// Set the access token to be used.
NSString *accessToken = GIDSignIn.sharedInstance.currentUser.authentication.accessToken;
call.requestHeaders[@"Authorization"] = [@"Bearer " stringByAppendingString:accessToken];
// Start the RPC.
// Set the request header with call options
GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
options.oauth2AccessToken = GIDSignIn.sharedInstance.currentUser.authentication.accessToken;
GRPCUnaryProtoCall *call = [client unaryCallWithMessage:request
responseHandler:self
callOptions:options];
[call start];
self.mainLabel.text = @"Waiting for RPC to complete...";
}
- (void)didReceiveProtoMessage:(GPBMessage *)message {
AUTHResponse *response = (AUTHResponse *)message;
if (response) {
// This test server responds with the email and scope of the access token it receives.
self.mainLabel.text = [NSString stringWithFormat:@"Used scope: %@ on behalf of user %@",
response.oauthScope, response.username];
}
}
- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
if (error) {
self.mainLabel.text = error.UIDescription;
}
}
@end

@ -25,20 +25,41 @@
static NSString * const kHostAddress = @"localhost:50051";
@interface HLWResponseHandler : NSObject<GRPCProtoResponseHandler>
@end
// A response handler object dispatching messages to main queue
@implementation HLWResponseHandler
- (dispatch_queue_t)dispatchQueue {
return dispatch_get_main_queue();
}
- (void)didReceiveProtoMessage:(GPBMessage *)message {
NSLog(@"%@", message);
}
@end
int main(int argc, char * argv[]) {
@autoreleasepool {
[GRPCCall useInsecureConnectionsForHost:kHostAddress];
[GRPCCall setUserAgentPrefix:@"HelloWorld/1.0" forHost:kHostAddress];
HLWGreeter *client = [[HLWGreeter alloc] initWithHost:kHostAddress];
HLWHelloRequest *request = [HLWHelloRequest message];
request.name = @"Objective-C";
[client sayHelloWithRequest:request handler:^(HLWHelloReply *response, NSError *error) {
NSLog(@"%@", response.message);
}];
GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
// this example does not use TLS (secure channel); use insecure channel instead
options.transportType = GRPCTransportTypeInsecure;
options.userAgentPrefix = @"HelloWorld/1.0";
GRPCUnaryProtoCall *call = [client sayHelloWithMessage:request
responseHandler:[[HLWResponseHandler alloc] init]
callOptions:options];
[call start];
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

@ -24,19 +24,40 @@
static NSString * const kHostAddress = @"localhost:50051";
@interface HLWResponseHandler : NSObject<GRPCProtoResponseHandler>
@end
// A response handler object dispatching messages to main queue
@implementation HLWResponseHandler
- (dispatch_queue_t)dispatchQueue {
return dispatch_get_main_queue();
}
- (void)didReceiveProtoMessage:(GPBMessage *)message {
NSLog(@"%@", message);
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
[GRPCCall useInsecureConnectionsForHost:kHostAddress];
[GRPCCall setUserAgentPrefix:@"HelloWorld/1.0" forHost:kHostAddress];
HLWGreeter *client = [[HLWGreeter alloc] initWithHost:kHostAddress];
HLWHelloRequest *request = [HLWHelloRequest message];
request.name = @"Objective-C";
[client sayHelloWithRequest:request handler:^(HLWHelloReply *response, NSError *error) {
NSLog(@"%@", response.message);
}];
GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
// this example does not use TLS (secure channel); use insecure channel instead
options.transportType = GRPCTransportTypeInsecure;
options.userAgentPrefix = @"HelloWorld/1.0";
GRPCUnaryProtoCall *call = [client sayHelloWithMessage:request
responseHandler:[[HLWResponseHandler alloc] init]
callOptions:options];
[call start];
}
return NSApplicationMain(argc, argv);

@ -17,10 +17,7 @@
*/
#import <UIKit/UIKit.h>
#import <GRPCClient/GRPCCall+Tests.h>
#import <RouteGuide/RouteGuide.pbrpc.h>
#import <RxLibrary/GRXWriter+Immediate.h>
#import <RxLibrary/GRXWriter+Transformations.h>
static NSString * const kHostAddress = @"localhost:50051";
@ -65,7 +62,7 @@ static NSString * const kHostAddress = @"localhost:50051";
* Run the getFeature demo. Calls getFeature with a point known to have a feature and a point known
* not to have a feature.
*/
@interface GetFeatureViewController : UIViewController
@interface GetFeatureViewController : UIViewController<GRPCProtoResponseHandler>
@property (weak, nonatomic) IBOutlet UILabel *outputLabel;
@ -75,39 +72,56 @@ static NSString * const kHostAddress = @"localhost:50051";
RTGRouteGuide *_service;
}
- (void)execRequest {
void (^handler)(RTGFeature *response, NSError *error) = ^(RTGFeature *response, NSError *error) {
// TODO(makdharma): Remove boilerplate by consolidating into one log function.
if (response.name.length) {
NSString *str =[NSString stringWithFormat:@"%@\nFound feature called %@ at %@.", self.outputLabel.text, response.location, response.name];
self.outputLabel.text = str;
NSLog(@"Found feature called %@ at %@.", response.name, response.location);
} else if (response) {
NSString *str =[NSString stringWithFormat:@"%@\nFound no features at %@", self.outputLabel.text,response.location];
self.outputLabel.text = str;
NSLog(@"Found no features at %@", response.location);
} else {
NSString *str =[NSString stringWithFormat:@"%@\nRPC error: %@", self.outputLabel.text, error];
self.outputLabel.text = str;
NSLog(@"RPC error: %@", error);
}
};
- (dispatch_queue_t)dispatchQueue {
return dispatch_get_main_queue();
}
- (void)didReceiveProtoMessage:(GPBMessage *)message {
RTGFeature *response = (RTGFeature *)message;
// TODO(makdharma): Remove boilerplate by consolidating into one log function.
if (response.name.length != 0) {
NSString *str =[NSString stringWithFormat:@"%@\nFound feature called %@ at %@.", self.outputLabel.text, response.location, response.name];
self.outputLabel.text = str;
NSLog(@"Found feature called %@ at %@.", response.name, response.location);
} else if (response) {
NSString *str =[NSString stringWithFormat:@"%@\nFound no features at %@", self.outputLabel.text,response.location];
self.outputLabel.text = str;
NSLog(@"Found no features at %@", response.location);
}
}
- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
if (error) {
NSString *str =[NSString stringWithFormat:@"%@\nRPC error: %@", self.outputLabel.text, error];
self.outputLabel.text = str;
NSLog(@"RPC error: %@", error);
}
}
- (void)execRequest {
RTGPoint *point = [RTGPoint message];
point.latitude = 409146138;
point.longitude = -746188906;
[_service getFeatureWithRequest:point handler:handler];
[_service getFeatureWithRequest:[RTGPoint message] handler:handler];
GRPCUnaryProtoCall *call = [_service getFeatureWithMessage:point
responseHandler:self
callOptions:nil];
[call start];
call = [_service getFeatureWithMessage:[RTGPoint message]
responseHandler:self
callOptions:nil];
[call start];
}
- (void)viewDidLoad {
[super viewDidLoad];
// This only needs to be done once per host, before creating service objects for that host.
[GRPCCall useInsecureConnectionsForHost:kHostAddress];
GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
options.transportType = GRPCTransportTypeInsecure;
_service = [[RTGRouteGuide alloc] initWithHost:kHostAddress];
_service = [[RTGRouteGuide alloc] initWithHost:kHostAddress callOptions:options];
}
- (void)viewDidAppear:(BOOL)animated {
@ -126,7 +140,7 @@ static NSString * const kHostAddress = @"localhost:50051";
* Run the listFeatures demo. Calls listFeatures with a rectangle containing all of the features in
* the pre-generated database. Prints each response as it comes in.
*/
@interface ListFeaturesViewController : UIViewController
@interface ListFeaturesViewController : UIViewController<GRPCProtoResponseHandler>
@property (weak, nonatomic) IBOutlet UILabel *outputLabel;
@ -136,6 +150,10 @@ static NSString * const kHostAddress = @"localhost:50051";
RTGRouteGuide *_service;
}
- (dispatch_queue_t)dispatchQueue {
return dispatch_get_main_queue();
}
- (void)execRequest {
RTGRectangle *rectangle = [RTGRectangle message];
rectangle.lo.latitude = 405E6;
@ -144,24 +162,36 @@ static NSString * const kHostAddress = @"localhost:50051";
rectangle.hi.longitude = -745E6;
NSLog(@"Looking for features between %@ and %@", rectangle.lo, rectangle.hi);
[_service listFeaturesWithRequest:rectangle
eventHandler:^(BOOL done, RTGFeature *response, NSError *error) {
if (response) {
NSString *str =[NSString stringWithFormat:@"%@\nFound feature at %@ called %@.", self.outputLabel.text, response.location, response.name];
self.outputLabel.text = str;
NSLog(@"Found feature at %@ called %@.", response.location, response.name);
} else if (error) {
NSString *str =[NSString stringWithFormat:@"%@\nRPC error: %@", self.outputLabel.text, error];
self.outputLabel.text = str;
NSLog(@"RPC error: %@", error);
}
}];
GRPCUnaryProtoCall *call = [_service listFeaturesWithMessage:rectangle
responseHandler:self
callOptions:nil];
[call start];
}
- (void)didReceiveProtoMessage:(GPBMessage *)message {
RTGFeature *response = (RTGFeature *)message;
if (response) {
NSString *str =[NSString stringWithFormat:@"%@\nFound feature at %@ called %@.", self.outputLabel.text, response.location, response.name];
self.outputLabel.text = str;
NSLog(@"Found feature at %@ called %@.", response.location, response.name);
}
}
- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
if (error) {
NSString *str =[NSString stringWithFormat:@"%@\nRPC error: %@", self.outputLabel.text, error];
self.outputLabel.text = str;
NSLog(@"RPC error: %@", error);
}
}
- (void)viewDidLoad {
[super viewDidLoad];
_service = [[RTGRouteGuide alloc] initWithHost:kHostAddress];
GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
options.transportType = GRPCTransportTypeInsecure;
_service = [[RTGRouteGuide alloc] initWithHost:kHostAddress callOptions:options];
}
- (void)viewDidAppear:(BOOL)animated {
@ -173,7 +203,6 @@ static NSString * const kHostAddress = @"localhost:50051";
@end
#pragma mark Demo: Record Route
/**
@ -181,7 +210,7 @@ static NSString * const kHostAddress = @"localhost:50051";
* database with a variable delay in between. Prints the statistics when they are sent from the
* server.
*/
@interface RecordRouteViewController : UIViewController
@interface RecordRouteViewController : UIViewController<GRPCProtoResponseHandler>
@property (weak, nonatomic) IBOutlet UILabel *outputLabel;
@ -191,47 +220,71 @@ static NSString * const kHostAddress = @"localhost:50051";
RTGRouteGuide *_service;
}
- (dispatch_queue_t)dispatchQueue {
return dispatch_get_main_queue();
}
- (void)execRequest {
NSString *dataBasePath = [NSBundle.mainBundle pathForResource:@"route_guide_db"
ofType:@"json"];
NSData *dataBaseContent = [NSData dataWithContentsOfFile:dataBasePath];
NSArray *features = [NSJSONSerialization JSONObjectWithData:dataBaseContent options:0 error:NULL];
NSError *error;
NSArray *features = [NSJSONSerialization JSONObjectWithData:dataBaseContent options:0 error:&error];
if (error) {
NSLog(@"Error reading database.");
NSString *str = @"Error reading database.";
self.outputLabel.text = str;
return;
}
GRXWriter *locations = [[GRXWriter writerWithContainer:features] map:^id(id feature) {
GRPCStreamingProtoCall *call = [_service recordRouteWithResponseHandler:self
callOptions:nil];
[call start];
for (id feature in features) {
RTGPoint *location = [RTGPoint message];
location.longitude = [((NSNumber *) feature[@"location"][@"longitude"]) intValue];
location.latitude = [((NSNumber *) feature[@"location"][@"latitude"]) intValue];
NSString *str =[NSString stringWithFormat:@"%@\nVisiting point %@", self.outputLabel.text, location];
self.outputLabel.text = str;
NSLog(@"Visiting point %@", location);
return location;
}];
[_service recordRouteWithRequestsWriter:locations
handler:^(RTGRouteSummary *response, NSError *error) {
if (response) {
NSString *str =[NSString stringWithFormat:
@"%@\nFinished trip with %i points\nPassed %i features\n"
"Travelled %i meters\nIt took %i seconds",
self.outputLabel.text, response.pointCount, response.featureCount,
response.distance, response.elapsedTime];
self.outputLabel.text = str;
NSLog(@"Finished trip with %i points", response.pointCount);
NSLog(@"Passed %i features", response.featureCount);
NSLog(@"Travelled %i meters", response.distance);
NSLog(@"It took %i seconds", response.elapsedTime);
} else {
NSString *str =[NSString stringWithFormat:@"%@\nRPC error: %@", self.outputLabel.text, error];
self.outputLabel.text = str;
NSLog(@"RPC error: %@", error);
}
}];
[call writeMessage:location];
}
[call finish];
}
- (void)didReceiveProtoMessage:(GPBMessage *)message {
RTGRouteSummary *response = (RTGRouteSummary *)message;
if (response) {
NSString *str =[NSString stringWithFormat:
@"%@\nFinished trip with %i points\nPassed %i features\n"
"Travelled %i meters\nIt took %i seconds",
self.outputLabel.text, response.pointCount, response.featureCount,
response.distance, response.elapsedTime];
self.outputLabel.text = str;
NSLog(@"Finished trip with %i points", response.pointCount);
NSLog(@"Passed %i features", response.featureCount);
NSLog(@"Travelled %i meters", response.distance);
NSLog(@"It took %i seconds", response.elapsedTime);
}
}
- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
if (error) {
NSString *str =[NSString stringWithFormat:@"%@\nRPC error: %@", self.outputLabel.text, error];
self.outputLabel.text = str;
NSLog(@"RPC error: %@", error);
}
}
- (void)viewDidLoad {
[super viewDidLoad];
_service = [[RTGRouteGuide alloc] initWithHost:kHostAddress];
GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
options.transportType = GRPCTransportTypeInsecure;
_service = [[RTGRouteGuide alloc] initWithHost:kHostAddress callOptions:options];
}
- (void)viewDidAppear:(BOOL)animated {
@ -250,7 +303,7 @@ static NSString * const kHostAddress = @"localhost:50051";
* Run the routeChat demo. Send some chat messages, and print any chat messages that are sent from
* the server.
*/
@interface RouteChatViewController : UIViewController
@interface RouteChatViewController : UIViewController<GRPCProtoResponseHandler>
@property (weak, nonatomic) IBOutlet UILabel *outputLabel;
@ -260,38 +313,52 @@ static NSString * const kHostAddress = @"localhost:50051";
RTGRouteGuide *_service;
}
- (dispatch_queue_t)dispatchQueue {
return dispatch_get_main_queue();
}
- (void)execRequest {
NSArray *notes = @[[RTGRouteNote noteWithMessage:@"First message" latitude:0 longitude:0],
[RTGRouteNote noteWithMessage:@"Second message" latitude:0 longitude:1],
[RTGRouteNote noteWithMessage:@"Third message" latitude:1 longitude:0],
[RTGRouteNote noteWithMessage:@"Fourth message" latitude:0 longitude:0]];
GRXWriter *notesWriter = [[GRXWriter writerWithContainer:notes] map:^id(RTGRouteNote *note) {
NSLog(@"Sending message %@ at %@", note.message, note.location);
return note;
}];
[_service routeChatWithRequestsWriter:notesWriter
eventHandler:^(BOOL done, RTGRouteNote *note, NSError *error) {
if (note) {
NSString *str =[NSString stringWithFormat:@"%@\nGot message %@ at %@",
self.outputLabel.text, note.message, note.location];
self.outputLabel.text = str;
NSLog(@"Got message %@ at %@", note.message, note.location);
} else if (error) {
NSString *str =[NSString stringWithFormat:@"%@\nRPC error: %@", self.outputLabel.text, error];
self.outputLabel.text = str;
NSLog(@"RPC error: %@", error);
}
if (done) {
NSLog(@"Chat ended.");
}
}];
GRPCStreamingProtoCall *call = [_service routeChatWithResponseHandler:self
callOptions:nil];
[call start];
for (RTGRouteNote *note in notes) {
[call writeMessage:note];
}
[call finish];
}
- (void)didReceiveProtoMessage:(GPBMessage *)message {
RTGRouteNote *note = (RTGRouteNote *)message;
if (note) {
NSString *str =[NSString stringWithFormat:@"%@\nGot message %@ at %@",
self.outputLabel.text, note.message, note.location];
self.outputLabel.text = str;
NSLog(@"Got message %@ at %@", note.message, note.location);
}
}
- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
if (!error) {
NSLog(@"Chat ended.");
} else {
NSString *str =[NSString stringWithFormat:@"%@\nRPC error: %@", self.outputLabel.text, error];
self.outputLabel.text = str;
NSLog(@"RPC error: %@", error);
}
}
- (void)viewDidLoad {
[super viewDidLoad];
_service = [[RTGRouteGuide alloc] initWithHost:kHostAddress];
GRPCMutableCallOptions *options = [[GRPCMutableCallOptions alloc] init];
options.transportType = GRPCTransportTypeInsecure;
_service = [[RTGRouteGuide alloc] initWithHost:kHostAddress callOptions:options];
}
- (void)viewDidAppear:(BOOL)animated {

@ -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.
load("@grpc_python_dependencies//:requirements.bzl", "requirement")
py_library(
name = "wait_for_ready_example",
testonly = 1,
srcs = ["wait_for_ready_example.py"],
deps = [
"//src/python/grpcio/grpc:grpcio",
"//examples:py_helloworld",
],
)
py_test(
name = "test/_wait_for_ready_example_test",
srcs = ["test/_wait_for_ready_example_test.py"],
deps = [":wait_for_ready_example",],
size = "small",
)

@ -0,0 +1,32 @@
# gRPC Python Example for Wait-for-ready
The default behavior of an RPC is to fail instantly if the server is not ready yet. This example demonstrates how to change that behavior.
### Definition of 'wait-for-ready' semantics
> If an RPC is issued but the channel is in TRANSIENT_FAILURE or SHUTDOWN states, the RPC is unable to be transmitted promptly. By default, gRPC implementations SHOULD fail such RPCs immediately. This is known as "fail fast," but the usage of the term is historical. RPCs SHOULD NOT fail as a result of the channel being in other states (CONNECTING, READY, or IDLE).
>
> gRPC implementations MAY provide a per-RPC option to not fail RPCs as a result of the channel being in TRANSIENT_FAILURE state. Instead, the implementation queues the RPCs until the channel is READY. This is known as "wait for ready." The RPCs SHOULD still fail before READY if there are unrelated reasons, such as the channel is SHUTDOWN or the RPC's deadline is reached.
>
> From https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md
### Use cases for 'wait-for-ready'
When developers spin up gRPC clients and servers at the same time, it is very like to fail first couple RPC calls due to unavailability of the server. If developers failed to prepare for this situation, the result can be catastrophic. But with 'wait-for-ready' semantics, developers can initialize the client and server in any order, especially useful in testing.
Also, developers may ensure the server is up before starting client. But in some cases like transient network failure may result in a temporary unavailability of the server. With 'wait-for-ready' semantics, those RPC calls will automatically wait until the server is ready to accept incoming requests.
### DEMO Snippets
```Python
# Per RPC level
stub = ...Stub(...)
stub.important_transaction_1(..., wait_for_ready=True)
stub.unimportant_transaction_2(...)
stub.important_transaction_3(..., wait_for_ready=True)
stub.unimportant_transaction_4(...)
# The unimportant transactions can be status report, or health check, etc.
```

@ -1,5 +1,4 @@
#!/bin/sh
# Copyright 2019 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.
@ -12,18 +11,21 @@
# 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.
"""Tests of the wait-for-ready example."""
set -e
import unittest
import logging
cd "$(dirname "$0")/../../.."
from examples.python.wait_for_ready import wait_for_ready_example
#
# Prevent the use of synchronization and threading constructs from std:: since
# the code should be using grpc_core::Mutex, grpc::internal::Mutex,
# grpc_core::Thread, etc.
#
egrep -Irn \
'std::(mutex|condition_variable|lock_guard|unique_lock|thread)' \
include/grpc include/grpcpp src/core src/cpp | diff - /dev/null
class WaitForReadyExampleTest(unittest.TestCase):
def test_wait_for_ready_example(self):
wait_for_ready_example.main()
# No unhandled exception raised, no deadlock, test passed!
if __name__ == '__main__':
logging.basicConfig()
unittest.main(verbosity=2)

@ -0,0 +1,114 @@
# 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 example of utilizing wait-for-ready flag."""
from __future__ import print_function
import logging
from concurrent import futures
from contextlib import contextmanager
import socket
import threading
import grpc
from examples.protos import helloworld_pb2
from examples.protos import helloworld_pb2_grpc
_LOGGER = logging.getLogger(__name__)
_LOGGER.setLevel(logging.INFO)
_ONE_DAY_IN_SECONDS = 60 * 60 * 24
@contextmanager
def get_free_loopback_tcp_port():
tcp_socket = socket.socket(socket.AF_INET6)
tcp_socket.bind(('', 0))
address_tuple = tcp_socket.getsockname()
yield "[::1]:%s" % (address_tuple[1])
tcp_socket.close()
class Greeter(helloworld_pb2_grpc.GreeterServicer):
def SayHello(self, request, unused_context):
return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
def create_server(server_address):
server = grpc.server(futures.ThreadPoolExecutor())
helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
bound_port = server.add_insecure_port(server_address)
assert bound_port == int(server_address.split(':')[-1])
return server
def process(stub, wait_for_ready=None):
try:
response = stub.SayHello(
helloworld_pb2.HelloRequest(name='you'),
wait_for_ready=wait_for_ready)
message = response.message
except grpc.RpcError as rpc_error:
assert rpc_error.code() == grpc.StatusCode.UNAVAILABLE
assert not wait_for_ready
message = rpc_error
else:
assert wait_for_ready
_LOGGER.info("Wait-for-ready %s, client received: %s", "enabled"
if wait_for_ready else "disabled", message)
def main():
# Pick a random free port
with get_free_loopback_tcp_port() as server_address:
# Register connectivity event to notify main thread
transient_failure_event = threading.Event()
def wait_for_transient_failure(channel_connectivity):
if channel_connectivity == grpc.ChannelConnectivity.TRANSIENT_FAILURE:
transient_failure_event.set()
# Create gRPC channel
channel = grpc.insecure_channel(server_address)
channel.subscribe(wait_for_transient_failure)
stub = helloworld_pb2_grpc.GreeterStub(channel)
# Fire an RPC without wait_for_ready
thread_disabled_wait_for_ready = threading.Thread(
target=process, args=(stub, False))
thread_disabled_wait_for_ready.start()
# Fire an RPC with wait_for_ready
thread_enabled_wait_for_ready = threading.Thread(
target=process, args=(stub, True))
thread_enabled_wait_for_ready.start()
# Wait for the channel entering TRANSIENT FAILURE state.
transient_failure_event.wait()
server = create_server(server_address)
server.start()
# Expected to fail with StatusCode.UNAVAILABLE.
thread_disabled_wait_for_ready.join()
# Expected to success.
thread_enabled_wait_for_ready.join()
server.stop(None)
channel.close()
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
main()

@ -28,7 +28,7 @@ def main
stub = EchoWithoutProtobuf::Stub.new('localhost:50051', :this_channel_is_insecure)
user = ARGV.size > 0 ? ARGV[0] : 'world'
message = stub.echo("hello #{user}")
p "Reponse: #{message}"
p "Response: #{message}"
end
main

@ -133,6 +133,7 @@ Pod::Spec.new do |s|
'include/grpcpp/support/client_interceptor.h',
'include/grpcpp/support/config.h',
'include/grpcpp/support/interceptor.h',
'include/grpcpp/support/message_allocator.h',
'include/grpcpp/support/proto_buffer_reader.h',
'include/grpcpp/support/proto_buffer_writer.h',
'include/grpcpp/support/server_callback.h',
@ -167,6 +168,7 @@ Pod::Spec.new do |s|
'include/grpcpp/impl/codegen/intercepted_channel.h',
'include/grpcpp/impl/codegen/interceptor.h',
'include/grpcpp/impl/codegen/interceptor_common.h',
'include/grpcpp/impl/codegen/message_allocator.h',
'include/grpcpp/impl/codegen/metadata_map.h',
'include/grpcpp/impl/codegen/method_handler_impl.h',
'include/grpcpp/impl/codegen/rpc_method.h',
@ -412,6 +414,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/handshaker_registry.h',
'src/core/lib/channel/status_util.h',
'src/core/lib/compression/algorithm_metadata.h',
'src/core/lib/compression/compression_args.h',
'src/core/lib/compression/compression_internal.h',
'src/core/lib/compression/message_compress.h',
'src/core/lib/compression/stream_compression.h',
@ -604,6 +607,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/handshaker_registry.h',
'src/core/lib/channel/status_util.h',
'src/core/lib/compression/algorithm_metadata.h',
'src/core/lib/compression/compression_args.h',
'src/core/lib/compression/compression_internal.h',
'src/core/lib/compression/message_compress.h',
'src/core/lib/compression/stream_compression.h',

@ -393,6 +393,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/handshaker_registry.h',
'src/core/lib/channel/status_util.h',
'src/core/lib/compression/algorithm_metadata.h',
'src/core/lib/compression/compression_args.h',
'src/core/lib/compression/compression_internal.h',
'src/core/lib/compression/message_compress.h',
'src/core/lib/compression/stream_compression.h',
@ -547,6 +548,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/handshaker_registry.cc',
'src/core/lib/channel/status_util.cc',
'src/core/lib/compression/compression.cc',
'src/core/lib/compression/compression_args.cc',
'src/core/lib/compression/compression_internal.cc',
'src/core/lib/compression/message_compress.cc',
'src/core/lib/compression/stream_compression.cc',
@ -1033,6 +1035,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/handshaker_registry.h',
'src/core/lib/channel/status_util.h',
'src/core/lib/compression/algorithm_metadata.h',
'src/core/lib/compression/compression_args.h',
'src/core/lib/compression/compression_internal.h',
'src/core/lib/compression/message_compress.h',
'src/core/lib/compression/stream_compression.h',

@ -327,6 +327,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/channel/handshaker_registry.h )
s.files += %w( src/core/lib/channel/status_util.h )
s.files += %w( src/core/lib/compression/algorithm_metadata.h )
s.files += %w( src/core/lib/compression/compression_args.h )
s.files += %w( src/core/lib/compression/compression_internal.h )
s.files += %w( src/core/lib/compression/message_compress.h )
s.files += %w( src/core/lib/compression/stream_compression.h )
@ -481,6 +482,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/channel/handshaker_registry.cc )
s.files += %w( src/core/lib/channel/status_util.cc )
s.files += %w( src/core/lib/compression/compression.cc )
s.files += %w( src/core/lib/compression/compression_args.cc )
s.files += %w( src/core/lib/compression/compression_internal.cc )
s.files += %w( src/core/lib/compression/message_compress.cc )
s.files += %w( src/core/lib/compression/stream_compression.cc )

@ -279,6 +279,7 @@
'src/core/lib/channel/handshaker_registry.cc',
'src/core/lib/channel/status_util.cc',
'src/core/lib/compression/compression.cc',
'src/core/lib/compression/compression_args.cc',
'src/core/lib/compression/compression_internal.cc',
'src/core/lib/compression/message_compress.cc',
'src/core/lib/compression/stream_compression.cc',
@ -646,6 +647,7 @@
'src/core/lib/channel/handshaker_registry.cc',
'src/core/lib/channel/status_util.cc',
'src/core/lib/compression/compression.cc',
'src/core/lib/compression/compression_args.cc',
'src/core/lib/compression/compression_internal.cc',
'src/core/lib/compression/message_compress.cc',
'src/core/lib/compression/stream_compression.cc',
@ -890,6 +892,7 @@
'src/core/lib/channel/handshaker_registry.cc',
'src/core/lib/channel/status_util.cc',
'src/core/lib/compression/compression.cc',
'src/core/lib/compression/compression_args.cc',
'src/core/lib/compression/compression_internal.cc',
'src/core/lib/compression/message_compress.cc',
'src/core/lib/compression/stream_compression.cc',
@ -1110,6 +1113,7 @@
'src/core/lib/channel/handshaker_registry.cc',
'src/core/lib/channel/status_util.cc',
'src/core/lib/compression/compression.cc',
'src/core/lib/compression/compression_args.cc',
'src/core/lib/compression/compression_internal.cc',
'src/core/lib/compression/message_compress.cc',
'src/core/lib/compression/stream_compression.cc',

@ -264,7 +264,7 @@ GRPCAPI grpc_call_credentials* grpc_google_refresh_token_credentials_create(
const char* json_refresh_token, void* reserved);
/** Creates an Oauth2 Access Token credentials with an access token that was
aquired by an out of band mechanism. */
acquired by an out of band mechanism. */
GRPCAPI grpc_call_credentials* grpc_access_token_credentials_create(
const char* access_token, void* reserved);

@ -115,6 +115,7 @@
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
#define GPR_HAS_PTHREAD_H 1
#define GPR_GETPID_IN_UNISTD_H 1
#ifdef _LP64
#define GPR_ARCH_64 1
@ -144,6 +145,7 @@
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
#define GPR_HAS_PTHREAD_H 1
#define GPR_GETPID_IN_UNISTD_H 1
#define GPR_SUPPORT_CHANNELS_FROM_FD 1
#elif defined(__linux__)
@ -170,6 +172,7 @@
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
#define GPR_HAS_PTHREAD_H 1
#define GPR_GETPID_IN_UNISTD_H 1
#ifdef _LP64
#define GPR_ARCH_64 1
@ -235,6 +238,7 @@
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
#define GPR_HAS_PTHREAD_H 1
#define GPR_GETPID_IN_UNISTD_H 1
#ifndef GRPC_CFSTREAM
#define GPR_SUPPORT_CHANNELS_FROM_FD 1
@ -260,6 +264,7 @@
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
#define GPR_HAS_PTHREAD_H 1
#define GPR_GETPID_IN_UNISTD_H 1
#define GPR_SUPPORT_CHANNELS_FROM_FD 1
#ifdef _LP64
@ -283,6 +288,7 @@
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
#define GPR_HAS_PTHREAD_H 1
#define GPR_GETPID_IN_UNISTD_H 1
#define GPR_SUPPORT_CHANNELS_FROM_FD 1
#ifdef _LP64
@ -303,6 +309,7 @@
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
#define GPR_HAS_PTHREAD_H 1
#define GPR_GETPID_IN_UNISTD_H 1
#ifdef _LP64
#define GPR_ARCH_64 1
@ -325,6 +332,7 @@
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
#define GPR_HAS_PTHREAD_H 1
#define GPR_GETPID_IN_UNISTD_H 1
#ifdef _LP64
#define GPR_ARCH_64 1
@ -353,6 +361,7 @@
#define GPR_POSIX_SUBPROCESS 1
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_TIME 1
#define GPR_HAS_PTHREAD_H 1
#define GPR_GETPID_IN_UNISTD_H 1
#ifdef _LP64
#define GPR_ARCH_64 1
@ -378,6 +387,7 @@
#define GPR_POSIX_SYNC 1
#define GPR_POSIX_STRING 1
#define GPR_POSIX_TIME 1
#define GPR_HAS_PTHREAD_H 1
#define GPR_GETPID_IN_UNISTD_H 1
#else
#error "Could not auto-detect platform"

@ -40,27 +40,6 @@ typedef struct grpc_slice grpc_slice;
reference ownership semantics (who should call unref?) and mutability
constraints (is the callee allowed to modify the slice?) */
typedef struct grpc_slice_refcount_vtable {
void (*ref)(void*);
void (*unref)(void*);
int (*eq)(grpc_slice a, grpc_slice b);
uint32_t (*hash)(grpc_slice slice);
} grpc_slice_refcount_vtable;
/** Reference count container for grpc_slice. Contains function pointers to
increment and decrement reference counts. Implementations should cleanup
when the reference count drops to zero.
Typically client code should not touch this, and use grpc_slice_malloc,
grpc_slice_new, or grpc_slice_new_with_len instead. */
typedef struct grpc_slice_refcount {
const grpc_slice_refcount_vtable* vtable;
/** If a subset of this slice is taken, use this pointer for the refcount.
Typically points back to the refcount itself, however iterning
implementations can use this to avoid a verification step on each hash
or equality check */
struct grpc_slice_refcount* sub_refcount;
} grpc_slice_refcount;
/* Inlined half of grpc_slice is allowed to expand the size of the overall type
by this many bytes */
#define GRPC_SLICE_INLINE_EXTRA_SIZE sizeof(void*)
@ -68,6 +47,7 @@ typedef struct grpc_slice_refcount {
#define GRPC_SLICE_INLINED_SIZE \
(sizeof(size_t) + sizeof(uint8_t*) - 1 + GRPC_SLICE_INLINE_EXTRA_SIZE)
struct grpc_slice_refcount;
/** A grpc_slice s, if initialized, represents the byte range
s.bytes[0..s.length-1].

@ -147,7 +147,7 @@ GPRAPI int grpc_slice_buf_start_eq(grpc_slice a, const void* b, size_t blen);
GPRAPI int grpc_slice_rchr(grpc_slice s, char c);
GPRAPI int grpc_slice_chr(grpc_slice s, char c);
/** return the index of the first occurance of \a needle in \a haystack, or -1
/** return the index of the first occurrence of \a needle in \a haystack, or -1
if it's not found */
GPRAPI int grpc_slice_slice(grpc_slice haystack, grpc_slice needle);

@ -82,6 +82,12 @@ class GenericStub final {
const grpc::ByteBuffer* request, grpc::ByteBuffer* response,
std::function<void(grpc::Status)> on_completion);
/// Setup and start a unary call to a named method \a method using
/// \a context and specifying the \a request and \a response buffers.
void UnaryCall(grpc::ClientContext* context, const grpc::string& method,
const grpc::ByteBuffer* request, grpc::ByteBuffer* response,
grpc::experimental::ClientUnaryReactor* reactor);
/// Setup a call to a named method \a method using \a context and tied to
/// \a reactor . Like any other bidi streaming RPC, it will not be activated
/// until StartCall is invoked on its reactor.

@ -661,7 +661,7 @@ class ServerAsyncReaderInterface
/// some failure occurred when trying to do so.
///
/// gRPC doesn't take ownership or a reference to \a msg or \a status, so it
/// is safe to to deallocate once Finish returns.
/// is safe to deallocate once Finish returns.
///
/// \param[in] tag Tag identifying this request.
/// \param[in] status To be sent to the client as the result of this call.
@ -735,7 +735,7 @@ class ServerAsyncReader final : public ServerAsyncReaderInterface<W, R> {
/// Note: \a msg is not sent if \a status has a non-OK code.
///
/// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
/// is safe to to deallocate once Finish returns.
/// is safe to deallocate once Finish returns.
void Finish(const W& msg, const Status& status, void* tag) override {
finish_ops_.set_output_tag(tag);
if (!ctx_->sent_initial_metadata_) {
@ -830,7 +830,7 @@ class ServerAsyncWriterInterface
/// in a single step.
///
/// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
/// is safe to to deallocate once WriteAndFinish returns.
/// is safe to deallocate once WriteAndFinish returns.
///
/// \param[in] msg The message to be written.
/// \param[in] options The WriteOptions to be used to write this message.
@ -897,7 +897,7 @@ class ServerAsyncWriter final : public ServerAsyncWriterInterface<W> {
/// Note: \a status must have an OK code.
///
/// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
/// is safe to to deallocate once WriteAndFinish returns.
/// is safe to deallocate once WriteAndFinish returns.
void WriteAndFinish(const W& msg, WriteOptions options, const Status& status,
void* tag) override {
write_ops_.set_output_tag(tag);
@ -993,7 +993,7 @@ class ServerAsyncReaderWriterInterface
/// single step.
///
/// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
/// is safe to to deallocate once WriteAndFinish returns.
/// is safe to deallocate once WriteAndFinish returns.
///
/// \param[in] msg The message to be written.
/// \param[in] options The WriteOptions to be used to write this message.
@ -1068,7 +1068,7 @@ class ServerAsyncReaderWriter final
/// Note: \a status must have an OK code.
//
/// gRPC doesn't take ownership or a reference to \a msg and \a status, so it
/// is safe to to deallocate once WriteAndFinish returns.
/// is safe to deallocate once WriteAndFinish returns.
void WriteAndFinish(const W& msg, WriteOptions options, const Status& status,
void* tag) override {
write_ops_.set_output_tag(tag);

@ -58,6 +58,7 @@ template <class R>
class ClientCallbackReaderFactory;
template <class W>
class ClientCallbackWriterFactory;
class ClientCallbackUnaryFactory;
class InterceptedChannel;
} // namespace internal
@ -117,6 +118,7 @@ class ChannelInterface {
friend class ::grpc::internal::ClientCallbackReaderFactory;
template <class W>
friend class ::grpc::internal::ClientCallbackWriterFactory;
friend class ::grpc::internal::ClientCallbackUnaryFactory;
template <class InputMessage, class OutputMessage>
friend class ::grpc::internal::BlockingUnaryCallImpl;
template <class InputMessage, class OutputMessage>

@ -100,6 +100,7 @@ template <class Response>
class ClientReadReactor;
template <class Request>
class ClientWriteReactor;
class ClientUnaryReactor;
// NOTE: The streaming objects are not actually implemented in the public API.
// These interfaces are provided for mocking only. Typical applications
@ -157,6 +158,15 @@ class ClientCallbackWriter {
}
};
class ClientCallbackUnary {
public:
virtual ~ClientCallbackUnary() {}
virtual void StartCall() = 0;
protected:
void BindReactor(ClientUnaryReactor* reactor);
};
// The following classes are the reactor interfaces that are to be implemented
// by the user. They are passed in to the library as an argument to a call on a
// stub (either a codegen-ed call or a generic call). The streaming RPC is
@ -346,6 +356,36 @@ class ClientWriteReactor {
ClientCallbackWriter<Request>* writer_;
};
/// \a ClientUnaryReactor is a reactor-style interface for a unary RPC.
/// This is _not_ a common way of invoking a unary RPC. In practice, this
/// option should be used only if the unary RPC wants to receive initial
/// metadata without waiting for the response to complete. Most deployments of
/// RPC systems do not use this option, but it is needed for generality.
/// All public methods behave as in ClientBidiReactor.
/// StartCall is included for consistency with the other reactor flavors: even
/// though there are no StartRead or StartWrite operations to queue before the
/// call (that is part of the unary call itself) and there is no reactor object
/// being created as a result of this call, we keep a consistent 2-phase
/// initiation API among all the reactor flavors.
class ClientUnaryReactor {
public:
virtual ~ClientUnaryReactor() {}
void StartCall() { call_->StartCall(); }
virtual void OnDone(const Status& s) {}
virtual void OnReadInitialMetadataDone(bool ok) {}
private:
friend class ClientCallbackUnary;
void BindCall(ClientCallbackUnary* call) { call_ = call; }
ClientCallbackUnary* call_;
};
// Define function out-of-line from class to avoid forward declaration issue
inline void ClientCallbackUnary::BindReactor(ClientUnaryReactor* reactor) {
reactor->BindCall(this);
}
} // namespace experimental
namespace internal {
@ -512,9 +552,9 @@ class ClientCallbackReaderWriterImpl
this->BindReactor(reactor);
}
ClientContext* context_;
ClientContext* const context_;
Call call_;
::grpc::experimental::ClientBidiReactor<Request, Response>* reactor_;
::grpc::experimental::ClientBidiReactor<Request, Response>* const reactor_;
CallOpSet<CallOpSendInitialMetadata, CallOpRecvInitialMetadata> start_ops_;
CallbackWithSuccessTag start_tag_;
@ -651,9 +691,9 @@ class ClientCallbackReaderImpl
start_ops_.ClientSendClose();
}
ClientContext* context_;
ClientContext* const context_;
Call call_;
::grpc::experimental::ClientReadReactor<Response>* reactor_;
::grpc::experimental::ClientReadReactor<Response>* const reactor_;
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpClientSendClose,
CallOpRecvInitialMetadata>
@ -824,9 +864,9 @@ class ClientCallbackWriterImpl
finish_ops_.AllowNoMessage();
}
ClientContext* context_;
ClientContext* const context_;
Call call_;
::grpc::experimental::ClientWriteReactor<Request>* reactor_;
::grpc::experimental::ClientWriteReactor<Request>* const reactor_;
CallOpSet<CallOpSendInitialMetadata, CallOpRecvInitialMetadata> start_ops_;
CallbackWithSuccessTag start_tag_;
@ -867,6 +907,109 @@ class ClientCallbackWriterFactory {
}
};
class ClientCallbackUnaryImpl final
: public ::grpc::experimental::ClientCallbackUnary {
public:
// always allocated against a call arena, no memory free required
static void operator delete(void* ptr, std::size_t size) {
assert(size == sizeof(ClientCallbackUnaryImpl));
}
// This operator should never be called as the memory should be freed as part
// of the arena destruction. It only exists to provide a matching operator
// delete to the operator new so that some compilers will not complain (see
// https://github.com/grpc/grpc/issues/11301) Note at the time of adding this
// there are no tests catching the compiler warning.
static void operator delete(void*, void*) { assert(0); }
void StartCall() override {
// This call initiates two batches, each with a callback
// 1. Send initial metadata + write + writes done + recv initial metadata
// 2. Read message, recv trailing metadata
started_ = true;
start_tag_.Set(call_.call(),
[this](bool ok) {
reactor_->OnReadInitialMetadataDone(ok);
MaybeFinish();
},
&start_ops_);
start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
context_->initial_metadata_flags());
start_ops_.RecvInitialMetadata(context_);
start_ops_.set_core_cq_tag(&start_tag_);
call_.PerformOps(&start_ops_);
finish_tag_.Set(call_.call(), [this](bool ok) { MaybeFinish(); },
&finish_ops_);
finish_ops_.ClientRecvStatus(context_, &finish_status_);
finish_ops_.set_core_cq_tag(&finish_tag_);
call_.PerformOps(&finish_ops_);
}
void MaybeFinish() {
if (--callbacks_outstanding_ == 0) {
Status s = std::move(finish_status_);
auto* reactor = reactor_;
auto* call = call_.call();
this->~ClientCallbackUnaryImpl();
g_core_codegen_interface->grpc_call_unref(call);
reactor->OnDone(s);
}
}
private:
friend class ClientCallbackUnaryFactory;
template <class Request, class Response>
ClientCallbackUnaryImpl(Call call, ClientContext* context, Request* request,
Response* response,
::grpc::experimental::ClientUnaryReactor* reactor)
: context_(context), call_(call), reactor_(reactor) {
this->BindReactor(reactor);
// TODO(vjpai): don't assert
GPR_CODEGEN_ASSERT(start_ops_.SendMessagePtr(request).ok());
start_ops_.ClientSendClose();
finish_ops_.RecvMessage(response);
finish_ops_.AllowNoMessage();
}
ClientContext* const context_;
Call call_;
::grpc::experimental::ClientUnaryReactor* const reactor_;
CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpClientSendClose,
CallOpRecvInitialMetadata>
start_ops_;
CallbackWithSuccessTag start_tag_;
CallOpSet<CallOpGenericRecvMessage, CallOpClientRecvStatus> finish_ops_;
CallbackWithSuccessTag finish_tag_;
Status finish_status_;
// This call will have 2 callbacks: start and finish
std::atomic_int callbacks_outstanding_{2};
bool started_{false};
};
class ClientCallbackUnaryFactory {
public:
template <class Request, class Response>
static void Create(ChannelInterface* channel,
const ::grpc::internal::RpcMethod& method,
ClientContext* context, const Request* request,
Response* response,
::grpc::experimental::ClientUnaryReactor* reactor) {
Call call = channel->CreateCall(method, context, channel->CallbackCQ());
g_core_codegen_interface->grpc_call_ref(call.call());
new (g_core_codegen_interface->grpc_call_arena_alloc(
call.call(), sizeof(ClientCallbackUnaryImpl)))
ClientCallbackUnaryImpl(call, context, request, response, reactor);
}
};
} // namespace internal
} // namespace grpc

@ -79,6 +79,7 @@ template <class Response>
class ClientCallbackReaderImpl;
template <class Request>
class ClientCallbackWriterImpl;
class ClientCallbackUnaryImpl;
} // namespace internal
template <class R>
@ -417,6 +418,7 @@ class ClientContext {
friend class ::grpc::internal::ClientCallbackReaderImpl;
template <class Request>
friend class ::grpc::internal::ClientCallbackWriterImpl;
friend class ::grpc::internal::ClientCallbackUnaryImpl;
// Used by friend class CallOpClientRecvStatus
void set_debug_error_string(const grpc::string& debug_error_string) {

@ -183,8 +183,8 @@ class CompletionQueue : private GrpcLibraryCodegen {
/// within the \a deadline). A \a tag points to an arbitrary location usually
/// employed to uniquely identify an event.
///
/// \param tag [out] Upon sucess, updated to point to the event's tag.
/// \param ok [out] Upon sucess, true if a successful event, false otherwise
/// \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.
///
@ -203,8 +203,8 @@ class CompletionQueue : private GrpcLibraryCodegen {
/// employed to uniquely identify an event.
///
/// \param f [in] Function to execute before calling AsyncNext on this queue.
/// \param tag [out] Upon sucess, updated to point to the event's tag.
/// \param ok [out] Upon sucess, true if read a regular event, false
/// \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.
///
@ -362,7 +362,7 @@ class CompletionQueue : private GrpcLibraryCodegen {
/// 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)
/// elsewhere)
void InitialAvalanching() {
gpr_atm_rel_store(&avalanches_in_flight_, static_cast<gpr_atm>(1));
}

@ -0,0 +1,55 @@
/*
*
* 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 GRPCPP_IMPL_CODEGEN_MESSAGE_ALLOCATOR_H
#define GRPCPP_IMPL_CODEGEN_MESSAGE_ALLOCATOR_H
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.
template <typename RequestT, typename ResponseT>
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;
};
// Implementations need to be thread-safe
template <typename RequestT, typename ResponseT>
class MessageAllocator {
public:
virtual ~MessageAllocator() = default;
// Allocate both request and response
virtual void AllocateMessages(
RpcAllocatorInfo<RequestT, ResponseT>* info) = 0;
// Optional: deallocate request early, called by
// ServerCallbackRpcController::ReleaseRequest
virtual void DeallocateRequest(RpcAllocatorInfo<RequestT, ResponseT>* info) {}
// Deallocate response and request (if applicable)
virtual void DeallocateMessages(
RpcAllocatorInfo<RequestT, ResponseT>* info) = 0;
};
} // namespace experimental
} // namespace grpc
#endif // GRPCPP_IMPL_CODEGEN_MESSAGE_ALLOCATOR_H

@ -86,8 +86,8 @@ class RpcMethodHandler : public MethodHandler {
param.call->cq()->Pluck(&ops);
}
void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
Status* status) final {
void* Deserialize(grpc_call* call, grpc_byte_buffer* req, Status* status,
void** handler_data) final {
ByteBuffer buf;
buf.set_buffer(req);
auto* request = new (g_core_codegen_interface->grpc_call_arena_alloc(
@ -191,8 +191,8 @@ class ServerStreamingHandler : public MethodHandler {
param.call->cq()->Pluck(&ops);
}
void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
Status* status) final {
void* Deserialize(grpc_call* call, grpc_byte_buffer* req, Status* status,
void** handler_data) final {
ByteBuffer buf;
buf.set_buffer(req);
auto* request = new (g_core_codegen_interface->grpc_call_arena_alloc(
@ -327,8 +327,8 @@ class ErrorMethodHandler : public MethodHandler {
param.call->cq()->Pluck(&ops);
}
void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
Status* status) final {
void* Deserialize(grpc_call* call, grpc_byte_buffer* req, Status* status,
void** handler_data) final {
// We have to destroy any request payload
if (req != nullptr) {
g_core_codegen_interface->grpc_byte_buffer_destroy(req);

@ -46,21 +46,25 @@ class MethodHandler {
/// \param context : the ServerContext structure for this server call
/// \param req : the request payload, if appropriate for this RPC
/// \param req_status : the request status after any interceptors have run
/// \param handler_data: internal data for the handler.
/// \param requester : used only by the callback API. It is a function
/// called by the RPC Controller to request another RPC (and also
/// to set up the state required to make that request possible)
HandlerParameter(Call* c, ServerContext* context, void* req,
Status req_status, std::function<void()> requester)
Status req_status, void* handler_data,
std::function<void()> requester)
: call(c),
server_context(context),
request(req),
status(req_status),
internal_data(handler_data),
call_requester(std::move(requester)) {}
~HandlerParameter() {}
Call* call;
ServerContext* server_context;
void* request;
Status status;
void* internal_data;
std::function<void()> call_requester;
};
virtual void RunHandler(const HandlerParameter& param) = 0;
@ -71,7 +75,7 @@ class MethodHandler {
pointer after calling RunHandler. Ownership of the deserialized request is
retained by the handler. Returns nullptr if deserialization failed. */
virtual void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
Status* status) {
Status* status, void** handler_data) {
GPR_CODEGEN_ASSERT(req == nullptr);
return nullptr;
}

@ -28,6 +28,7 @@
#include <grpcpp/impl/codegen/callback_common.h>
#include <grpcpp/impl/codegen/config.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
#include <grpcpp/impl/codegen/message_allocator.h>
#include <grpcpp/impl/codegen/server_context.h>
#include <grpcpp/impl/codegen/server_interface.h>
#include <grpcpp/impl/codegen/status.h>
@ -37,11 +38,43 @@ namespace grpc {
// Declare base class of all reactors as internal
namespace internal {
// Forward declarations
template <class Request, class Response>
class CallbackClientStreamingHandler;
template <class Request, class Response>
class CallbackServerStreamingHandler;
template <class Request, class Response>
class CallbackBidiHandler;
class ServerReactor {
public:
virtual ~ServerReactor() = default;
virtual void OnDone() = 0;
virtual void OnCancel() = 0;
private:
friend class ::grpc::ServerContext;
template <class Request, class Response>
friend class CallbackClientStreamingHandler;
template <class Request, class Response>
friend class CallbackServerStreamingHandler;
template <class Request, class Response>
friend class CallbackBidiHandler;
// The ServerReactor is responsible for tracking when it is safe to call
// OnCancel. This function should not be called until after OnStarted is done
// and the RPC has completed with a cancellation. This is tracked by counting
// how many of these conditions have been met and calling OnCancel when none
// remain unmet.
void MaybeCallOnCancel() {
if (on_cancel_conditions_remaining_.fetch_sub(
1, std::memory_order_acq_rel) == 1) {
OnCancel();
}
}
std::atomic_int on_cancel_conditions_remaining_{2};
};
} // namespace internal
@ -103,6 +136,14 @@ class ServerCallbackRpcController {
/// to be called before the callback completes.
virtual void SetCancelCallback(std::function<void()> 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;
};
// NOTE: The actual streaming object classes are provided
@ -332,7 +373,7 @@ class ServerReadReactor : public internal::ServerReactor {
ServerCallbackReader<Request>* reader_;
};
/// \a ServerReadReactor is the interface for a server-streaming RPC.
/// \a ServerWriteReactor is the interface for a server-streaming RPC.
template <class Request, class Response>
class ServerWriteReactor : public internal::ServerReactor {
public:
@ -415,17 +456,24 @@ class CallbackUnaryHandler : public MethodHandler {
experimental::ServerCallbackRpcController*)>
func)
: func_(func) {}
void SetMessageAllocator(
experimental::MessageAllocator<RequestType, ResponseType>* allocator) {
allocator_ = allocator;
}
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<experimental::RpcAllocatorInfo<RequestType, ResponseType>*>(
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,
static_cast<RequestType*>(param.request),
std::move(param.call_requester));
ServerCallbackRpcControllerImpl(param.server_context, param.call,
allocator_info, allocator_,
std::move(param.call_requester));
Status status = param.status;
if (status.ok()) {
// Call the actual function handler and expect the user to call finish
CatchingCallback(func_, param.server_context, controller->request(),
@ -436,18 +484,41 @@ class CallbackUnaryHandler : public MethodHandler {
}
}
void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
Status* status) final {
void* Deserialize(grpc_call* call, grpc_byte_buffer* req, Status* status,
void** handler_data) final {
ByteBuffer buf;
buf.set_buffer(req);
auto* request = new (g_core_codegen_interface->grpc_call_arena_alloc(
call, sizeof(RequestType))) RequestType();
RequestType* request = nullptr;
experimental::RpcAllocatorInfo<RequestType, ResponseType>* allocator_info =
new (g_core_codegen_interface->grpc_call_arena_alloc(
call, sizeof(*allocator_info)))
experimental::RpcAllocatorInfo<RequestType, ResponseType>();
if (allocator_ != nullptr) {
allocator_->AllocateMessages(allocator_info);
} 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();
}
*handler_data = allocator_info;
request = allocator_info->request;
*status = SerializationTraits<RequestType>::Deserialize(&buf, request);
buf.Release();
if (status->ok()) {
return request;
}
request->~RequestType();
// 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;
}
return nullptr;
}
@ -455,6 +526,8 @@ class CallbackUnaryHandler : public MethodHandler {
std::function<void(ServerContext*, const RequestType*, ResponseType*,
experimental::ServerCallbackRpcController*)>
func_;
experimental::MessageAllocator<RequestType, ResponseType>* allocator_ =
nullptr;
// The implementation class of ServerCallbackRpcController is a private member
// of CallbackUnaryHandler since it is never exposed anywhere, and this allows
@ -475,8 +548,9 @@ 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(&resp_));
finish_ops_.ServerSendStatus(
&ctx_->trailing_metadata_,
finish_ops_.SendMessagePtr(allocator_info_->response));
} else {
finish_ops_.ServerSendStatus(&ctx_->trailing_metadata_, s);
}
@ -514,28 +588,50 @@ 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;
}
private:
friend class CallbackUnaryHandler<RequestType, ResponseType>;
ServerCallbackRpcControllerImpl(ServerContext* ctx, Call* call,
const RequestType* req,
std::function<void()> call_requester)
ServerCallbackRpcControllerImpl(
ServerContext* ctx, Call* call,
experimental::RpcAllocatorInfo<RequestType, ResponseType>*
allocator_info,
experimental::MessageAllocator<RequestType, ResponseType>* allocator,
std::function<void()> call_requester)
: ctx_(ctx),
call_(*call),
req_(req),
allocator_info_(allocator_info),
allocator_(allocator),
call_requester_(std::move(call_requester)) {
ctx_->BeginCompletionOp(call, [this](bool) { MaybeDone(); }, nullptr);
}
~ServerCallbackRpcControllerImpl() { req_->~RequestType(); }
const RequestType* request() { return req_; }
ResponseType* response() { return &resp_; }
const RequestType* request() { return allocator_info_->request; }
ResponseType* response() { return allocator_info_->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();
}
}
this->~ServerCallbackRpcControllerImpl(); // explicitly call destructor
g_core_codegen_interface->grpc_call_unref(call);
call_requester();
@ -551,8 +647,8 @@ class CallbackUnaryHandler : public MethodHandler {
ServerContext* ctx_;
Call call_;
const RequestType* req_;
ResponseType resp_;
experimental::RpcAllocatorInfo<RequestType, ResponseType>* allocator_info_;
experimental::MessageAllocator<RequestType, ResponseType>* allocator_;
std::function<void()> call_requester_;
std::atomic_int callbacks_outstanding_{
2}; // reserve for Finish and CompletionOp
@ -590,6 +686,8 @@ class CallbackClientStreamingHandler : public MethodHandler {
reader->BindReactor(reactor);
reactor->OnStarted(param.server_context, reader->response());
// The earliest that OnCancel can be called is after OnStarted is done.
reactor->MaybeCallOnCancel();
reader->MaybeDone();
}
@ -732,11 +830,13 @@ class CallbackServerStreamingHandler : public MethodHandler {
std::move(param.call_requester), reactor);
writer->BindReactor(reactor);
reactor->OnStarted(param.server_context, writer->request());
// The earliest that OnCancel can be called is after OnStarted is done.
reactor->MaybeCallOnCancel();
writer->MaybeDone();
}
void* Deserialize(grpc_call* call, grpc_byte_buffer* req,
Status* status) final {
void* Deserialize(grpc_call* call, grpc_byte_buffer* req, Status* status,
void** handler_data) final {
ByteBuffer buf;
buf.set_buffer(req);
auto* request = new (g_core_codegen_interface->grpc_call_arena_alloc(
@ -908,6 +1008,8 @@ class CallbackBidiHandler : public MethodHandler {
stream->BindReactor(reactor);
reactor->OnStarted(param.server_context);
// The earliest that OnCancel can be called is after OnStarted is done.
reactor->MaybeCallOnCancel();
stream->MaybeDone();
}

@ -149,7 +149,7 @@ class ServerInterface : public internal::CallHook {
/// 192.168.1.1:31416, [::1]:27182, etc.).
/// \params creds The credentials associated with the server.
///
/// \return bound port number on sucess, 0 on failure.
/// \return bound port number on success, 0 on failure.
///
/// \warning It's an error to call this method on an already started server.
virtual int AddListeningPort(const grpc::string& addr,

@ -135,6 +135,11 @@ class Service {
internal::RpcServiceMethod::ApiType::RAW_CALL_BACK);
}
internal::MethodHandler* GetHandler(int index) {
size_t idx = static_cast<size_t>(index);
return service_->methods_[idx]->handler();
}
private:
Service* service_;
};

@ -19,8 +19,15 @@
#ifndef GRPCPP_IMPL_CODEGEN_SYNC_H
#define GRPCPP_IMPL_CODEGEN_SYNC_H
#include <grpc/impl/codegen/log.h>
#include <grpc/impl/codegen/port_platform.h>
#ifdef GPR_HAS_PTHREAD_H
#include <pthread.h>
#endif
#include <mutex>
#include <grpc/impl/codegen/log.h>
#include <grpc/impl/codegen/sync.h>
#include <grpcpp/impl/codegen/core_codegen_interface.h>
@ -49,7 +56,13 @@ class Mutex {
const gpr_mu* get() const { return &mu_; }
private:
gpr_mu mu_;
union {
gpr_mu mu_;
std::mutex do_not_use_sth_;
#ifdef GPR_HAS_PTHREAD_H
pthread_mutex_t do_not_use_pth_;
#endif
};
};
// MutexLock is a std::

@ -180,7 +180,7 @@ class ClientReader final : public ClientReaderInterface<R> {
///
// Side effect:
/// Once complete, the initial metadata read from
/// the server will be accessable through the \a ClientContext used to
/// the server will be accessible through the \a ClientContext used to
/// construct this object.
void WaitForInitialMetadata() override {
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
@ -298,7 +298,7 @@ class ClientWriter : public ClientWriterInterface<W> {
///
// Side effect:
/// Once complete, the initial metadata read from the server will be
/// accessable through the \a ClientContext used to construct this object.
/// accessible through the \a ClientContext used to construct this object.
void WaitForInitialMetadata() {
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
@ -449,7 +449,7 @@ class ClientReaderWriter final : public ClientReaderWriterInterface<W, R> {
/// with or after the \a Finish method.
///
/// Once complete, the initial metadata read from the server will be
/// accessable through the \a ClientContext used to construct this object.
/// accessible through the \a ClientContext used to construct this object.
void WaitForInitialMetadata() override {
GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);

@ -98,10 +98,10 @@ class ChannelCredentials : private GrpcLibraryCodegen {
// 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<Channel> CreateChannelWithInterceptors(
const grpc::string& target, const ChannelArguments& args,
const grpc::string& /* target */, const ChannelArguments& /* args */,
std::vector<
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>
interceptor_creators) {
/* interceptor_creators */) {
return nullptr;
}
};

@ -0,0 +1,24 @@
/*
*
* 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 GRPCPP_SUPPORT_MESSAGE_ALLOCATOR_H
#define GRPCPP_SUPPORT_MESSAGE_ALLOCATOR_H
#include <grpcpp/impl/codegen/message_allocator.h>
#endif // GRPCPP_SUPPORT_MESSAGE_ALLOCATOR_H

@ -332,6 +332,7 @@
<file baseinstalldir="/" name="src/core/lib/channel/handshaker_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/status_util.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/algorithm_metadata.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/compression_args.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/compression_internal.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/message_compress.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/stream_compression.h" role="src" />
@ -486,6 +487,7 @@
<file baseinstalldir="/" name="src/core/lib/channel/handshaker_registry.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/status_util.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/compression.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/compression_args.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/compression_internal.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/message_compress.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/compression/stream_compression.cc" role="src" />

@ -84,7 +84,7 @@ void PrintIncludes(grpc_generator::Printer* printer,
}
grpc::string GetHeaderPrologue(grpc_generator::File* file,
const Parameters& /*params*/) {
const Parameters& params) {
grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
@ -94,7 +94,9 @@ grpc::string GetHeaderPrologue(grpc_generator::File* file,
vars["filename"] = file->filename();
vars["filename_identifier"] = FilenameIdentifier(file->filename());
vars["filename_base"] = file->filename_without_ext();
vars["message_header_ext"] = kCppGeneratorMessageHeaderExt;
vars["message_header_ext"] = params.message_header_extension.empty()
? kCppGeneratorMessageHeaderExt
: params.message_header_extension;
printer->Print(vars, "// Generated by the gRPC C++ plugin.\n");
printer->Print(vars,
@ -115,6 +117,13 @@ grpc::string GetHeaderPrologue(grpc_generator::File* file,
return output;
}
// Convert from "a/b/c.proto" to "#include \"a/b/c$message_header_ext$\"\n"
grpc::string ImportInludeFromProtoName(const grpc::string& proto_name) {
return grpc::string("#include \"") +
proto_name.substr(0, proto_name.size() - 6) +
grpc::string("$message_header_ext$\"\n");
}
grpc::string GetHeaderIncludes(grpc_generator::File* file,
const Parameters& params) {
grpc::string output;
@ -146,12 +155,30 @@ grpc::string GetHeaderIncludes(grpc_generator::File* file,
params.grpc_search_path);
printer->Print(vars, "\n");
printer->Print(vars, "namespace grpc {\n");
printer->Print(vars, "namespace experimental {\n");
printer->Print(vars, "template <typename RequestT, typename ResponseT>\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");
vars["message_header_ext"] = params.message_header_extension.empty()
? kCppGeneratorMessageHeaderExt
: params.message_header_extension;
if (params.include_import_headers) {
const std::vector<grpc::string> import_names = file->GetImportNames();
for (const auto& import_name : import_names) {
const grpc::string include_name =
ImportInludeFromProtoName(import_name);
printer->Print(vars, include_name.c_str());
}
printer->PrintRaw("\n");
}
if (!file->package().empty()) {
std::vector<grpc::string> parts = file->package_parts();
@ -584,6 +611,14 @@ void PrintHeaderClientMethodCallbackInterfaces(
"virtual void $Method$(::grpc::ClientContext* context, "
"const ::grpc::ByteBuffer* request, $Response$* response, "
"std::function<void(::grpc::Status)>) = 0;\n");
printer->Print(*vars,
"virtual void $Method$(::grpc::ClientContext* context, "
"const $Request$* request, $Response$* response, "
"::grpc::experimental::ClientUnaryReactor* reactor) = 0;\n");
printer->Print(*vars,
"virtual void $Method$(::grpc::ClientContext* context, "
"const ::grpc::ByteBuffer* request, $Response$* response, "
"::grpc::experimental::ClientUnaryReactor* reactor) = 0;\n");
} else if (ClientOnlyStreaming(method)) {
printer->Print(*vars,
"virtual void $Method$(::grpc::ClientContext* context, "
@ -650,6 +685,16 @@ void PrintHeaderClientMethodCallback(grpc_generator::Printer* printer,
"void $Method$(::grpc::ClientContext* context, "
"const ::grpc::ByteBuffer* request, $Response$* response, "
"std::function<void(::grpc::Status)>) override;\n");
printer->Print(
*vars,
"void $Method$(::grpc::ClientContext* context, "
"const $Request$* request, $Response$* response, "
"::grpc::experimental::ClientUnaryReactor* reactor) override;\n");
printer->Print(
*vars,
"void $Method$(::grpc::ClientContext* context, "
"const ::grpc::ByteBuffer* request, $Response$* response, "
"::grpc::experimental::ClientUnaryReactor* reactor) override;\n");
} else if (ClientOnlyStreaming(method)) {
printer->Print(*vars,
"void $Method$(::grpc::ClientContext* context, "
@ -970,7 +1015,15 @@ void PrintHeaderServerMethodCallback(
"controller) {\n"
" return this->$"
"Method$(context, request, response, controller);\n"
" }));\n");
" }));\n}\n");
printer->Print(*vars,
"void SetMessageAllocatorFor_$Method$(\n"
" ::grpc::experimental::MessageAllocator< "
"$RealRequest$, $RealResponse$>* allocator) {\n"
" static_cast<::grpc::internal::CallbackUnaryHandler< "
"$RealRequest$, $RealResponse$>*>(\n"
" ::grpc::Service::experimental().GetHandler($Idx$))\n"
" ->SetMessageAllocator(allocator);\n");
} else if (ClientOnlyStreaming(method)) {
printer->Print(
*vars,
@ -1556,7 +1609,7 @@ grpc::string GetHeaderEpilogue(grpc_generator::File* file,
}
grpc::string GetSourcePrologue(grpc_generator::File* file,
const Parameters& /*params*/) {
const Parameters& params) {
grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
@ -1565,7 +1618,9 @@ grpc::string GetSourcePrologue(grpc_generator::File* file,
vars["filename"] = file->filename();
vars["filename_base"] = file->filename_without_ext();
vars["message_header_ext"] = kCppGeneratorMessageHeaderExt;
vars["message_header_ext"] = params.message_header_extension.empty()
? kCppGeneratorMessageHeaderExt
: params.message_header_extension;
vars["service_header_ext"] = kCppGeneratorServiceHeaderExt;
printer->Print(vars, "// Generated by the gRPC C++ plugin.\n");
@ -1587,7 +1642,6 @@ grpc::string GetSourceIncludes(grpc_generator::File* file,
// Scope the output stream so it closes and finalizes output to the string.
auto printer = file->CreatePrinter(&output);
std::map<grpc::string, grpc::string> vars;
static const char* headers_strs[] = {
"functional",
"grpcpp/impl/codegen/async_stream.h",
@ -1647,7 +1701,7 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"const $Request$* request, $Response$* response, "
"std::function<void(::grpc::Status)> f) {\n");
printer->Print(*vars,
" return ::grpc::internal::CallbackUnaryCall"
" ::grpc::internal::CallbackUnaryCall"
"(stub_->channel_.get(), stub_->rpcmethod_$Method$_, "
"context, request, response, std::move(f));\n}\n\n");
@ -1657,10 +1711,30 @@ void PrintSourceClientMethod(grpc_generator::Printer* printer,
"const ::grpc::ByteBuffer* request, $Response$* response, "
"std::function<void(::grpc::Status)> f) {\n");
printer->Print(*vars,
" return ::grpc::internal::CallbackUnaryCall"
" ::grpc::internal::CallbackUnaryCall"
"(stub_->channel_.get(), stub_->rpcmethod_$Method$_, "
"context, request, response, std::move(f));\n}\n\n");
printer->Print(*vars,
"void $ns$$Service$::Stub::experimental_async::$Method$("
"::grpc::ClientContext* context, "
"const $Request$* request, $Response$* response, "
"::grpc::experimental::ClientUnaryReactor* reactor) {\n");
printer->Print(*vars,
" ::grpc::internal::ClientCallbackUnaryFactory::Create"
"(stub_->channel_.get(), stub_->rpcmethod_$Method$_, "
"context, request, response, reactor);\n}\n\n");
printer->Print(*vars,
"void $ns$$Service$::Stub::experimental_async::$Method$("
"::grpc::ClientContext* context, "
"const ::grpc::ByteBuffer* request, $Response$* response, "
"::grpc::experimental::ClientUnaryReactor* reactor) {\n");
printer->Print(*vars,
" ::grpc::internal::ClientCallbackUnaryFactory::Create"
"(stub_->channel_.get(), stub_->rpcmethod_$Method$_, "
"context, request, response, reactor);\n}\n\n");
for (auto async_prefix : async_prefixes) {
(*vars)["AsyncPrefix"] = async_prefix.prefix;
(*vars)["AsyncStart"] = async_prefix.start;
@ -2046,7 +2120,7 @@ grpc::string GetSourceEpilogue(grpc_generator::File* file,
// TODO(mmukhi): Make sure we need parameters or not.
grpc::string GetMockPrologue(grpc_generator::File* file,
const Parameters& /*params*/) {
const Parameters& params) {
grpc::string output;
{
// Scope the output stream so it closes and finalizes output to the string.
@ -2055,7 +2129,9 @@ grpc::string GetMockPrologue(grpc_generator::File* file,
vars["filename"] = file->filename();
vars["filename_base"] = file->filename_without_ext();
vars["message_header_ext"] = kCppGeneratorMessageHeaderExt;
vars["message_header_ext"] = params.message_header_extension.empty()
? kCppGeneratorMessageHeaderExt
: params.message_header_extension;
vars["service_header_ext"] = kCppGeneratorServiceHeaderExt;
printer->Print(vars, "// Generated by the gRPC C++ plugin.\n");
@ -2065,6 +2141,15 @@ grpc::string GetMockPrologue(grpc_generator::File* file,
printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
printer->Print(vars, "#include \"$filename_base$$service_header_ext$\"\n");
if (params.include_import_headers) {
const std::vector<grpc::string> import_names = file->GetImportNames();
for (const auto& import_name : import_names) {
const grpc::string include_name =
ImportInludeFromProtoName(import_name);
printer->Print(vars, include_name.c_str());
}
printer->PrintRaw("\n");
}
printer->Print(vars, file->additional_headers().c_str());
printer->Print(vars, "\n");
}

@ -56,6 +56,10 @@ struct Parameters {
grpc::string gmock_search_path;
// *EXPERIMENTAL* Additional include files in grpc.pb.h
std::vector<grpc::string> additional_header_includes;
// By default, use "pb.h"
grpc::string message_header_extension;
// Whether to include headers corresponding to imports in source file.
bool include_import_headers;
};
// Return the prologue of the generated header file.

@ -48,6 +48,7 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
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);
@ -83,6 +84,15 @@ class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
} 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;

@ -50,7 +50,8 @@ void PrintProtoRpcDeclarationAsPragma(
}
template <typename DescriptorType>
static void PrintAllComments(const DescriptorType* desc, Printer* printer) {
static void PrintAllComments(const DescriptorType* desc, Printer* printer,
bool deprecated = false) {
std::vector<grpc::string> comments;
grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING_DETACHED,
&comments);
@ -70,17 +71,20 @@ static void PrintAllComments(const DescriptorType* desc, Printer* printer) {
}
printer->Print("\n");
}
printer->Print(" *\n");
printer->Print(
" * This method belongs to a set of APIs that have been deprecated. Using"
" the v2 API is recommended.\n");
if (deprecated) {
printer->Print(" *\n");
printer->Print(
" * This method belongs to a set of APIs that have been deprecated. "
"Using"
" the v2 API is recommended.\n");
}
printer->Print(" */\n");
}
void PrintMethodSignature(Printer* printer, const MethodDescriptor* method,
const map< ::grpc::string, ::grpc::string>& vars) {
// Print comment
PrintAllComments(method, printer);
PrintAllComments(method, printer, true);
printer->Print(vars, "- ($return_type$)$method_name$With");
if (method->client_streaming()) {

@ -55,22 +55,23 @@ class ProtoBufMethod : public grpc_generator::Method {
return method_->output_type()->file()->name();
}
bool get_module_and_message_path_input(grpc::string* str,
grpc::string generator_file_name,
bool generate_in_pb2_grpc,
grpc::string import_prefix) const {
// TODO(https://github.com/grpc/grpc/issues/18800): Clean this up.
bool get_module_and_message_path_input(
grpc::string* str, grpc::string generator_file_name,
bool generate_in_pb2_grpc, grpc::string import_prefix,
const std::vector<grpc::string>& prefixes_to_filter) const final {
return grpc_python_generator::GetModuleAndMessagePath(
method_->input_type(), str, generator_file_name, generate_in_pb2_grpc,
import_prefix);
import_prefix, prefixes_to_filter);
}
bool get_module_and_message_path_output(grpc::string* str,
grpc::string generator_file_name,
bool generate_in_pb2_grpc,
grpc::string import_prefix) const {
bool get_module_and_message_path_output(
grpc::string* str, grpc::string generator_file_name,
bool generate_in_pb2_grpc, grpc::string import_prefix,
const std::vector<grpc::string>& prefixes_to_filter) const final {
return grpc_python_generator::GetModuleAndMessagePath(
method_->output_type(), str, generator_file_name, generate_in_pb2_grpc,
import_prefix);
import_prefix, prefixes_to_filter);
}
bool NoStreaming() const {
@ -189,6 +190,15 @@ class ProtoBufFile : public grpc_generator::File {
return grpc_python_generator::get_all_comments(file_);
}
vector<grpc::string> GetImportNames() const {
vector<grpc::string> proto_names;
for (int i = 0; i < file_->dependency_count(); ++i) {
const auto& dep = *file_->dependency(i);
proto_names.push_back(dep.name());
}
return proto_names;
}
private:
const grpc::protobuf::FileDescriptor* file_;
};

@ -214,13 +214,15 @@ bool PrivateGenerator::PrintBetaServerFactory(
grpc::string input_message_module_and_class;
if (!method->get_module_and_message_path_input(
&input_message_module_and_class, generator_file_name,
generate_in_pb2_grpc, config.import_prefix)) {
generate_in_pb2_grpc, config.import_prefix,
config.prefixes_to_filter)) {
return false;
}
grpc::string output_message_module_and_class;
if (!method->get_module_and_message_path_output(
&output_message_module_and_class, generator_file_name,
generate_in_pb2_grpc, config.import_prefix)) {
generate_in_pb2_grpc, config.import_prefix,
config.prefixes_to_filter)) {
return false;
}
method_implementation_constructors.insert(
@ -320,13 +322,15 @@ bool PrivateGenerator::PrintBetaStubFactory(
grpc::string input_message_module_and_class;
if (!method->get_module_and_message_path_input(
&input_message_module_and_class, generator_file_name,
generate_in_pb2_grpc, config.import_prefix)) {
generate_in_pb2_grpc, config.import_prefix,
config.prefixes_to_filter)) {
return false;
}
grpc::string output_message_module_and_class;
if (!method->get_module_and_message_path_output(
&output_message_module_and_class, generator_file_name,
generate_in_pb2_grpc, config.import_prefix)) {
generate_in_pb2_grpc, config.import_prefix,
config.prefixes_to_filter)) {
return false;
}
method_cardinalities.insert(
@ -425,13 +429,15 @@ bool PrivateGenerator::PrintStub(
grpc::string request_module_and_class;
if (!method->get_module_and_message_path_input(
&request_module_and_class, generator_file_name,
generate_in_pb2_grpc, config.import_prefix)) {
generate_in_pb2_grpc, config.import_prefix,
config.prefixes_to_filter)) {
return false;
}
grpc::string response_module_and_class;
if (!method->get_module_and_message_path_output(
&response_module_and_class, generator_file_name,
generate_in_pb2_grpc, config.import_prefix)) {
generate_in_pb2_grpc, config.import_prefix,
config.prefixes_to_filter)) {
return false;
}
StringMap method_dict;
@ -516,13 +522,15 @@ bool PrivateGenerator::PrintAddServicerToServer(
grpc::string request_module_and_class;
if (!method->get_module_and_message_path_input(
&request_module_and_class, generator_file_name,
generate_in_pb2_grpc, config.import_prefix)) {
generate_in_pb2_grpc, config.import_prefix,
config.prefixes_to_filter)) {
return false;
}
grpc::string response_module_and_class;
if (!method->get_module_and_message_path_output(
&response_module_and_class, generator_file_name,
generate_in_pb2_grpc, config.import_prefix)) {
generate_in_pb2_grpc, config.import_prefix,
config.prefixes_to_filter)) {
return false;
}
StringMap method_dict;
@ -589,17 +597,21 @@ bool PrivateGenerator::PrintPreamble(grpc_generator::Printer* out) {
grpc::string input_type_file_name = method->get_input_type_name();
grpc::string input_module_name =
ModuleName(input_type_file_name, config.import_prefix);
ModuleName(input_type_file_name, config.import_prefix,
config.prefixes_to_filter);
grpc::string input_module_alias =
ModuleAlias(input_type_file_name, config.import_prefix);
ModuleAlias(input_type_file_name, config.import_prefix,
config.prefixes_to_filter);
imports_set.insert(
std::make_tuple(input_module_name, input_module_alias));
grpc::string output_type_file_name = method->get_output_type_name();
grpc::string output_module_name =
ModuleName(output_type_file_name, config.import_prefix);
ModuleName(output_type_file_name, config.import_prefix,
config.prefixes_to_filter);
grpc::string output_module_alias =
ModuleAlias(output_type_file_name, config.import_prefix);
ModuleAlias(output_type_file_name, config.import_prefix,
config.prefixes_to_filter);
imports_set.insert(
std::make_tuple(output_module_name, output_module_alias));
}

@ -20,6 +20,7 @@
#define GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_H
#include <utility>
#include <vector>
#include "src/compiler/config.h"
#include "src/compiler/schema_interface.h"
@ -35,6 +36,7 @@ struct GeneratorConfiguration {
grpc::string beta_package_root;
// TODO(https://github.com/google/protobuf/issues/888): Drop this.
grpc::string import_prefix;
std::vector<grpc::string> prefixes_to_filter;
};
class PythonGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {

@ -49,23 +49,39 @@ namespace {
typedef vector<const Descriptor*> DescriptorVector;
typedef vector<grpc::string> StringVector;
static grpc::string StripModulePrefixes(
const grpc::string& raw_module_name,
const std::vector<grpc::string>& prefixes_to_filter) {
for (const auto& prefix : prefixes_to_filter) {
if (raw_module_name.rfind(prefix, 0) == 0) {
return raw_module_name.substr(prefix.size(),
raw_module_name.size() - prefix.size());
}
}
return raw_module_name;
}
// TODO(https://github.com/google/protobuf/issues/888):
// Export `ModuleName` from protobuf's
// `src/google/protobuf/compiler/python/python_generator.cc` file.
grpc::string ModuleName(const grpc::string& filename,
const grpc::string& import_prefix) {
const grpc::string& import_prefix,
const std::vector<grpc::string>& prefixes_to_filter) {
grpc::string basename = StripProto(filename);
basename = StringReplace(basename, "-", "_");
basename = StringReplace(basename, "/", ".");
return import_prefix + basename + "_pb2";
return StripModulePrefixes(import_prefix + basename + "_pb2",
prefixes_to_filter);
}
// TODO(https://github.com/google/protobuf/issues/888):
// Export `ModuleAlias` from protobuf's
// `src/google/protobuf/compiler/python/python_generator.cc` file.
grpc::string ModuleAlias(const grpc::string& filename,
const grpc::string& import_prefix) {
grpc::string module_name = ModuleName(filename, import_prefix);
const grpc::string& import_prefix,
const std::vector<grpc::string>& prefixes_to_filter) {
grpc::string module_name =
ModuleName(filename, import_prefix, prefixes_to_filter);
// We can't have dots in the module name, so we replace each with _dot_.
// But that could lead to a collision between a.b and a_dot_b, so we also
// duplicate each underscore.
@ -74,10 +90,10 @@ grpc::string ModuleAlias(const grpc::string& filename,
return module_name;
}
bool GetModuleAndMessagePath(const Descriptor* type, grpc::string* out,
grpc::string generator_file_name,
bool generate_in_pb2_grpc,
grpc::string& import_prefix) {
bool GetModuleAndMessagePath(
const Descriptor* type, grpc::string* out, grpc::string generator_file_name,
bool generate_in_pb2_grpc, grpc::string& import_prefix,
const std::vector<grpc::string>& prefixes_to_filter) {
const Descriptor* path_elem_type = type;
DescriptorVector message_path;
do {
@ -93,7 +109,7 @@ bool GetModuleAndMessagePath(const Descriptor* type, grpc::string* out,
grpc::string module;
if (generator_file_name != file_name || generate_in_pb2_grpc) {
module = ModuleAlias(file_name, import_prefix) + ".";
module = ModuleAlias(file_name, import_prefix, prefixes_to_filter) + ".";
} else {
module = "";
}

@ -57,10 +57,12 @@ struct Method : public CommentHolder {
virtual bool get_module_and_message_path_input(
grpc::string* str, grpc::string generator_file_name,
bool generate_in_pb2_grpc, grpc::string import_prefix) const = 0;
bool generate_in_pb2_grpc, grpc::string import_prefix,
const std::vector<grpc::string>& prefixes_to_filter) const = 0;
virtual bool get_module_and_message_path_output(
grpc::string* str, grpc::string generator_file_name,
bool generate_in_pb2_grpc, grpc::string import_prefix) const = 0;
bool generate_in_pb2_grpc, grpc::string import_prefix,
const std::vector<grpc::string>& prefixes_to_filter) const = 0;
virtual grpc::string get_input_type_name() const = 0;
virtual grpc::string get_output_type_name() const = 0;
@ -101,6 +103,7 @@ struct File : public CommentHolder {
virtual grpc::string package() const = 0;
virtual std::vector<grpc::string> package_parts() const = 0;
virtual grpc::string additional_headers() const = 0;
virtual std::vector<grpc::string> GetImportNames() const { return {}; }
virtual int service_count() const = 0;
virtual std::unique_ptr<const Service> service(int i) const = 0;

File diff suppressed because it is too large Load Diff

@ -49,8 +49,8 @@ ClientChannelNode::ClientChannelNode(grpc_channel* channel,
: ChannelNode(channel, channel_tracer_max_nodes, is_top_level_channel) {
client_channel_ =
grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel));
grpc_client_channel_set_channelz_node(client_channel_, this);
GPR_ASSERT(client_channel_->filter == &grpc_client_channel_filter);
grpc_client_channel_set_channelz_node(client_channel_, this);
}
void ClientChannelNode::PopulateConnectivityState(grpc_json* json) {
@ -127,8 +127,7 @@ void SubchannelNode::PopulateConnectivityState(grpc_json* json) {
if (subchannel_ == nullptr) {
state = GRPC_CHANNEL_SHUTDOWN;
} else {
state = subchannel_->CheckConnectivity(nullptr,
true /* inhibit_health_checking */);
state = subchannel_->CheckConnectivity(true /* inhibit_health_checking */);
}
json = grpc_json_create_child(nullptr, json, "state", nullptr,
GRPC_JSON_OBJECT, false);

@ -25,7 +25,7 @@
/// Channel arg indicating HTTP CONNECT headers (string).
/// Multiple headers are separated by newlines. Key/value pairs are
/// seperated by colons.
/// separated by colons.
#define GRPC_ARG_HTTP_CONNECT_HEADERS "grpc.http_connect_headers"
/// Registers handshaker factory.

@ -185,7 +185,6 @@ class LoadBalancingPolicy : public InternallyRefCounted<LoadBalancingPolicy> {
/// Sets the connectivity state and returns a new picker to be used
/// by the client channel.
virtual void UpdateState(grpc_connectivity_state state,
grpc_error* state_error,
UniquePtr<SubchannelPicker>) GRPC_ABSTRACT;
/// Requests that the resolver re-resolve.

@ -281,7 +281,7 @@ class GrpcLb : public LoadBalancingPolicy {
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, grpc_error* state_error,
void UpdateState(grpc_connectivity_state state,
UniquePtr<SubchannelPicker> picker) override;
void RequestReresolution() override;
@ -621,12 +621,8 @@ grpc_channel* GrpcLb::Helper::CreateChannel(const char* target,
}
void GrpcLb::Helper::UpdateState(grpc_connectivity_state state,
grpc_error* state_error,
UniquePtr<SubchannelPicker> picker) {
if (parent_->shutting_down_) {
GRPC_ERROR_UNREF(state_error);
return;
}
if (parent_->shutting_down_) return;
// 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()) {
@ -636,10 +632,7 @@ void GrpcLb::Helper::UpdateState(grpc_connectivity_state state,
parent_.get(), this, parent_->pending_child_policy_.get(),
grpc_connectivity_state_name(state));
}
if (state != GRPC_CHANNEL_READY) {
GRPC_ERROR_UNREF(state_error);
return;
}
if (state != GRPC_CHANNEL_READY) return;
grpc_pollset_set_del_pollset_set(
parent_->child_policy_->interested_parties(),
parent_->interested_parties());
@ -647,7 +640,6 @@ void GrpcLb::Helper::UpdateState(grpc_connectivity_state state,
parent_->child_policy_ = std::move(parent_->pending_child_policy_);
} else if (!CalledByCurrentChild()) {
// This request is from an outdated child, so ignore it.
GRPC_ERROR_UNREF(state_error);
return;
}
// Record whether child policy reports READY.
@ -682,8 +674,7 @@ void GrpcLb::Helper::UpdateState(grpc_connectivity_state state,
parent_.get(), this, grpc_connectivity_state_name(state),
picker.get());
}
parent_->channel_control_helper()->UpdateState(state, state_error,
std::move(picker));
parent_->channel_control_helper()->UpdateState(state, std::move(picker));
return;
}
// Cases 2 and 3a: wrap picker from the child in our own picker.
@ -698,10 +689,9 @@ void GrpcLb::Helper::UpdateState(grpc_connectivity_state state,
client_stats = parent_->lb_calld_->client_stats()->Ref();
}
parent_->channel_control_helper()->UpdateState(
state, state_error,
UniquePtr<SubchannelPicker>(
New<Picker>(parent_.get(), parent_->serverlist_, std::move(picker),
std::move(client_stats))));
state, UniquePtr<SubchannelPicker>(
New<Picker>(parent_.get(), parent_->serverlist_,
std::move(picker), std::move(client_stats))));
}
void GrpcLb::Helper::RequestReresolution() {

@ -73,7 +73,7 @@ class PickFirst : public LoadBalancingPolicy {
: SubchannelData(subchannel_list, address, subchannel, combiner) {}
void ProcessConnectivityChangeLocked(
grpc_connectivity_state connectivity_state, grpc_error* error) override;
grpc_connectivity_state connectivity_state) override;
// Processes the connectivity change to READY for an unselected subchannel.
void ProcessUnselectedReadyLocked();
@ -189,10 +189,11 @@ void PickFirst::ExitIdleLocked() {
idle_ = false;
if (subchannel_list_ == nullptr ||
subchannel_list_->num_subchannels() == 0) {
grpc_error* error =
GRPC_ERROR_CREATE_FROM_STATIC_STRING("No addresses to connect to");
grpc_error* error = grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("No addresses to connect to"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
channel_control_helper()->UpdateState(
GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(error),
GRPC_CHANNEL_TRANSIENT_FAILURE,
UniquePtr<SubchannelPicker>(New<TransientFailurePicker>(error)));
} else {
subchannel_list_->subchannel(0)
@ -266,9 +267,11 @@ void PickFirst::UpdateLocked(UpdateArgs args) {
// haven't gotten a non-empty update by the time the application tries
// to start a new call.)
if (!idle_) {
grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update");
grpc_error* error = grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
channel_control_helper()->UpdateState(
GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(error),
GRPC_CHANNEL_TRANSIENT_FAILURE,
UniquePtr<SubchannelPicker>(New<TransientFailurePicker>(error)));
}
return;
@ -282,9 +285,7 @@ void PickFirst::UpdateLocked(UpdateArgs args) {
// check and instead do it in ExitIdleLocked().
for (size_t i = 0; i < subchannel_list->num_subchannels(); ++i) {
PickFirstSubchannelData* sd = subchannel_list->subchannel(i);
grpc_error* error = GRPC_ERROR_NONE;
grpc_connectivity_state state = sd->CheckConnectivityStateLocked(&error);
GRPC_ERROR_UNREF(error);
grpc_connectivity_state state = sd->CheckConnectivityStateLocked();
if (state == GRPC_CHANNEL_READY) {
subchannel_list_ = std::move(subchannel_list);
sd->StartConnectivityWatchLocked();
@ -338,7 +339,7 @@ void PickFirst::UpdateLocked(UpdateArgs args) {
}
void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
grpc_connectivity_state connectivity_state, grpc_error* error) {
grpc_connectivity_state connectivity_state) {
PickFirst* p = static_cast<PickFirst*>(subchannel_list()->policy());
AutoChildRefsUpdater guard(p);
// The notification must be for a subchannel in either the current or
@ -369,17 +370,16 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
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()) {
grpc_error* new_error =
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"selected subchannel failed; switching to pending update",
&error, 1);
grpc_error* error = grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"selected subchannel failed; switching to pending update"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
p->channel_control_helper()->UpdateState(
GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(new_error),
UniquePtr<SubchannelPicker>(
New<TransientFailurePicker>(new_error)));
GRPC_CHANNEL_TRANSIENT_FAILURE,
UniquePtr<SubchannelPicker>(New<TransientFailurePicker>(error)));
} else {
p->channel_control_helper()->UpdateState(
GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE,
GRPC_CHANNEL_CONNECTING,
UniquePtr<SubchannelPicker>(New<QueuePicker>(p->Ref())));
}
} else {
@ -393,7 +393,7 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
p->selected_ = nullptr;
StopConnectivityWatchLocked();
p->channel_control_helper()->UpdateState(
GRPC_CHANNEL_IDLE, GRPC_ERROR_NONE,
GRPC_CHANNEL_IDLE,
UniquePtr<SubchannelPicker>(New<QueuePicker>(p->Ref())));
} else {
// This is unlikely but can happen when a subchannel has been asked
@ -401,19 +401,17 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
// some connectivity state notifications.
if (connectivity_state == GRPC_CHANNEL_READY) {
p->channel_control_helper()->UpdateState(
GRPC_CHANNEL_READY, GRPC_ERROR_NONE,
UniquePtr<SubchannelPicker>(
New<Picker>(connected_subchannel()->Ref())));
GRPC_CHANNEL_READY, UniquePtr<SubchannelPicker>(New<Picker>(
connected_subchannel()->Ref())));
} else { // CONNECTING
p->channel_control_helper()->UpdateState(
connectivity_state, GRPC_ERROR_REF(error),
connectivity_state,
UniquePtr<SubchannelPicker>(New<QueuePicker>(p->Ref())));
}
// Renew notification.
RenewConnectivityWatchLocked();
}
}
GRPC_ERROR_UNREF(error);
return;
}
// If we get here, there are two possible cases:
@ -450,13 +448,13 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
subchannel_list()->set_in_transient_failure(true);
// Only report new state in case 1.
if (subchannel_list() == p->subchannel_list_.get()) {
grpc_error* new_error =
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"failed to connect to all addresses", &error, 1);
grpc_error* error = grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"failed to connect to all addresses"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
p->channel_control_helper()->UpdateState(
GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(new_error),
UniquePtr<SubchannelPicker>(
New<TransientFailurePicker>(new_error)));
GRPC_CHANNEL_TRANSIENT_FAILURE,
UniquePtr<SubchannelPicker>(New<TransientFailurePicker>(error)));
}
}
sd->CheckConnectivityStateAndStartWatchingLocked();
@ -467,7 +465,7 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
// Only update connectivity state in case 1.
if (subchannel_list() == p->subchannel_list_.get()) {
p->channel_control_helper()->UpdateState(
GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE,
GRPC_CHANNEL_CONNECTING,
UniquePtr<SubchannelPicker>(New<QueuePicker>(p->Ref())));
}
// Renew notification.
@ -477,7 +475,6 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
case GRPC_CHANNEL_SHUTDOWN:
GPR_UNREACHABLE_CODE(break);
}
GRPC_ERROR_UNREF(error);
}
void PickFirst::PickFirstSubchannelData::ProcessUnselectedReadyLocked() {
@ -507,7 +504,7 @@ void PickFirst::PickFirstSubchannelData::ProcessUnselectedReadyLocked() {
// Cases 1 and 2.
p->selected_ = this;
p->channel_control_helper()->UpdateState(
GRPC_CHANNEL_READY, GRPC_ERROR_NONE,
GRPC_CHANNEL_READY,
UniquePtr<SubchannelPicker>(New<Picker>(connected_subchannel()->Ref())));
if (grpc_lb_pick_first_trace.enabled()) {
gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", p, subchannel());
@ -518,9 +515,7 @@ void PickFirst::PickFirstSubchannelData::
CheckConnectivityStateAndStartWatchingLocked() {
PickFirst* p = static_cast<PickFirst*>(subchannel_list()->policy());
// Check current state.
grpc_error* error = GRPC_ERROR_NONE;
grpc_connectivity_state current_state = CheckConnectivityStateLocked(&error);
GRPC_ERROR_UNREF(error);
grpc_connectivity_state current_state = CheckConnectivityStateLocked();
// Start watch.
StartConnectivityWatchLocked();
// If current state is READY, select the subchannel now, since we started

@ -92,11 +92,11 @@ class RoundRobin : public LoadBalancingPolicy {
}
void UpdateConnectivityStateLocked(
grpc_connectivity_state connectivity_state, grpc_error* error);
grpc_connectivity_state connectivity_state);
private:
void ProcessConnectivityChangeLocked(
grpc_connectivity_state connectivity_state, grpc_error* error) override;
grpc_connectivity_state connectivity_state) override;
grpc_connectivity_state last_connectivity_state_ = GRPC_CHANNEL_IDLE;
};
@ -119,7 +119,6 @@ class RoundRobin : public LoadBalancingPolicy {
}
~RoundRobinSubchannelList() {
GRPC_ERROR_UNREF(last_transient_failure_error_);
RoundRobin* p = static_cast<RoundRobin*>(policy());
p->Unref(DEBUG_LOCATION, "subchannel_list");
}
@ -129,11 +128,8 @@ class RoundRobin : public LoadBalancingPolicy {
// Updates the counters of subchannels in each state when a
// subchannel transitions from old_state to new_state.
// transient_failure_error is the error that is reported when
// new_state is TRANSIENT_FAILURE.
void UpdateStateCountersLocked(grpc_connectivity_state old_state,
grpc_connectivity_state new_state,
grpc_error* transient_failure_error);
grpc_connectivity_state new_state);
// If this subchannel list is the RR policy's current subchannel
// list, updates the RR policy's connectivity state based on the
@ -148,7 +144,6 @@ class RoundRobin : public LoadBalancingPolicy {
size_t num_ready_ = 0;
size_t num_connecting_ = 0;
size_t num_transient_failure_ = 0;
grpc_error* last_transient_failure_error_ = GRPC_ERROR_NONE;
};
class Picker : public SubchannelPicker {
@ -315,11 +310,10 @@ void RoundRobin::RoundRobinSubchannelList::StartWatchingLocked() {
// subchannel already used by some other channel may have a non-IDLE
// state.
for (size_t i = 0; i < num_subchannels(); ++i) {
grpc_error* error = GRPC_ERROR_NONE;
grpc_connectivity_state state =
subchannel(i)->CheckConnectivityStateLocked(&error);
subchannel(i)->CheckConnectivityStateLocked();
if (state != GRPC_CHANNEL_IDLE) {
subchannel(i)->UpdateConnectivityStateLocked(state, error);
subchannel(i)->UpdateConnectivityStateLocked(state);
}
}
// Start connectivity watch for each subchannel.
@ -333,8 +327,7 @@ void RoundRobin::RoundRobinSubchannelList::StartWatchingLocked() {
}
void RoundRobin::RoundRobinSubchannelList::UpdateStateCountersLocked(
grpc_connectivity_state old_state, grpc_connectivity_state new_state,
grpc_error* transient_failure_error) {
grpc_connectivity_state old_state, grpc_connectivity_state new_state) {
GPR_ASSERT(old_state != GRPC_CHANNEL_SHUTDOWN);
GPR_ASSERT(new_state != GRPC_CHANNEL_SHUTDOWN);
if (old_state == GRPC_CHANNEL_READY) {
@ -354,8 +347,6 @@ void RoundRobin::RoundRobinSubchannelList::UpdateStateCountersLocked(
} else if (new_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
++num_transient_failure_;
}
GRPC_ERROR_UNREF(last_transient_failure_error_);
last_transient_failure_error_ = transient_failure_error;
}
// Sets the RR policy's connectivity state and generates a new picker based
@ -382,20 +373,21 @@ void RoundRobin::RoundRobinSubchannelList::
if (num_ready_ > 0) {
/* 1) READY */
p->channel_control_helper()->UpdateState(
GRPC_CHANNEL_READY, GRPC_ERROR_NONE,
UniquePtr<SubchannelPicker>(New<Picker>(p, this)));
GRPC_CHANNEL_READY, UniquePtr<SubchannelPicker>(New<Picker>(p, this)));
} else if (num_connecting_ > 0) {
/* 2) CONNECTING */
p->channel_control_helper()->UpdateState(
GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE,
GRPC_CHANNEL_CONNECTING,
UniquePtr<SubchannelPicker>(New<QueuePicker>(p->Ref())));
} else if (num_transient_failure_ == num_subchannels()) {
/* 3) TRANSIENT_FAILURE */
grpc_error* error =
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"connections to all backends failing"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
p->channel_control_helper()->UpdateState(
GRPC_CHANNEL_TRANSIENT_FAILURE,
GRPC_ERROR_REF(last_transient_failure_error_),
UniquePtr<SubchannelPicker>(New<TransientFailurePicker>(
GRPC_ERROR_REF(last_transient_failure_error_))));
UniquePtr<SubchannelPicker>(New<TransientFailurePicker>(error)));
}
}
@ -430,7 +422,7 @@ void RoundRobin::RoundRobinSubchannelList::
}
void RoundRobin::RoundRobinSubchannelData::UpdateConnectivityStateLocked(
grpc_connectivity_state connectivity_state, grpc_error* error) {
grpc_connectivity_state connectivity_state) {
RoundRobin* p = static_cast<RoundRobin*>(subchannel_list()->policy());
if (grpc_lb_round_robin_trace.enabled()) {
gpr_log(
@ -443,12 +435,12 @@ void RoundRobin::RoundRobinSubchannelData::UpdateConnectivityStateLocked(
grpc_connectivity_state_name(connectivity_state));
}
subchannel_list()->UpdateStateCountersLocked(last_connectivity_state_,
connectivity_state, error);
connectivity_state);
last_connectivity_state_ = connectivity_state;
}
void RoundRobin::RoundRobinSubchannelData::ProcessConnectivityChangeLocked(
grpc_connectivity_state connectivity_state, grpc_error* error) {
grpc_connectivity_state connectivity_state) {
RoundRobin* p = static_cast<RoundRobin*>(subchannel_list()->policy());
GPR_ASSERT(subchannel() != nullptr);
// If the new state is TRANSIENT_FAILURE, re-resolve.
@ -468,7 +460,7 @@ void RoundRobin::RoundRobinSubchannelData::ProcessConnectivityChangeLocked(
// Renew connectivity watch.
RenewConnectivityWatchLocked();
// Update state counters.
UpdateConnectivityStateLocked(connectivity_state, error);
UpdateConnectivityStateLocked(connectivity_state);
// Update overall state and renew notification.
subchannel_list()->UpdateRoundRobinStateFromSubchannelStateCountsLocked();
}
@ -492,9 +484,11 @@ void RoundRobin::UpdateLocked(UpdateArgs args) {
if (latest_pending_subchannel_list_->num_subchannels() == 0) {
// If the new list is empty, immediately promote the new list to the
// current list and transition to TRANSIENT_FAILURE.
grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update");
grpc_error* error =
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
channel_control_helper()->UpdateState(
GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(error),
GRPC_CHANNEL_TRANSIENT_FAILURE,
UniquePtr<SubchannelPicker>(New<TransientFailurePicker>(error)));
subchannel_list_ = std::move(latest_pending_subchannel_list_);
} else if (subchannel_list_ == nullptr) {

@ -51,7 +51,7 @@ class MySubchannelData
: public SubchannelData<MySubchannelList, MySubchannelData> {
public:
void ProcessConnectivityChangeLocked(
grpc_connectivity_state connectivity_state, grpc_error* error) override {
grpc_connectivity_state connectivity_state) override {
// ...code to handle connectivity changes...
}
};
@ -101,10 +101,10 @@ class SubchannelData {
// pending (i.e., between calling StartConnectivityWatchLocked() or
// RenewConnectivityWatchLocked() and the resulting invocation of
// ProcessConnectivityChangeLocked()).
grpc_connectivity_state CheckConnectivityStateLocked(grpc_error** error) {
grpc_connectivity_state CheckConnectivityStateLocked() {
GPR_ASSERT(!connectivity_notification_pending_);
pending_connectivity_state_unsafe_ = subchannel()->CheckConnectivity(
error, subchannel_list_->inhibit_health_checking());
subchannel_list_->inhibit_health_checking());
UpdateConnectedSubchannelLocked();
return pending_connectivity_state_unsafe_;
}
@ -153,8 +153,7 @@ class SubchannelData {
// Implementations must invoke either RenewConnectivityWatchLocked() or
// StopConnectivityWatchLocked() before returning.
virtual void ProcessConnectivityChangeLocked(
grpc_connectivity_state connectivity_state,
grpc_error* error) GRPC_ABSTRACT;
grpc_connectivity_state connectivity_state) GRPC_ABSTRACT;
// Unrefs the subchannel.
void UnrefSubchannelLocked(const char* reason);
@ -462,8 +461,7 @@ void SubchannelData<SubchannelListType, SubchannelDataType>::
return;
}
// Call the subclass's ProcessConnectivityChangeLocked() method.
sd->ProcessConnectivityChangeLocked(sd->pending_connectivity_state_unsafe_,
GRPC_ERROR_REF(error));
sd->ProcessConnectivityChangeLocked(sd->pending_connectivity_state_unsafe_);
}
template <typename SubchannelListType, typename SubchannelDataType>

@ -118,6 +118,7 @@ namespace {
constexpr char kXds[] = "xds_experimental";
constexpr char kDefaultLocalityName[] = "xds_default_locality";
constexpr uint32_t kDefaultLocalityWeight = 3;
class XdsLb : public LoadBalancingPolicy {
public:
@ -259,26 +260,51 @@ class XdsLb : public LoadBalancingPolicy {
bool retry_timer_callback_pending_ = false;
};
// Since pickers are UniquePtrs we use this RefCounted wrapper
// to control references to it by the xds picker and the locality
// entry
class PickerRef : public RefCounted<PickerRef> {
public:
explicit PickerRef(UniquePtr<SubchannelPicker> picker)
: picker_(std::move(picker)) {}
PickResult Pick(PickArgs* pick, grpc_error** error) {
return picker_->Pick(pick, error);
}
private:
UniquePtr<SubchannelPicker> picker_;
};
// The picker will use a stateless weighting algorithm to pick the locality to
// use for each request.
class Picker : public SubchannelPicker {
public:
Picker(UniquePtr<SubchannelPicker> child_picker,
RefCountedPtr<XdsLbClientStats> client_stats)
: child_picker_(std::move(child_picker)),
client_stats_(std::move(client_stats)) {}
// Maintains a weighted list of pickers from each locality that is in ready
// state. The first element in the pair represents the end of a range
// proportional to the locality's weight. The start of the range is the
// previous value in the vector and is 0 for the first element.
using PickerList =
InlinedVector<Pair<uint32_t, RefCountedPtr<PickerRef>>, 1>;
Picker(RefCountedPtr<XdsLbClientStats> client_stats, PickerList pickers)
: client_stats_(std::move(client_stats)),
pickers_(std::move(pickers)) {}
PickResult Pick(PickArgs* pick, grpc_error** error) override;
private:
UniquePtr<SubchannelPicker> child_picker_;
// Calls the picker of the locality that the key falls within
PickResult PickFromLocality(const uint32_t key, PickArgs* pick,
grpc_error** error);
RefCountedPtr<XdsLbClientStats> client_stats_;
PickerList pickers_;
};
class LocalityMap {
public:
class LocalityEntry : public InternallyRefCounted<LocalityEntry> {
public:
explicit LocalityEntry(RefCountedPtr<XdsLb> parent)
: parent_(std::move(parent)) {}
LocalityEntry(RefCountedPtr<XdsLb> parent, uint32_t locality_weight)
: parent_(std::move(parent)), locality_weight_(locality_weight) {}
~LocalityEntry() = default;
void UpdateLocked(xds_grpclb_serverlist* serverlist,
@ -299,7 +325,7 @@ class XdsLb : public LoadBalancingPolicy {
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, grpc_error* state_error,
void UpdateState(grpc_connectivity_state state,
UniquePtr<SubchannelPicker> picker) override;
void RequestReresolution() override;
void set_child(LoadBalancingPolicy* child) { child_ = child; }
@ -323,6 +349,9 @@ class XdsLb : public LoadBalancingPolicy {
// pending_child_policy_.
Mutex child_policy_mu_;
RefCountedPtr<XdsLb> parent_;
RefCountedPtr<PickerRef> picker_ref_;
grpc_connectivity_state connectivity_state_;
uint32_t locality_weight_;
};
void UpdateLocked(const LocalityList& locality_list,
@ -346,7 +375,9 @@ class XdsLb : public LoadBalancingPolicy {
gpr_free(locality_name);
xds_grpclb_destroy_serverlist(serverlist);
}
char* locality_name;
uint32_t locality_weight;
// The deserialized response from the balancer. May be nullptr until one
// such response has arrived.
xds_grpclb_serverlist* serverlist;
@ -412,6 +443,8 @@ class XdsLb : public LoadBalancingPolicy {
RefCountedPtr<Config> child_policy_config_;
// Map of policies to use in the backend
LocalityMap locality_map_;
// TODO(mhaidry) : Add support for multiple maps of localities
// with different priorities
LocalityList locality_serverlist_;
// TODO(mhaidry) : Add a pending locality map that may be swapped with the
// the current one when new localities in the pending map are ready
@ -424,8 +457,12 @@ class XdsLb : public LoadBalancingPolicy {
XdsLb::PickResult XdsLb::Picker::Pick(PickArgs* pick, grpc_error** error) {
// TODO(roth): Add support for drop handling.
// Forward pick to child policy.
PickResult result = child_picker_->Pick(pick, error);
// Generate a random number between 0 and the total weight
const uint32_t key =
(rand() * pickers_[pickers_.size() - 1].first) / RAND_MAX;
// Forward pick to whichever locality maps to the range in which the
// random number falls in.
PickResult result = PickFromLocality(key, pick, error);
// If pick succeeded, add client stats.
if (result == PickResult::PICK_COMPLETE &&
pick->connected_subchannel != nullptr && client_stats_ != nullptr) {
@ -434,6 +471,29 @@ XdsLb::PickResult XdsLb::Picker::Pick(PickArgs* pick, grpc_error** error) {
return result;
}
XdsLb::PickResult XdsLb::Picker::PickFromLocality(const uint32_t key,
PickArgs* pick,
grpc_error** error) {
size_t mid = 0;
size_t start_index = 0;
size_t end_index = pickers_.size() - 1;
size_t index = 0;
while (end_index > start_index) {
mid = (start_index + end_index) / 2;
if (pickers_[mid].first > key) {
end_index = mid;
} else if (pickers_[mid].first < key) {
start_index = mid + 1;
} else {
index = mid + 1;
break;
}
}
if (index == 0) index = start_index;
GPR_ASSERT(pickers_[index].first > key);
return pickers_[index].second->Pick(pick, error);
}
//
// serverlist parsing code
//
@ -935,6 +995,8 @@ void XdsLb::BalancerChannelState::BalancerCallState::
MakeUnique<LocalityServerlistEntry>());
xdslb_policy->locality_serverlist_[0]->locality_name =
static_cast<char*>(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
@ -1316,8 +1378,8 @@ void XdsLb::LocalityMap::UpdateLocked(
gpr_strdup(locality_serverlist[i]->locality_name));
auto iter = map_.find(locality_name);
if (iter == map_.end()) {
OrphanablePtr<LocalityEntry> new_entry =
MakeOrphanable<LocalityEntry>(parent->Ref());
OrphanablePtr<LocalityEntry> new_entry = MakeOrphanable<LocalityEntry>(
parent->Ref(), locality_serverlist[i]->locality_weight);
MutexLock lock(&child_refs_mu_);
iter = map_.emplace(std::move(locality_name), std::move(new_entry)).first;
}
@ -1335,8 +1397,8 @@ void grpc_core::XdsLb::LocalityMap::ShutdownLocked() {
}
void grpc_core::XdsLb::LocalityMap::ResetBackoffLocked() {
for (auto iter = map_.begin(); iter != map_.end(); iter++) {
iter->second->ResetBackoffLocked();
for (auto& p : map_) {
p.second->ResetBackoffLocked();
}
}
@ -1344,8 +1406,8 @@ void grpc_core::XdsLb::LocalityMap::FillChildRefsForChannelz(
channelz::ChildRefsList* child_subchannels,
channelz::ChildRefsList* child_channels) {
MutexLock lock(&child_refs_mu_);
for (auto iter = map_.begin(); iter != map_.end(); iter++) {
iter->second->FillChildRefsForChannelz(child_subchannels, child_channels);
for (auto& p : map_) {
p.second->FillChildRefsForChannelz(child_subchannels, child_channels);
}
}
@ -1558,6 +1620,7 @@ void XdsLb::LocalityMap::LocalityEntry::Orphan() {
//
// LocalityEntry::Helper implementation
//
bool XdsLb::LocalityMap::LocalityEntry::Helper::CalledByPendingChild() const {
GPR_ASSERT(child_ != nullptr);
return child_ == entry_->pending_child_policy_.get();
@ -1587,12 +1650,8 @@ grpc_channel* XdsLb::LocalityMap::LocalityEntry::Helper::CreateChannel(
}
void XdsLb::LocalityMap::LocalityEntry::Helper::UpdateState(
grpc_connectivity_state state, grpc_error* state_error,
UniquePtr<SubchannelPicker> picker) {
if (entry_->parent_->shutting_down_) {
GRPC_ERROR_UNREF(state_error);
return;
}
grpc_connectivity_state state, UniquePtr<SubchannelPicker> picker) {
if (entry_->parent_->shutting_down_) return;
// 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()) {
@ -1602,10 +1661,7 @@ void XdsLb::LocalityMap::LocalityEntry::Helper::UpdateState(
entry_->parent_.get(), this, entry_->pending_child_policy_.get(),
grpc_connectivity_state_name(state));
}
if (state != GRPC_CHANNEL_READY) {
GRPC_ERROR_UNREF(state_error);
return;
}
if (state != GRPC_CHANNEL_READY) return;
grpc_pollset_set_del_pollset_set(
entry_->child_policy_->interested_parties(),
entry_->parent_->interested_parties());
@ -1613,7 +1669,6 @@ void XdsLb::LocalityMap::LocalityEntry::Helper::UpdateState(
entry_->child_policy_ = std::move(entry_->pending_child_policy_);
} else if (!CalledByCurrentChild()) {
// This request is from an outdated child, so ignore it.
GRPC_ERROR_UNREF(state_error);
return;
}
// TODO(juanlishen): When in fallback mode, pass the child picker
@ -1624,10 +1679,72 @@ void XdsLb::LocalityMap::LocalityEntry::Helper::UpdateState(
entry_->parent_->lb_chand_->lb_calld() == nullptr
? nullptr
: entry_->parent_->lb_chand_->lb_calld()->client_stats();
entry_->parent_->channel_control_helper()->UpdateState(
state, state_error,
UniquePtr<SubchannelPicker>(
New<Picker>(std::move(picker), std::move(client_stats))));
// Cache the picker and its state in the entry
entry_->picker_ref_ = MakeRefCounted<PickerRef>(std::move(picker));
entry_->connectivity_state_ = state;
// Construct a new xds picker which maintains a map of all locality pickers
// that are ready. Each locality is represented by a portion of the range
// proportional to its weight, such that the total range is the sum of the
// weights of all localities
uint32_t end = 0;
size_t num_connecting = 0;
size_t num_idle = 0;
size_t num_transient_failures = 0;
auto& locality_map = this->entry_->parent_->locality_map_.map_;
Picker::PickerList pickers;
for (auto& p : locality_map) {
const LocalityEntry* entry = p.second.get();
grpc_connectivity_state connectivity_state = entry->connectivity_state_;
switch (connectivity_state) {
case GRPC_CHANNEL_READY: {
end += entry->locality_weight_;
pickers.push_back(MakePair(end, entry->picker_ref_));
break;
}
case GRPC_CHANNEL_CONNECTING: {
num_connecting++;
break;
}
case GRPC_CHANNEL_IDLE: {
num_idle++;
break;
}
case GRPC_CHANNEL_TRANSIENT_FAILURE: {
num_transient_failures++;
break;
}
default: {
gpr_log(GPR_ERROR, "Invalid locality connectivity state - %d",
connectivity_state);
}
}
}
// Pass on the constructed xds picker if it has any ready pickers in their map
// otherwise pass a QueuePicker if any of the locality pickers are in a
// connecting or idle state, finally return a transient failure picker if all
// locality pickers are in transient failure
if (pickers.size() > 0) {
entry_->parent_->channel_control_helper()->UpdateState(
GRPC_CHANNEL_READY,
UniquePtr<LoadBalancingPolicy::SubchannelPicker>(
New<Picker>(std::move(client_stats), std::move(pickers))));
} else if (num_connecting > 0) {
entry_->parent_->channel_control_helper()->UpdateState(
GRPC_CHANNEL_CONNECTING,
UniquePtr<SubchannelPicker>(New<QueuePicker>(this->entry_->parent_)));
} else if (num_idle > 0) {
entry_->parent_->channel_control_helper()->UpdateState(
GRPC_CHANNEL_IDLE,
UniquePtr<SubchannelPicker>(New<QueuePicker>(this->entry_->parent_)));
} else {
GPR_ASSERT(num_transient_failures == locality_map.size());
grpc_error* error =
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"connections to all localities failing"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
entry_->parent_->channel_control_helper()->UpdateState(
state, UniquePtr<SubchannelPicker>(New<TransientFailurePicker>(error)));
}
}
void XdsLb::LocalityMap::LocalityEntry::Helper::RequestReresolution() {

@ -43,6 +43,7 @@
#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/iomgr/gethostname.h"
#include "src/core/lib/iomgr/iomgr_custom.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/json/json.h"
@ -430,8 +431,11 @@ static grpc_address_resolver_vtable ares_resolver = {
grpc_resolve_address_ares, blocking_resolve_address_ares};
static bool should_use_ares(const char* resolver_env) {
return resolver_env == nullptr || strlen(resolver_env) == 0 ||
gpr_stricmp(resolver_env, "ares") == 0;
// TODO(lidiz): Remove the "g_custom_iomgr_enabled" flag once c-ares support
// custom IO managers (e.g. gevent).
return !g_custom_iomgr_enabled &&
(resolver_env == nullptr || strlen(resolver_env) == 0 ||
gpr_stricmp(resolver_env, "ares") == 0);
}
void grpc_resolver_dns_ares_init() {

@ -119,13 +119,9 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper
return parent_->channel_control_helper()->CreateChannel(target, args);
}
void UpdateState(grpc_connectivity_state state, grpc_error* state_error,
void UpdateState(grpc_connectivity_state state,
UniquePtr<SubchannelPicker> picker) override {
if (parent_->resolver_ == nullptr) {
// shutting down.
GRPC_ERROR_UNREF(state_error);
return;
}
if (parent_->resolver_ == nullptr) return; // Shutting down.
// 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()) {
@ -136,10 +132,7 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper
parent_.get(), this, child_,
grpc_connectivity_state_name(state));
}
if (state != GRPC_CHANNEL_READY) {
GRPC_ERROR_UNREF(state_error);
return;
}
if (state != GRPC_CHANNEL_READY) return;
grpc_pollset_set_del_pollset_set(
parent_->lb_policy_->interested_parties(),
parent_->interested_parties());
@ -147,11 +140,9 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper
parent_->lb_policy_ = std::move(parent_->pending_lb_policy_);
} else if (!CalledByCurrentChild()) {
// This request is from an outdated child, so ignore it.
GRPC_ERROR_UNREF(state_error);
return;
}
parent_->channel_control_helper()->UpdateState(state, state_error,
std::move(picker));
parent_->channel_control_helper()->UpdateState(state, std::move(picker));
}
void RequestReresolution() override {
@ -234,8 +225,7 @@ grpc_error* ResolvingLoadBalancingPolicy::Init(const grpc_channel_args& args) {
}
// Return our picker to the channel.
channel_control_helper()->UpdateState(
GRPC_CHANNEL_IDLE, GRPC_ERROR_NONE,
UniquePtr<SubchannelPicker>(New<QueuePicker>(Ref())));
GRPC_CHANNEL_IDLE, UniquePtr<SubchannelPicker>(New<QueuePicker>(Ref())));
return GRPC_ERROR_NONE;
}
@ -313,7 +303,7 @@ void ResolvingLoadBalancingPolicy::StartResolvingLocked() {
GPR_ASSERT(!started_resolving_);
started_resolving_ = true;
channel_control_helper()->UpdateState(
GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE,
GRPC_CHANNEL_CONNECTING,
UniquePtr<SubchannelPicker>(New<QueuePicker>(Ref())));
resolver_->StartLocked();
}
@ -334,7 +324,7 @@ void ResolvingLoadBalancingPolicy::OnResolverError(grpc_error* error) {
grpc_error* state_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Resolver transient failure", &error, 1);
channel_control_helper()->UpdateState(
GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(state_error),
GRPC_CHANNEL_TRANSIENT_FAILURE,
UniquePtr<SubchannelPicker>(New<TransientFailurePicker>(state_error)));
}
GRPC_ERROR_UNREF(error);

@ -332,10 +332,9 @@ class Subchannel::ConnectedSubchannelStateWatcher
health_state = GRPC_CHANNEL_CONNECTING;
}
// Report initial state.
c->SetConnectivityStateLocked(GRPC_CHANNEL_READY, GRPC_ERROR_NONE,
"subchannel_connected");
c->SetConnectivityStateLocked(GRPC_CHANNEL_READY, "subchannel_connected");
grpc_connectivity_state_set(&c->state_and_health_tracker_, health_state,
GRPC_ERROR_NONE, "subchannel_connected");
"subchannel_connected");
}
~ConnectedSubchannelStateWatcher() {
@ -367,11 +366,10 @@ class Subchannel::ConnectedSubchannelStateWatcher
c->connected_subchannel_watcher_.reset();
self->last_connectivity_state_ = GRPC_CHANNEL_TRANSIENT_FAILURE;
c->SetConnectivityStateLocked(GRPC_CHANNEL_TRANSIENT_FAILURE,
GRPC_ERROR_REF(error),
"reflect_child");
grpc_connectivity_state_set(&c->state_and_health_tracker_,
GRPC_CHANNEL_TRANSIENT_FAILURE,
GRPC_ERROR_REF(error), "reflect_child");
"reflect_child");
c->backoff_begun_ = false;
c->backoff_.Reset();
c->MaybeStartConnectingLocked();
@ -388,11 +386,11 @@ class Subchannel::ConnectedSubchannelStateWatcher
// from READY to CONNECTING or IDLE.
self->last_connectivity_state_ = self->pending_connectivity_state_;
c->SetConnectivityStateLocked(self->pending_connectivity_state_,
GRPC_ERROR_REF(error), "reflect_child");
"reflect_child");
if (self->pending_connectivity_state_ != GRPC_CHANNEL_READY) {
grpc_connectivity_state_set(&c->state_and_health_tracker_,
self->pending_connectivity_state_,
GRPC_ERROR_REF(error), "reflect_child");
"reflect_child");
}
c->connected_subchannel_->NotifyOnStateChange(
nullptr, &self->pending_connectivity_state_,
@ -415,8 +413,7 @@ class Subchannel::ConnectedSubchannelStateWatcher
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_,
GRPC_ERROR_REF(error), "health_changed");
self->health_state_, "health_changed");
}
self->health_check_client_->NotifyOnHealthChange(
&self->health_state_, &self->on_health_changed_);
@ -742,11 +739,10 @@ channelz::SubchannelNode* Subchannel::channelz_node() {
}
grpc_connectivity_state Subchannel::CheckConnectivity(
grpc_error** error, bool inhibit_health_checking) {
MutexLock lock(&mu_);
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_get(tracker, error);
grpc_connectivity_state state = grpc_connectivity_state_check(tracker);
return state;
}
@ -854,7 +850,6 @@ const char* SubchannelConnectivityStateChangeString(
} // namespace
void Subchannel::SetConnectivityStateLocked(grpc_connectivity_state state,
grpc_error* error,
const char* reason) {
if (channelz_node_ != nullptr) {
channelz_node_->AddTraceEvent(
@ -862,7 +857,7 @@ void Subchannel::SetConnectivityStateLocked(grpc_connectivity_state state,
grpc_slice_from_static_string(
SubchannelConnectivityStateChangeString(state)));
}
grpc_connectivity_state_set(&state_tracker_, state, error, reason);
grpc_connectivity_state_set(&state_tracker_, state, reason);
}
void Subchannel::MaybeStartConnectingLocked() {
@ -939,11 +934,9 @@ 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, GRPC_ERROR_NONE,
"connecting");
SetConnectivityStateLocked(GRPC_CHANNEL_CONNECTING, "connecting");
grpc_connectivity_state_set(&state_and_health_tracker_,
GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE,
"connecting");
GRPC_CHANNEL_CONNECTING, "connecting");
grpc_connector_connect(connector_, &args, &connecting_result_,
&on_connecting_finished_);
}
@ -961,16 +954,11 @@ void Subchannel::OnConnectingFinished(void* arg, grpc_error* error) {
} else if (c->disconnected_) {
GRPC_SUBCHANNEL_WEAK_UNREF(c, "connecting");
} else {
const char* errmsg = grpc_error_string(error);
gpr_log(GPR_INFO, "Connect failed: %s", errmsg);
error = grpc_error_set_int(
GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Connect Failed",
&error, 1),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
gpr_log(GPR_INFO, "Connect failed: %s", grpc_error_string(error));
c->SetConnectivityStateLocked(GRPC_CHANNEL_TRANSIENT_FAILURE,
GRPC_ERROR_REF(error), "connect_failed");
"connect_failed");
grpc_connectivity_state_set(&c->state_and_health_tracker_,
GRPC_CHANNEL_TRANSIENT_FAILURE, error,
GRPC_CHANNEL_TRANSIENT_FAILURE,
"connect_failed");
c->MaybeStartConnectingLocked();
GRPC_SUBCHANNEL_WEAK_UNREF(c, "connecting");

@ -208,8 +208,7 @@ class Subchannel {
channelz::SubchannelNode* channelz_node();
// Polls the current connectivity state of the subchannel.
grpc_connectivity_state CheckConnectivity(grpc_error** error,
bool inhibit_health_checking);
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.
@ -242,7 +241,7 @@ class Subchannel {
// Sets the subchannel's connectivity state to \a state.
void SetConnectivityStateLocked(grpc_connectivity_state state,
grpc_error* error, const char* reason);
const char* reason);
// Methods for connection.
void MaybeStartConnectingLocked();

@ -124,7 +124,7 @@ static void cancel_timer_if_needed(grpc_deadline_state* deadline_state) {
deadline_state->timer_state = GRPC_DEADLINE_STATE_FINISHED;
grpc_timer_cancel(&deadline_state->timer);
} else {
// timer was either in STATE_INITAL (nothing to cancel)
// timer was either in STATE_INITIAL (nothing to cancel)
// OR in STATE_FINISHED (again nothing to cancel)
}
}

@ -36,7 +36,7 @@
#define EXPECTED_CONTENT_TYPE "application/grpc"
#define EXPECTED_CONTENT_TYPE_LENGTH sizeof(EXPECTED_CONTENT_TYPE) - 1
/* default maximum size of payload eligable for GET request */
/* default maximum size of payload eligible for GET request */
static constexpr size_t kMaxPayloadSizeForGet = 2048;
static void recv_initial_metadata_ready(void* user_data, grpc_error* error);
@ -107,7 +107,8 @@ static grpc_error* client_filter_incoming_metadata(grpc_call_element* elem,
* https://github.com/grpc/grpc/blob/master/doc/http-grpc-status-mapping.md.
*/
if (b->idx.named.grpc_status != nullptr ||
grpc_mdelem_eq(b->idx.named.status->md, GRPC_MDELEM_STATUS_200)) {
grpc_mdelem_static_value_eq(b->idx.named.status->md,
GRPC_MDELEM_STATUS_200)) {
grpc_metadata_batch_remove(b, b->idx.named.status);
} else {
char* val = grpc_dump_slice(GRPC_MDVALUE(b->idx.named.status->md),
@ -140,8 +141,9 @@ static grpc_error* client_filter_incoming_metadata(grpc_call_element* elem,
}
if (b->idx.named.content_type != nullptr) {
if (!grpc_mdelem_eq(b->idx.named.content_type->md,
GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC)) {
if (!grpc_mdelem_static_value_eq(
b->idx.named.content_type->md,
GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC)) {
if (grpc_slice_buf_start_eq(GRPC_MDVALUE(b->idx.named.content_type->md),
EXPECTED_CONTENT_TYPE,
EXPECTED_CONTENT_TYPE_LENGTH) &&

@ -25,7 +25,7 @@
/* Processes metadata on the client side for HTTP2 transports */
extern const grpc_channel_filter grpc_http_client_filter;
/* Channel arg to determine maximum size of payload eligable for GET request */
/* Channel arg to determine maximum size of payload eligible for GET request */
#define GRPC_ARG_MAX_PAYLOAD_SIZE_FOR_GET "grpc.max_payload_size_for_get"
#endif /* GRPC_CORE_EXT_FILTERS_HTTP_CLIENT_HTTP_CLIENT_FILTER_H */

@ -29,6 +29,7 @@
#include "src/core/ext/filters/http/message_compress/message_compress_filter.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/compression/algorithm_metadata.h"
#include "src/core/lib/compression/compression_args.h"
#include "src/core/lib/compression/compression_internal.h"
#include "src/core/lib/compression/message_compress.h"
#include "src/core/lib/gpr/string.h"

@ -131,18 +131,19 @@ static grpc_error* hs_filter_incoming_metadata(grpc_call_element* elem,
static const char* error_name = "Failed processing incoming headers";
if (b->idx.named.method != nullptr) {
if (grpc_mdelem_eq(b->idx.named.method->md, GRPC_MDELEM_METHOD_POST)) {
if (grpc_mdelem_static_value_eq(b->idx.named.method->md,
GRPC_MDELEM_METHOD_POST)) {
*calld->recv_initial_metadata_flags &=
~(GRPC_INITIAL_METADATA_CACHEABLE_REQUEST |
GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST);
} else if (grpc_mdelem_eq(b->idx.named.method->md,
GRPC_MDELEM_METHOD_PUT)) {
} else if (grpc_mdelem_static_value_eq(b->idx.named.method->md,
GRPC_MDELEM_METHOD_PUT)) {
*calld->recv_initial_metadata_flags &=
~GRPC_INITIAL_METADATA_CACHEABLE_REQUEST;
*calld->recv_initial_metadata_flags |=
GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST;
} else if (grpc_mdelem_eq(b->idx.named.method->md,
GRPC_MDELEM_METHOD_GET)) {
} else if (grpc_mdelem_static_value_eq(b->idx.named.method->md,
GRPC_MDELEM_METHOD_GET)) {
*calld->recv_initial_metadata_flags |=
GRPC_INITIAL_METADATA_CACHEABLE_REQUEST;
*calld->recv_initial_metadata_flags &=
@ -163,7 +164,8 @@ static grpc_error* hs_filter_incoming_metadata(grpc_call_element* elem,
}
if (b->idx.named.te != nullptr) {
if (!grpc_mdelem_eq(b->idx.named.te->md, GRPC_MDELEM_TE_TRAILERS)) {
if (!grpc_mdelem_static_value_eq(b->idx.named.te->md,
GRPC_MDELEM_TE_TRAILERS)) {
hs_add_error(error_name, &error,
grpc_attach_md_to_error(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad header"),
@ -178,9 +180,12 @@ static grpc_error* hs_filter_incoming_metadata(grpc_call_element* elem,
}
if (b->idx.named.scheme != nullptr) {
if (!grpc_mdelem_eq(b->idx.named.scheme->md, GRPC_MDELEM_SCHEME_HTTP) &&
!grpc_mdelem_eq(b->idx.named.scheme->md, GRPC_MDELEM_SCHEME_HTTPS) &&
!grpc_mdelem_eq(b->idx.named.scheme->md, GRPC_MDELEM_SCHEME_GRPC)) {
if (!grpc_mdelem_static_value_eq(b->idx.named.scheme->md,
GRPC_MDELEM_SCHEME_HTTP) &&
!grpc_mdelem_static_value_eq(b->idx.named.scheme->md,
GRPC_MDELEM_SCHEME_HTTPS) &&
!grpc_mdelem_static_value_eq(b->idx.named.scheme->md,
GRPC_MDELEM_SCHEME_GRPC)) {
hs_add_error(error_name, &error,
grpc_attach_md_to_error(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Bad header"),
@ -196,8 +201,9 @@ static grpc_error* hs_filter_incoming_metadata(grpc_call_element* elem,
}
if (b->idx.named.content_type != nullptr) {
if (!grpc_mdelem_eq(b->idx.named.content_type->md,
GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC)) {
if (!grpc_mdelem_static_value_eq(
b->idx.named.content_type->md,
GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC)) {
if (grpc_slice_buf_start_eq(GRPC_MDVALUE(b->idx.named.content_type->md),
EXPECTED_CONTENT_TYPE,
EXPECTED_CONTENT_TYPE_LENGTH) &&

@ -23,7 +23,7 @@
#include <string.h>
/* Retuns 1 if the version is supported, 0 otherwise. */
/* Returns 1 if the version is supported, 0 otherwise. */
int grpc_chttp2_is_alpn_version_supported(const char* version, size_t size);
/* Returns the number of protocol versions to advertise */

@ -119,7 +119,7 @@ static void maybe_start_some_streams(grpc_chttp2_transport* t);
static void connectivity_state_set(grpc_chttp2_transport* t,
grpc_connectivity_state state,
grpc_error* error, const char* reason);
const char* reason);
static void benign_reclaimer_locked(void* t, grpc_error* error);
static void destructive_reclaimer_locked(void* t, grpc_error* error);
@ -592,8 +592,7 @@ static void close_transport_locked(grpc_chttp2_transport* t,
}
GPR_ASSERT(error != GRPC_ERROR_NONE);
t->closed_with_error = GRPC_ERROR_REF(error);
connectivity_state_set(t, GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_REF(error),
"close_transport");
connectivity_state_set(t, GRPC_CHANNEL_SHUTDOWN, "close_transport");
if (t->ping_state.is_delayed_ping_timer_set) {
grpc_timer_cancel(&t->ping_state.delayed_ping_timer);
}
@ -1171,8 +1170,7 @@ void grpc_chttp2_add_incoming_goaway(grpc_chttp2_transport* t,
/* lie: use transient failure from the transport to indicate goaway has been
* received */
connectivity_state_set(t, GRPC_CHANNEL_TRANSIENT_FAILURE,
GRPC_ERROR_REF(t->goaway_error), "got_goaway");
connectivity_state_set(t, GRPC_CHANNEL_TRANSIENT_FAILURE, "got_goaway");
}
static void maybe_start_some_streams(grpc_chttp2_transport* t) {
@ -1194,10 +1192,8 @@ static void maybe_start_some_streams(grpc_chttp2_transport* t) {
t->next_stream_id += 2;
if (t->next_stream_id >= MAX_CLIENT_STREAM_ID) {
connectivity_state_set(
t, GRPC_CHANNEL_TRANSIENT_FAILURE,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Stream IDs exhausted"),
"no_more_stream_ids");
connectivity_state_set(t, GRPC_CHANNEL_TRANSIENT_FAILURE,
"no_more_stream_ids");
}
grpc_chttp2_stream_map_add(&t->stream_map, s->id, s);
@ -1285,8 +1281,8 @@ void grpc_chttp2_complete_closure_step(grpc_chttp2_transport* t,
static bool contains_non_ok_status(grpc_metadata_batch* batch) {
if (batch->idx.named.grpc_status != nullptr) {
return !grpc_mdelem_eq(batch->idx.named.grpc_status->md,
GRPC_MDELEM_GRPC_STATUS_0);
return !grpc_mdelem_static_value_eq(batch->idx.named.grpc_status->md,
GRPC_MDELEM_GRPC_STATUS_0);
}
return false;
}
@ -1417,7 +1413,7 @@ static void perform_stream_op_locked(void* stream_op,
// on_complete will be null if and only if there are no send ops in the batch.
if (on_complete != nullptr) {
// This batch has send ops. Use final_data as a barrier until enqueue time;
// the inital counter is dropped at the end of this function.
// the initial counter is dropped at the end of this function.
on_complete->next_data.scratch = CLOSURE_BARRIER_FIRST_REF_BIT;
on_complete->error_data.error = GRPC_ERROR_NONE;
}
@ -2804,9 +2800,9 @@ static void keepalive_watchdog_fired_locked(void* arg, grpc_error* error) {
static void connectivity_state_set(grpc_chttp2_transport* t,
grpc_connectivity_state state,
grpc_error* error, const char* reason) {
const char* reason) {
GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_INFO, "set connectivity_state=%d", state));
grpc_connectivity_state_set(&t->channel_callback.state_tracker, state, error,
grpc_connectivity_state_set(&t->channel_callback.state_tracker, state,
reason);
}

@ -56,7 +56,7 @@
/* don't consider adding anything bigger than this to the hpack table */
#define MAX_DECODER_SPACE_USAGE 512
static grpc_slice_refcount terminal_slice_refcount = {nullptr, nullptr};
static grpc_slice_refcount terminal_slice_refcount;
static const grpc_slice terminal_slice = {
&terminal_slice_refcount, /* refcount */
{{0, nullptr}} /* data.refcounted */

@ -163,15 +163,6 @@ static void report_stall(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
}
}
static bool stream_ref_if_not_destroyed(gpr_refcount* r) {
gpr_atm count;
do {
count = gpr_atm_acq_load(&r->count);
if (count == 0) return false;
} while (!gpr_atm_rel_cas(&r->count, count, count + 1));
return true;
}
/* How many bytes would we like to put on the wire during a single syscall */
static uint32_t target_write_size(grpc_chttp2_transport* t) {
return 1024 * 1024;
@ -254,7 +245,7 @@ class WriteContext {
while (grpc_chttp2_list_pop_stalled_by_transport(t_, &s)) {
if (t_->closed_with_error == GRPC_ERROR_NONE &&
grpc_chttp2_list_add_writable_stream(t_, s)) {
if (!stream_ref_if_not_destroyed(&s->refcount->refs)) {
if (!s->refcount->refs.RefIfNonZero()) {
grpc_chttp2_list_remove_writable_stream(t_, s);
}
}

@ -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,
@ -177,7 +176,7 @@ struct op_and_state {
bool done = false;
struct stream_obj* s; /* Pointer back to the stream object */
/* next op_and_state in the linked list */
struct op_and_state* next;
struct op_and_state* next = nullptr;
};
struct op_storage {
@ -324,7 +323,7 @@ static grpc_error* make_error_with_desc(int error_code, const char* desc) {
inline op_and_state::op_and_state(stream_obj* s,
const grpc_transport_stream_op_batch& op)
: op(op), state(s->arena), s(s), next(s->storage.head) {}
: op(op), state(s->arena), s(s) {}
/*
Add a new stream op to op storage.
@ -335,10 +334,8 @@ static void add_to_storage(struct stream_obj* s,
/* add new op at the beginning of the linked list. The memory is freed
in remove_from_storage */
op_and_state* new_op = grpc_core::New<op_and_state>(s, *op);
// Pontential fix to crash on GPR_ASSERT(!curr->done)
// TODO (mxyan): check if this is indeed necessary.
new_op->done = false;
gpr_mu_lock(&s->mu);
new_op->next = storage->head;
storage->head = new_op;
storage->num_pending_ops++;
if (op->send_message) {

@ -1088,10 +1088,8 @@ void perform_stream_op(grpc_transport* gt, grpc_stream* gs,
void close_transport_locked(inproc_transport* t) {
INPROC_LOG(GPR_INFO, "close_transport %p %d", t, t->is_closed);
grpc_connectivity_state_set(
&t->connectivity, GRPC_CHANNEL_SHUTDOWN,
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Closing transport."),
"close transport");
grpc_connectivity_state_set(&t->connectivity, GRPC_CHANNEL_SHUTDOWN,
"close transport");
if (!t->is_closed) {
t->is_closed = true;
/* Also end all streams on this transport */

@ -21,7 +21,6 @@
#include <limits.h>
#include <string.h>
#include <grpc/compression.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
@ -213,106 +212,6 @@ void grpc_channel_args_destroy(grpc_channel_args* a) {
gpr_free(a);
}
grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
const grpc_channel_args* a) {
size_t i;
if (a == nullptr) return GRPC_COMPRESS_NONE;
for (i = 0; i < a->num_args; ++i) {
if (a->args[i].type == GRPC_ARG_INTEGER &&
!strcmp(GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM, a->args[i].key)) {
return static_cast<grpc_compression_algorithm>(a->args[i].value.integer);
break;
}
}
return GRPC_COMPRESS_NONE;
}
grpc_channel_args* grpc_channel_args_set_compression_algorithm(
grpc_channel_args* a, grpc_compression_algorithm algorithm) {
GPR_ASSERT(algorithm < GRPC_COMPRESS_ALGORITHMS_COUNT);
grpc_arg tmp;
tmp.type = GRPC_ARG_INTEGER;
tmp.key = (char*)GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM;
tmp.value.integer = algorithm;
return grpc_channel_args_copy_and_add(a, &tmp, 1);
}
/** Returns 1 if the argument for compression algorithm's enabled states bitset
* was found in \a a, returning the arg's value in \a states. Otherwise, returns
* 0. */
static int find_compression_algorithm_states_bitset(const grpc_channel_args* a,
int** states_arg) {
if (a != nullptr) {
size_t i;
for (i = 0; i < a->num_args; ++i) {
if (a->args[i].type == GRPC_ARG_INTEGER &&
!strcmp(GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET,
a->args[i].key)) {
*states_arg = &a->args[i].value.integer;
**states_arg |= 0x1; /* forcefully enable support for no compression */
return 1;
}
}
}
return 0; /* GPR_FALSE */
}
grpc_channel_args* grpc_channel_args_compression_algorithm_set_state(
grpc_channel_args** a, grpc_compression_algorithm algorithm, int state) {
int* states_arg = nullptr;
grpc_channel_args* result = *a;
const int states_arg_found =
find_compression_algorithm_states_bitset(*a, &states_arg);
if (grpc_channel_args_get_compression_algorithm(*a) == algorithm &&
state == 0) {
const char* algo_name = nullptr;
GPR_ASSERT(grpc_compression_algorithm_name(algorithm, &algo_name) != 0);
gpr_log(GPR_ERROR,
"Tried to disable default compression algorithm '%s'. The "
"operation has been ignored.",
algo_name);
} else if (states_arg_found) {
if (state != 0) {
GPR_BITSET((unsigned*)states_arg, algorithm);
} else if (algorithm != GRPC_COMPRESS_NONE) {
GPR_BITCLEAR((unsigned*)states_arg, algorithm);
}
} else {
/* create a new arg */
grpc_arg tmp;
tmp.type = GRPC_ARG_INTEGER;
tmp.key = (char*)GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET;
/* all enabled by default */
tmp.value.integer = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1;
if (state != 0) {
GPR_BITSET((unsigned*)&tmp.value.integer, algorithm);
} else if (algorithm != GRPC_COMPRESS_NONE) {
GPR_BITCLEAR((unsigned*)&tmp.value.integer, algorithm);
}
result = grpc_channel_args_copy_and_add(*a, &tmp, 1);
grpc_channel_args_destroy(*a);
*a = result;
}
return result;
}
uint32_t grpc_channel_args_compression_algorithm_get_states(
const grpc_channel_args* a) {
int* states_arg;
if (find_compression_algorithm_states_bitset(a, &states_arg)) {
return static_cast<uint32_t>(*states_arg);
} else {
return (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1; /* All algs. enabled */
}
}
grpc_channel_args* grpc_channel_args_set_socket_mutator(
grpc_channel_args* a, grpc_socket_mutator* mutator) {
grpc_arg tmp = grpc_socket_mutator_to_arg(mutator);
return grpc_channel_args_copy_and_add(a, &tmp, 1);
}
int grpc_channel_args_compare(const grpc_channel_args* a,
const grpc_channel_args* b) {
int c = GPR_ICMP(a->num_args, b->num_args);

@ -21,9 +21,7 @@
#include <grpc/support/port_platform.h>
#include <grpc/compression.h>
#include <grpc/grpc.h>
#include "src/core/lib/iomgr/socket_mutator.h"
// Channel args are intentionally immutable, to avoid the need for locking.
@ -60,44 +58,9 @@ inline void grpc_channel_args_destroy(const grpc_channel_args* a) {
grpc_channel_args_destroy(const_cast<grpc_channel_args*>(a));
}
/** Returns the compression algorithm set in \a a. */
grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
const grpc_channel_args* a);
/** Returns a channel arg instance with compression enabled. If \a a is
* non-NULL, its args are copied. N.B. GRPC_COMPRESS_NONE disables compression
* for the channel. */
grpc_channel_args* grpc_channel_args_set_compression_algorithm(
grpc_channel_args* a, grpc_compression_algorithm algorithm);
/** Sets the support for the given compression algorithm. By default, all
* compression algorithms are enabled. It's an error to disable an algorithm set
* by grpc_channel_args_set_compression_algorithm.
*
* Returns an instance with the updated algorithm states. The \a a pointer is
* modified to point to the returned instance (which may be different from the
* input value of \a a). */
grpc_channel_args* grpc_channel_args_compression_algorithm_set_state(
grpc_channel_args** a, grpc_compression_algorithm algorithm, int enabled);
/** Returns the bitset representing the support state (true for enabled, false
* for disabled) for compression algorithms.
*
* The i-th bit of the returned bitset corresponds to the i-th entry in the
* grpc_compression_algorithm enum. */
uint32_t grpc_channel_args_compression_algorithm_get_states(
const grpc_channel_args* a);
int grpc_channel_args_compare(const grpc_channel_args* a,
const grpc_channel_args* b);
/** Returns a channel arg instance with socket mutator added. The socket mutator
* will perform its mutate_fd method on all file descriptors used by the
* channel.
* If \a a is non-MULL, its args are copied. */
grpc_channel_args* grpc_channel_args_set_socket_mutator(
grpc_channel_args* a, grpc_socket_mutator* mutator);
/** Returns the value of argument \a name from \a args, or NULL if not found. */
const grpc_arg* grpc_channel_args_find(const grpc_channel_args* args,
const char* name);

@ -0,0 +1,127 @@
/*
*
* 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 <grpc/support/port_platform.h>
#include <limits.h>
#include <string.h>
#include <grpc/compression.h>
#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/compression/compression_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
const grpc_channel_args* a) {
size_t i;
if (a == nullptr) return GRPC_COMPRESS_NONE;
for (i = 0; i < a->num_args; ++i) {
if (a->args[i].type == GRPC_ARG_INTEGER &&
!strcmp(GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM, a->args[i].key)) {
return static_cast<grpc_compression_algorithm>(a->args[i].value.integer);
break;
}
}
return GRPC_COMPRESS_NONE;
}
grpc_channel_args* grpc_channel_args_set_compression_algorithm(
grpc_channel_args* a, grpc_compression_algorithm algorithm) {
GPR_ASSERT(algorithm < GRPC_COMPRESS_ALGORITHMS_COUNT);
grpc_arg tmp;
tmp.type = GRPC_ARG_INTEGER;
tmp.key = (char*)GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM;
tmp.value.integer = algorithm;
return grpc_channel_args_copy_and_add(a, &tmp, 1);
}
/** Returns 1 if the argument for compression algorithm's enabled states bitset
* was found in \a a, returning the arg's value in \a states. Otherwise, returns
* 0. */
static int find_compression_algorithm_states_bitset(const grpc_channel_args* a,
int** states_arg) {
if (a != nullptr) {
size_t i;
for (i = 0; i < a->num_args; ++i) {
if (a->args[i].type == GRPC_ARG_INTEGER &&
!strcmp(GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET,
a->args[i].key)) {
*states_arg = &a->args[i].value.integer;
**states_arg |= 0x1; /* forcefully enable support for no compression */
return 1;
}
}
}
return 0; /* GPR_FALSE */
}
grpc_channel_args* grpc_channel_args_compression_algorithm_set_state(
grpc_channel_args** a, grpc_compression_algorithm algorithm, int state) {
int* states_arg = nullptr;
grpc_channel_args* result = *a;
const int states_arg_found =
find_compression_algorithm_states_bitset(*a, &states_arg);
if (grpc_channel_args_get_compression_algorithm(*a) == algorithm &&
state == 0) {
const char* algo_name = nullptr;
GPR_ASSERT(grpc_compression_algorithm_name(algorithm, &algo_name) != 0);
gpr_log(GPR_ERROR,
"Tried to disable default compression algorithm '%s'. The "
"operation has been ignored.",
algo_name);
} else if (states_arg_found) {
if (state != 0) {
GPR_BITSET((unsigned*)states_arg, algorithm);
} else if (algorithm != GRPC_COMPRESS_NONE) {
GPR_BITCLEAR((unsigned*)states_arg, algorithm);
}
} else {
/* create a new arg */
grpc_arg tmp;
tmp.type = GRPC_ARG_INTEGER;
tmp.key = (char*)GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET;
/* all enabled by default */
tmp.value.integer = (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1;
if (state != 0) {
GPR_BITSET((unsigned*)&tmp.value.integer, algorithm);
} else if (algorithm != GRPC_COMPRESS_NONE) {
GPR_BITCLEAR((unsigned*)&tmp.value.integer, algorithm);
}
result = grpc_channel_args_copy_and_add(*a, &tmp, 1);
grpc_channel_args_destroy(*a);
*a = result;
}
return result;
}
uint32_t grpc_channel_args_compression_algorithm_get_states(
const grpc_channel_args* a) {
int* states_arg;
if (find_compression_algorithm_states_bitset(a, &states_arg)) {
return static_cast<uint32_t>(*states_arg);
} else {
return (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1; /* All algs. enabled */
}
}

@ -0,0 +1,55 @@
/*
*
* 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_CORE_LIB_COMPRESSION_COMPRESSION_ARGS_H
#define GRPC_CORE_LIB_COMPRESSION_COMPRESSION_ARGS_H
#include <grpc/support/port_platform.h>
#include <grpc/compression.h>
#include <grpc/impl/codegen/grpc_types.h>
/** Returns the compression algorithm set in \a a. */
grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
const grpc_channel_args* a);
/** Returns a channel arg instance with compression enabled. If \a a is
* non-NULL, its args are copied. N.B. GRPC_COMPRESS_NONE disables compression
* for the channel. */
grpc_channel_args* grpc_channel_args_set_compression_algorithm(
grpc_channel_args* a, grpc_compression_algorithm algorithm);
/** Sets the support for the given compression algorithm. By default, all
* compression algorithms are enabled. It's an error to disable an algorithm set
* by grpc_channel_args_set_compression_algorithm.
*
* Returns an instance with the updated algorithm states. The \a a pointer is
* modified to point to the returned instance (which may be different from the
* input value of \a a). */
grpc_channel_args* grpc_channel_args_compression_algorithm_set_state(
grpc_channel_args** a, grpc_compression_algorithm algorithm, int state);
/** Returns the bitset representing the support state (true for enabled, false
* for disabled) for compression algorithms.
*
* The i-th bit of the returned bitset corresponds to the i-th entry in the
* grpc_compression_algorithm enum. */
uint32_t grpc_channel_args_compression_algorithm_get_states(
const grpc_channel_args* a);
#endif /* GRPC_CORE_LIB_COMPRESSION_COMPRESSION_ARGS_H */

@ -29,49 +29,10 @@
#include <grpc/support/sync.h>
#include "src/core/lib/gpr/alloc.h"
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gprpp/memory.h"
namespace {
enum init_strategy {
NO_INIT, // Do not initialize the arena blocks.
ZERO_INIT, // Initialize arena blocks with 0.
NON_ZERO_INIT, // Initialize arena blocks with a non-zero value.
};
gpr_once g_init_strategy_once = GPR_ONCE_INIT;
init_strategy g_init_strategy = NO_INIT;
} // namespace
static void set_strategy_from_env() {
char* str = gpr_getenv("GRPC_ARENA_INIT_STRATEGY");
if (str == nullptr) {
g_init_strategy = NO_INIT;
} else if (strcmp(str, "zero_init") == 0) {
g_init_strategy = ZERO_INIT;
} else if (strcmp(str, "non_zero_init") == 0) {
g_init_strategy = NON_ZERO_INIT;
} else {
g_init_strategy = NO_INIT;
}
gpr_free(str);
}
static void* gpr_arena_alloc_maybe_init(size_t size) {
void* mem = gpr_malloc_aligned(size, GPR_MAX_ALIGNMENT);
gpr_once_init(&g_init_strategy_once, set_strategy_from_env);
if (GPR_UNLIKELY(g_init_strategy != NO_INIT)) {
if (g_init_strategy == ZERO_INIT) {
memset(mem, 0, size);
} else { // NON_ZERO_INIT.
memset(mem, 0xFE, size);
}
}
return mem;
}
void gpr_arena_init() {
gpr_once_init(&g_init_strategy_once, set_strategy_from_env);
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
@ -109,8 +70,7 @@ 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_alloc_maybe_init(size);
void* retval = arena->ptrs[arena->num_ptrs++] = gpr_arena_malloc(size);
gpr_mu_unlock(&arena->mu);
return retval;
}
@ -154,7 +114,7 @@ struct gpr_arena {
gpr_arena* gpr_arena_create(size_t initial_size) {
initial_size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(initial_size);
return new (gpr_arena_alloc_maybe_init(
return new (gpr_arena_malloc(
GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena)) + initial_size))
gpr_arena(initial_size);
}
@ -179,7 +139,7 @@ void* gpr_arena_alloc(gpr_arena* arena, size_t size) {
// 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_alloc_maybe_init(
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;

@ -37,7 +37,5 @@ gpr_arena* gpr_arena_create(size_t initial_size);
void* gpr_arena_alloc(gpr_arena* arena, size_t size);
// Destroy an arena, returning the total number of bytes allocated
size_t gpr_arena_destroy(gpr_arena* arena);
// Initializes the Arena component.
void gpr_arena_init();
#endif /* GRPC_CORE_LIB_GPR_ARENA_H */

@ -123,6 +123,22 @@ class RefCount {
RefNonZero();
}
bool RefIfNonZero() { return value_.IncrementIfNonzero(); }
bool RefIfNonZero(const DebugLocation& location, const char* reason) {
#ifndef NDEBUG
if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
const RefCount::Value old_refs = get();
gpr_log(GPR_INFO,
"%s:%p %s:%d ref_if_non_zero "
"%" PRIdPTR " -> %" PRIdPTR " %s",
trace_flag_->name(), this, location.file(), location.line(),
old_refs, old_refs + 1, reason);
}
#endif
return RefIfNonZero();
}
// Decrements the ref-count and returns true if the ref-count reaches 0.
bool Unref() {
const Value prior = value_.FetchSub(1, MemoryOrder::ACQ_REL);

@ -37,8 +37,8 @@ class CFStreamHandle final {
static CFStreamHandle* CreateStreamHandle(CFReadStreamRef read_stream,
CFWriteStreamRef write_stream);
~CFStreamHandle();
CFStreamHandle(const CFReadStreamRef& ref) = delete;
CFStreamHandle(CFReadStreamRef&& ref) = delete;
CFStreamHandle(const CFStreamHandle& ref) = delete;
CFStreamHandle(CFStreamHandle&& ref) = delete;
CFStreamHandle& operator=(const CFStreamHandle& rhs) = delete;
void NotifyOnOpen(grpc_closure* closure);

@ -213,7 +213,7 @@ struct grpc_pollset {
poll */
bool seen_inactive;
bool shutting_down; /* Is the pollset shutting down ? */
grpc_closure* shutdown_closure; /* Called after after shutdown is complete */
grpc_closure* shutdown_closure; /* Called after shutdown is complete */
/* Number of workers who are *about-to* attach themselves to the pollset
* worker list */

@ -49,6 +49,8 @@ static bool iomgr_platform_add_closure_to_background_poller(
return false;
}
bool g_custom_iomgr_enabled = false;
static grpc_iomgr_platform_vtable vtable = {
iomgr_platform_init,
iomgr_platform_flush,
@ -61,6 +63,7 @@ void grpc_custom_iomgr_init(grpc_socket_vtable* socket,
grpc_custom_resolver_vtable* resolver,
grpc_custom_timer_vtable* timer,
grpc_custom_poller_vtable* poller) {
g_custom_iomgr_enabled = true;
grpc_custom_endpoint_init(socket);
grpc_custom_timer_init(timer);
grpc_custom_pollset_init(poller);

@ -39,6 +39,8 @@ extern gpr_thd_id g_init_thread;
#define GRPC_CUSTOM_IOMGR_ASSERT_SAME_THREAD()
#endif /* GRPC_CUSTOM_IOMGR_THREAD_CHECK */
extern bool g_custom_iomgr_enabled;
void grpc_custom_iomgr_init(grpc_socket_vtable* socket,
grpc_custom_resolver_vtable* resolver,
grpc_custom_timer_vtable* timer,

@ -88,6 +88,15 @@
#ifdef LINUX_VERSION_CODE
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
#define GRPC_HAVE_TCP_USER_TIMEOUT
#ifdef __GLIBC_PREREQ
#if !(__GLIBC_PREREQ(2, 17))
/*
* TCP_USER_TIMEOUT wasn't imported to glibc until 2.17. Use Linux system
* header instead.
*/
#define GRPC_LINUX_TCP_H 1
#endif /* __GLIBC_PREREQ(2, 17) */
#endif /* ifdef __GLIBC_PREREQ */
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) */
#endif /* LINUX_VERSION_CODE */
#ifndef __GLIBC__

@ -32,6 +32,7 @@
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/slice/slice_internal.h"
grpc_core::TraceFlag grpc_resource_quota_trace(false, "resource_quota");
@ -430,41 +431,43 @@ static bool rq_reclaim(grpc_resource_quota* resource_quota, bool destructive) {
* ru_slice: a slice implementation that is backed by a grpc_resource_user
*/
typedef struct {
grpc_slice_refcount base;
gpr_refcount refs;
grpc_resource_user* resource_user;
size_t size;
} ru_slice_refcount;
namespace grpc_core {
static void ru_slice_ref(void* p) {
ru_slice_refcount* rc = static_cast<ru_slice_refcount*>(p);
gpr_ref(&rc->refs);
}
static void ru_slice_unref(void* p) {
ru_slice_refcount* rc = static_cast<ru_slice_refcount*>(p);
if (gpr_unref(&rc->refs)) {
grpc_resource_user_free(rc->resource_user, rc->size);
class RuSliceRefcount {
public:
static void Destroy(void* p) {
auto* rc = static_cast<RuSliceRefcount*>(p);
rc->~RuSliceRefcount();
gpr_free(rc);
}
}
RuSliceRefcount(grpc_resource_user* resource_user, size_t size)
: base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
&base_),
resource_user_(resource_user),
size_(size) {
// Nothing to do here.
}
~RuSliceRefcount() { grpc_resource_user_free(resource_user_, size_); }
grpc_slice_refcount* base_refcount() { return &base_; }
static const grpc_slice_refcount_vtable ru_slice_vtable = {
ru_slice_ref, ru_slice_unref, grpc_slice_default_eq_impl,
grpc_slice_default_hash_impl};
private:
grpc_slice_refcount base_;
RefCount refs_;
grpc_resource_user* resource_user_;
size_t size_;
};
} // namespace grpc_core
static grpc_slice ru_slice_create(grpc_resource_user* resource_user,
size_t size) {
ru_slice_refcount* rc = static_cast<ru_slice_refcount*>(
gpr_malloc(sizeof(ru_slice_refcount) + size));
rc->base.vtable = &ru_slice_vtable;
rc->base.sub_refcount = &rc->base;
gpr_ref_init(&rc->refs, 1);
rc->resource_user = resource_user;
rc->size = size;
auto* rc = static_cast<grpc_core::RuSliceRefcount*>(
gpr_malloc(sizeof(grpc_core::RuSliceRefcount) + size));
new (rc) grpc_core::RuSliceRefcount(resource_user, size);
grpc_slice slice;
slice.refcount = &rc->base;
slice.refcount = rc->base_refcount();
slice.data.refcounted.bytes = reinterpret_cast<uint8_t*>(rc + 1);
slice.data.refcounted.length = size;
return slice;

@ -30,7 +30,11 @@
#include <fcntl.h>
#include <limits.h>
#include <netinet/in.h>
#ifdef GRPC_LINUX_TCP_H
#include <linux/tcp.h>
#else
#include <netinet/tcp.h>
#endif
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>

@ -314,7 +314,6 @@ class grpc_ssl_server_security_connector
bool try_fetch_ssl_server_credentials() {
grpc_ssl_server_certificate_config* certificate_config = nullptr;
bool status;
if (!has_cert_config_fetcher()) return false;
grpc_ssl_server_credentials* server_creds =
@ -374,7 +373,9 @@ class grpc_ssl_server_security_connector
options.num_alpn_protocols = static_cast<uint16_t>(num_alpn_protocols);
tsi_result result = tsi_create_ssl_server_handshaker_factory_with_options(
&options, &new_handshaker_factory);
gpr_free((void*)options.pem_key_cert_pairs);
grpc_tsi_ssl_pem_key_cert_pairs_destroy(
const_cast<tsi_ssl_pem_key_cert_pair*>(options.pem_key_cert_pairs),
options.num_key_cert_pairs);
gpr_free((void*)alpn_protocol_strings);
if (result != TSI_OK) {

@ -26,6 +26,7 @@
#include <string.h>
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/iomgr/exec_ctx.h"
@ -67,17 +68,10 @@ void grpc_slice_unref(grpc_slice slice) {
/* grpc_slice_from_static_string support structure - a refcount that does
nothing */
static void noop_ref(void* unused) {}
static void noop_unref(void* unused) {}
static const grpc_slice_refcount_vtable noop_refcount_vtable = {
noop_ref, noop_unref, grpc_slice_default_eq_impl,
grpc_slice_default_hash_impl};
static grpc_slice_refcount noop_refcount = {&noop_refcount_vtable,
&noop_refcount};
static grpc_slice_refcount NoopRefcount;
size_t grpc_slice_memory_usage(grpc_slice s) {
if (s.refcount == nullptr || s.refcount == &noop_refcount) {
if (s.refcount == nullptr || s.refcount == &NoopRefcount) {
return 0;
} else {
return s.data.refcounted.length;
@ -86,7 +80,7 @@ size_t grpc_slice_memory_usage(grpc_slice s) {
grpc_slice grpc_slice_from_static_buffer(const void* s, size_t len) {
grpc_slice slice;
slice.refcount = &noop_refcount;
slice.refcount = &NoopRefcount;
slice.data.refcounted.bytes = (uint8_t*)s;
slice.data.refcounted.length = len;
return slice;
@ -96,45 +90,43 @@ grpc_slice grpc_slice_from_static_string(const char* s) {
return grpc_slice_from_static_buffer(s, strlen(s));
}
namespace grpc_core {
/* grpc_slice_new support structures - we create a refcount object extended
with the user provided data pointer & destroy function */
typedef struct new_slice_refcount {
grpc_slice_refcount rc;
gpr_refcount refs;
void (*user_destroy)(void*);
void* user_data;
} new_slice_refcount;
static void new_slice_ref(void* p) {
new_slice_refcount* r = static_cast<new_slice_refcount*>(p);
gpr_ref(&r->refs);
}
static void new_slice_unref(void* p) {
new_slice_refcount* r = static_cast<new_slice_refcount*>(p);
if (gpr_unref(&r->refs)) {
r->user_destroy(r->user_data);
gpr_free(r);
class NewSliceRefcount {
public:
static void Destroy(void* arg) {
Delete(static_cast<NewSliceRefcount*>(arg));
}
}
static const grpc_slice_refcount_vtable new_slice_vtable = {
new_slice_ref, new_slice_unref, grpc_slice_default_eq_impl,
grpc_slice_default_hash_impl};
NewSliceRefcount(void (*destroy)(void*), void* user_data)
: rc_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this, &rc_),
user_destroy_(destroy),
user_data_(user_data) {}
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
grpc_slice_refcount* base_refcount() { return &rc_; }
private:
~NewSliceRefcount() { user_destroy_(user_data_); }
grpc_slice_refcount rc_;
RefCount refs_;
void (*user_destroy_)(void*);
void* user_data_;
};
} // namespace grpc_core
grpc_slice grpc_slice_new_with_user_data(void* p, size_t len,
void (*destroy)(void*),
void* user_data) {
grpc_slice slice;
new_slice_refcount* rc =
static_cast<new_slice_refcount*>(gpr_malloc(sizeof(new_slice_refcount)));
gpr_ref_init(&rc->refs, 1);
rc->rc.vtable = &new_slice_vtable;
rc->rc.sub_refcount = &rc->rc;
rc->user_destroy = destroy;
rc->user_data = user_data;
slice.refcount = &rc->rc;
slice.refcount =
grpc_core::New<grpc_core::NewSliceRefcount>(destroy, user_data)
->base_refcount();
slice.data.refcounted.bytes = static_cast<uint8_t*>(p);
slice.data.refcounted.length = len;
return slice;
@ -145,46 +137,45 @@ grpc_slice grpc_slice_new(void* p, size_t len, void (*destroy)(void*)) {
return grpc_slice_new_with_user_data(p, len, destroy, p);
}
namespace grpc_core {
/* grpc_slice_new_with_len support structures - we create a refcount object
extended with the user provided data pointer & destroy function */
typedef struct new_with_len_slice_refcount {
grpc_slice_refcount rc;
gpr_refcount refs;
void* user_data;
size_t user_length;
void (*user_destroy)(void*, size_t);
} new_with_len_slice_refcount;
static void new_with_len_ref(void* p) {
new_with_len_slice_refcount* r = static_cast<new_with_len_slice_refcount*>(p);
gpr_ref(&r->refs);
}
static void new_with_len_unref(void* p) {
new_with_len_slice_refcount* r = static_cast<new_with_len_slice_refcount*>(p);
if (gpr_unref(&r->refs)) {
r->user_destroy(r->user_data, r->user_length);
gpr_free(r);
class NewWithLenSliceRefcount {
public:
static void Destroy(void* arg) {
Delete(static_cast<NewWithLenSliceRefcount*>(arg));
}
}
static const grpc_slice_refcount_vtable new_with_len_vtable = {
new_with_len_ref, new_with_len_unref, grpc_slice_default_eq_impl,
grpc_slice_default_hash_impl};
NewWithLenSliceRefcount(void (*destroy)(void*, size_t), void* user_data,
size_t user_length)
: rc_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this, &rc_),
user_data_(user_data),
user_length_(user_length),
user_destroy_(destroy) {}
GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
grpc_slice_refcount* base_refcount() { return &rc_; }
private:
~NewWithLenSliceRefcount() { user_destroy_(user_data_, user_length_); }
grpc_slice_refcount rc_;
RefCount refs_;
void* user_data_;
size_t user_length_;
void (*user_destroy_)(void*, size_t);
};
} // namespace grpc_core
grpc_slice grpc_slice_new_with_len(void* p, size_t len,
void (*destroy)(void*, size_t)) {
grpc_slice slice;
new_with_len_slice_refcount* rc = static_cast<new_with_len_slice_refcount*>(
gpr_malloc(sizeof(new_with_len_slice_refcount)));
gpr_ref_init(&rc->refs, 1);
rc->rc.vtable = &new_with_len_vtable;
rc->rc.sub_refcount = &rc->rc;
rc->user_destroy = destroy;
rc->user_data = p;
rc->user_length = len;
slice.refcount = &rc->rc;
slice.refcount =
grpc_core::New<grpc_core::NewWithLenSliceRefcount>(destroy, p, len)
->base_refcount();
slice.data.refcounted.bytes = static_cast<uint8_t*>(p);
slice.data.refcounted.length = len;
return slice;
@ -203,39 +194,28 @@ grpc_slice grpc_slice_from_copied_string(const char* source) {
namespace {
struct MallocRefCount {
MallocRefCount(const grpc_slice_refcount_vtable* vtable) {
base.vtable = vtable;
base.sub_refcount = &base;
class MallocRefCount {
public:
static void Destroy(void* arg) {
MallocRefCount* r = static_cast<MallocRefCount*>(arg);
r->~MallocRefCount();
gpr_free(r);
}
void Ref() { refs.Ref(); }
void Unref() {
if (refs.Unref()) {
gpr_free(this);
}
}
MallocRefCount()
: base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
&base_) {}
~MallocRefCount() = default;
grpc_slice_refcount* base_refcount() { return &base_; }
grpc_slice_refcount base;
grpc_core::RefCount refs;
private:
grpc_slice_refcount base_;
grpc_core::RefCount refs_;
};
} // namespace
static void malloc_ref(void* p) {
MallocRefCount* r = static_cast<MallocRefCount*>(p);
r->Ref();
}
static void malloc_unref(void* p) {
MallocRefCount* r = static_cast<MallocRefCount*>(p);
r->Unref();
}
static const grpc_slice_refcount_vtable malloc_vtable = {
malloc_ref, malloc_unref, grpc_slice_default_eq_impl,
grpc_slice_default_hash_impl};
grpc_slice grpc_slice_malloc_large(size_t length) {
grpc_slice slice;
@ -248,14 +228,16 @@ grpc_slice grpc_slice_malloc_large(size_t length) {
refcount is a malloc_refcount
bytes is an array of bytes of the requested length
Both parts are placed in the same allocation returned from gpr_malloc */
void* data =
auto* rc =
static_cast<MallocRefCount*>(gpr_malloc(sizeof(MallocRefCount) + length));
auto* rc = new (data) MallocRefCount(&malloc_vtable);
/* Initial refcount on rc is 1 - and it's up to the caller to release
this reference. */
new (rc) MallocRefCount();
/* Build up the slice to be returned. */
/* The slices refcount points back to the allocated block. */
slice.refcount = &rc->base;
slice.refcount = rc->base_refcount();
/* The data bytes are placed immediately after the refcount struct */
slice.data.refcounted.bytes = reinterpret_cast<uint8_t*>(rc + 1);
/* And the length of the block is set to the requested length */
@ -286,7 +268,7 @@ grpc_slice grpc_slice_sub_no_ref(grpc_slice source, size_t begin, size_t end) {
GPR_ASSERT(source.data.refcounted.length >= end);
/* Build the result */
subset.refcount = source.refcount->sub_refcount;
subset.refcount = source.refcount->sub_refcount();
/* Point into the source array */
subset.data.refcounted.bytes = source.data.refcounted.bytes + begin;
subset.data.refcounted.length = end - begin;
@ -312,7 +294,7 @@ grpc_slice grpc_slice_sub(grpc_slice source, size_t begin, size_t end) {
} else {
subset = grpc_slice_sub_no_ref(source, begin, end);
/* Bump the refcount */
subset.refcount->vtable->ref(subset.refcount);
subset.refcount->Ref();
}
return subset;
}
@ -340,23 +322,23 @@ grpc_slice grpc_slice_split_tail_maybe_ref(grpc_slice* source, size_t split,
tail.data.inlined.length = static_cast<uint8_t>(tail_length);
memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split,
tail_length);
source->refcount = source->refcount->sub_refcount;
source->refcount = source->refcount->sub_refcount();
} else {
/* Build the result */
switch (ref_whom) {
case GRPC_SLICE_REF_TAIL:
tail.refcount = source->refcount->sub_refcount;
source->refcount = &noop_refcount;
tail.refcount = source->refcount->sub_refcount();
source->refcount = &NoopRefcount;
break;
case GRPC_SLICE_REF_HEAD:
tail.refcount = &noop_refcount;
source->refcount = source->refcount->sub_refcount;
tail.refcount = &NoopRefcount;
source->refcount = source->refcount->sub_refcount();
break;
case GRPC_SLICE_REF_BOTH:
tail.refcount = source->refcount->sub_refcount;
source->refcount = source->refcount->sub_refcount;
tail.refcount = source->refcount->sub_refcount();
source->refcount = source->refcount->sub_refcount();
/* Bump the refcount */
tail.refcount->vtable->ref(tail.refcount);
tail.refcount->Ref();
break;
}
/* Point into the source array */
@ -392,20 +374,20 @@ grpc_slice grpc_slice_split_head(grpc_slice* source, size_t split) {
head.refcount = nullptr;
head.data.inlined.length = static_cast<uint8_t>(split);
memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split);
source->refcount = source->refcount->sub_refcount;
source->refcount = source->refcount->sub_refcount();
source->data.refcounted.bytes += split;
source->data.refcounted.length -= split;
} else {
GPR_ASSERT(source->data.refcounted.length >= split);
/* Build the result */
head.refcount = source->refcount->sub_refcount;
head.refcount = source->refcount->sub_refcount();
/* Bump the refcount */
head.refcount->vtable->ref(head.refcount);
head.refcount->Ref();
/* Point into the source array */
head.data.refcounted.bytes = source->data.refcounted.bytes;
head.data.refcounted.length = split;
source->refcount = source->refcount->sub_refcount;
source->refcount = source->refcount->sub_refcount();
source->data.refcounted.bytes += split;
source->data.refcounted.length -= split;
}
@ -421,8 +403,9 @@ int grpc_slice_default_eq_impl(grpc_slice a, grpc_slice b) {
}
int grpc_slice_eq(grpc_slice a, grpc_slice b) {
if (a.refcount && b.refcount && a.refcount->vtable == b.refcount->vtable) {
return a.refcount->vtable->eq(a, b);
if (a.refcount && b.refcount &&
a.refcount->GetType() == b.refcount->GetType()) {
return a.refcount->Eq(a, b);
}
return grpc_slice_default_eq_impl(a, b);
}

@ -27,6 +27,7 @@
#include <grpc/support/log.h>
#include "src/core/lib/gpr/murmur_hash.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/iomgr/iomgr_internal.h" /* for iomgr_abort_on_leaks() */
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/slice/slice_string_helpers.h"
@ -39,24 +40,17 @@
#define TABLE_IDX(hash, capacity) (((hash) >> LOG2_SHARD_COUNT) % (capacity))
#define SHARD_IDX(hash) ((hash) & ((1 << LOG2_SHARD_COUNT) - 1))
typedef struct interned_slice_refcount {
grpc_slice_refcount base;
grpc_slice_refcount sub;
size_t length;
gpr_atm refcnt;
uint32_t hash;
struct interned_slice_refcount* bucket_next;
} interned_slice_refcount;
using grpc_core::InternedSliceRefcount;
typedef struct slice_shard {
gpr_mu mu;
interned_slice_refcount** strs;
InternedSliceRefcount** strs;
size_t count;
size_t capacity;
} slice_shard;
/* hash seed: decided at initialization time */
static uint32_t g_hash_seed;
uint32_t g_hash_seed;
static int g_forced_hash_seed = 0;
static slice_shard g_shards[SHARD_COUNT];
@ -69,73 +63,35 @@ typedef struct {
static static_metadata_hash_ent
static_metadata_hash[4 * GRPC_STATIC_MDSTR_COUNT];
static uint32_t max_static_metadata_hash_probe;
static uint32_t static_metadata_hash_values[GRPC_STATIC_MDSTR_COUNT];
uint32_t grpc_static_metadata_hash_values[GRPC_STATIC_MDSTR_COUNT];
static void interned_slice_ref(void* p) {
interned_slice_refcount* s = static_cast<interned_slice_refcount*>(p);
GPR_ASSERT(gpr_atm_no_barrier_fetch_add(&s->refcnt, 1) > 0);
}
namespace grpc_core {
static void interned_slice_destroy(interned_slice_refcount* s) {
slice_shard* shard = &g_shards[SHARD_IDX(s->hash)];
gpr_mu_lock(&shard->mu);
GPR_ASSERT(0 == gpr_atm_no_barrier_load(&s->refcnt));
interned_slice_refcount** prev_next;
interned_slice_refcount* cur;
for (prev_next = &shard->strs[TABLE_IDX(s->hash, shard->capacity)],
InternedSliceRefcount::~InternedSliceRefcount() {
slice_shard* shard = &g_shards[SHARD_IDX(this->hash)];
MutexLock lock(&shard->mu);
InternedSliceRefcount** prev_next;
InternedSliceRefcount* cur;
for (prev_next = &shard->strs[TABLE_IDX(this->hash, shard->capacity)],
cur = *prev_next;
cur != s; prev_next = &cur->bucket_next, cur = cur->bucket_next)
cur != this; prev_next = &cur->bucket_next, cur = cur->bucket_next)
;
*prev_next = cur->bucket_next;
shard->count--;
gpr_free(s);
gpr_mu_unlock(&shard->mu);
}
static void interned_slice_unref(void* p) {
interned_slice_refcount* s = static_cast<interned_slice_refcount*>(p);
if (1 == gpr_atm_full_fetch_add(&s->refcnt, -1)) {
interned_slice_destroy(s);
}
}
static void interned_slice_sub_ref(void* p) {
interned_slice_ref((static_cast<char*>(p)) -
offsetof(interned_slice_refcount, sub));
}
static void interned_slice_sub_unref(void* p) {
interned_slice_unref((static_cast<char*>(p)) -
offsetof(interned_slice_refcount, sub));
}
static uint32_t interned_slice_hash(grpc_slice slice) {
interned_slice_refcount* s =
reinterpret_cast<interned_slice_refcount*>(slice.refcount);
return s->hash;
}
static int interned_slice_eq(grpc_slice a, grpc_slice b) {
return a.refcount == b.refcount;
}
static const grpc_slice_refcount_vtable interned_slice_vtable = {
interned_slice_ref, interned_slice_unref, interned_slice_eq,
interned_slice_hash};
static const grpc_slice_refcount_vtable interned_slice_sub_vtable = {
interned_slice_sub_ref, interned_slice_sub_unref,
grpc_slice_default_eq_impl, grpc_slice_default_hash_impl};
} // namespace grpc_core
static void grow_shard(slice_shard* shard) {
GPR_TIMER_SCOPE("grow_strtab", 0);
size_t capacity = shard->capacity * 2;
size_t i;
interned_slice_refcount** strtab;
interned_slice_refcount *s, *next;
InternedSliceRefcount** strtab;
InternedSliceRefcount *s, *next;
strtab = static_cast<interned_slice_refcount**>(
gpr_zalloc(sizeof(interned_slice_refcount*) * capacity));
strtab = static_cast<InternedSliceRefcount**>(
gpr_zalloc(sizeof(InternedSliceRefcount*) * capacity));
for (i = 0; i < shard->capacity; i++) {
for (s = shard->strs[i]; s; s = next) {
@ -150,7 +106,7 @@ static void grow_shard(slice_shard* shard) {
shard->capacity = capacity;
}
static grpc_slice materialize(interned_slice_refcount* s) {
static grpc_slice materialize(InternedSliceRefcount* s) {
grpc_slice slice;
slice.refcount = &s->base;
slice.data.refcounted.bytes = reinterpret_cast<uint8_t*>(s + 1);
@ -164,7 +120,7 @@ uint32_t grpc_slice_default_hash_impl(grpc_slice s) {
}
uint32_t grpc_static_slice_hash(grpc_slice s) {
return static_metadata_hash_values[GRPC_STATIC_METADATA_INDEX(s)];
return grpc_static_metadata_hash_values[GRPC_STATIC_METADATA_INDEX(s)];
}
int grpc_static_slice_eq(grpc_slice a, grpc_slice b) {
@ -173,7 +129,7 @@ int grpc_static_slice_eq(grpc_slice a, grpc_slice b) {
uint32_t grpc_slice_hash(grpc_slice s) {
return s.refcount == nullptr ? grpc_slice_default_hash_impl(s)
: s.refcount->vtable->hash(s);
: s.refcount->Hash(s);
}
grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
@ -197,8 +153,9 @@ grpc_slice grpc_slice_maybe_static_intern(grpc_slice slice,
}
bool grpc_slice_is_interned(const grpc_slice& slice) {
return (slice.refcount && slice.refcount->vtable == &interned_slice_vtable) ||
GRPC_IS_STATIC_METADATA_STRING(slice);
return (slice.refcount &&
(slice.refcount->GetType() == grpc_slice_refcount::Type::INTERNED ||
GRPC_IS_STATIC_METADATA_STRING(slice)));
}
grpc_slice grpc_slice_intern(grpc_slice slice) {
@ -208,6 +165,7 @@ grpc_slice grpc_slice_intern(grpc_slice slice) {
}
uint32_t hash = grpc_slice_hash(slice);
for (uint32_t i = 0; i <= max_static_metadata_hash_probe; i++) {
static_metadata_hash_ent ent =
static_metadata_hash[(hash + i) % GPR_ARRAY_SIZE(static_metadata_hash)];
@ -217,7 +175,7 @@ grpc_slice grpc_slice_intern(grpc_slice slice) {
}
}
interned_slice_refcount* s;
InternedSliceRefcount* s;
slice_shard* shard = &g_shards[SHARD_IDX(hash)];
gpr_mu_lock(&shard->mu);
@ -226,14 +184,7 @@ grpc_slice grpc_slice_intern(grpc_slice slice) {
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 (gpr_atm_no_barrier_fetch_add(&s->refcnt, 1) == 0) {
/* If we get here, we've added a ref to something that was about to
* die - drop it immediately.
* The *only* possible path here (given the shard mutex) should be to
* drop from one ref back to zero - assert that with a CAS */
GPR_ASSERT(gpr_atm_rel_cas(&s->refcnt, 1, 0));
/* and treat this as if we were never here... sshhh */
} else {
if (s->refcnt.RefIfNonZero()) {
gpr_mu_unlock(&shard->mu);
return materialize(s);
}
@ -242,27 +193,20 @@ grpc_slice grpc_slice_intern(grpc_slice slice) {
/* not found: create a new string */
/* string data goes after the internal_string header */
s = static_cast<interned_slice_refcount*>(
s = static_cast<InternedSliceRefcount*>(
gpr_malloc(sizeof(*s) + GRPC_SLICE_LENGTH(slice)));
gpr_atm_rel_store(&s->refcnt, 1);
s->length = GRPC_SLICE_LENGTH(slice);
s->hash = hash;
s->base.vtable = &interned_slice_vtable;
s->base.sub_refcount = &s->sub;
s->sub.vtable = &interned_slice_sub_vtable;
s->sub.sub_refcount = &s->sub;
s->bucket_next = shard->strs[idx];
shard->strs[idx] = s;
memcpy(s + 1, GRPC_SLICE_START_PTR(slice), GRPC_SLICE_LENGTH(slice));
new (s) grpc_core::InternedSliceRefcount(GRPC_SLICE_LENGTH(slice), hash,
shard->strs[idx]);
memcpy(reinterpret_cast<char*>(s + 1), GRPC_SLICE_START_PTR(slice),
GRPC_SLICE_LENGTH(slice));
shard->strs[idx] = s;
shard->count++;
if (shard->count > shard->capacity * 2) {
grow_shard(shard);
}
gpr_mu_unlock(&shard->mu);
return materialize(s);
}
@ -280,7 +224,7 @@ void grpc_slice_intern_init(void) {
gpr_mu_init(&shard->mu);
shard->count = 0;
shard->capacity = INITIAL_SHARD_CAPACITY;
shard->strs = static_cast<interned_slice_refcount**>(
shard->strs = static_cast<InternedSliceRefcount**>(
gpr_zalloc(sizeof(*shard->strs) * shard->capacity));
}
for (size_t i = 0; i < GPR_ARRAY_SIZE(static_metadata_hash); i++) {
@ -289,13 +233,13 @@ void grpc_slice_intern_init(void) {
}
max_static_metadata_hash_probe = 0;
for (size_t i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) {
static_metadata_hash_values[i] =
grpc_static_metadata_hash_values[i] =
grpc_slice_default_hash_impl(grpc_static_slice_table[i]);
for (size_t j = 0; j < GPR_ARRAY_SIZE(static_metadata_hash); j++) {
size_t slot = (static_metadata_hash_values[i] + j) %
size_t slot = (grpc_static_metadata_hash_values[i] + j) %
GPR_ARRAY_SIZE(static_metadata_hash);
if (static_metadata_hash[slot].idx == GRPC_STATIC_MDSTR_COUNT) {
static_metadata_hash[slot].hash = static_metadata_hash_values[i];
static_metadata_hash[slot].hash = grpc_static_metadata_hash_values[i];
static_metadata_hash[slot].idx = static_cast<uint32_t>(i);
if (j > max_static_metadata_hash_probe) {
max_static_metadata_hash_probe = static_cast<uint32_t>(j);
@ -315,8 +259,7 @@ void grpc_slice_intern_shutdown(void) {
gpr_log(GPR_DEBUG, "WARNING: %" PRIuPTR " metadata strings were leaked",
shard->count);
for (size_t j = 0; j < shard->capacity; j++) {
for (interned_slice_refcount* s = shard->strs[j]; s;
s = s->bucket_next) {
for (InternedSliceRefcount* s = shard->strs[j]; s; s = s->bucket_next) {
char* text =
grpc_dump_slice(materialize(s), GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_DEBUG, "LEAKED: %s", text);

@ -23,17 +23,215 @@
#include <grpc/slice.h>
#include <grpc/slice_buffer.h>
#include <string.h>
inline const grpc_slice& grpc_slice_ref_internal(const grpc_slice& slice) {
#include "src/core/lib/gpr/murmur_hash.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/transport/static_metadata.h"
// Interned slices have specific fast-path operations for hashing. To inline
// these operations, we need to forward declare them here.
extern uint32_t grpc_static_metadata_hash_values[GRPC_STATIC_MDSTR_COUNT];
extern uint32_t g_hash_seed;
// grpc_slice_refcount : A reference count for grpc_slice.
//
// Non-inlined grpc_slice objects are refcounted. Historically this was
// implemented via grpc_slice_refcount, a C-style polymorphic class using a
// manually managed vtable of operations. Subclasses would define their own
// vtable; the 'virtual' methods (ref, unref, equals and hash) would simply call
// the function pointers in the vtable as necessary.
//
// Unfortunately, this leads to some inefficiencies in the generated code that
// can be improved upon. For example, equality checking for interned slices is a
// simple equality check on the refcount pointer. With the vtable approach, this
// would translate to roughly the following (high-level) instructions:
//
// grpc_slice_equals(slice1, slice2):
// load vtable->eq -> eq_func
// call eq_func(slice1, slice2)
//
// interned_slice_equals(slice1, slice2)
// load slice1.ref -> r1
// load slice2.ref -> r2
// cmp r1, r2 -> retval
// ret retval
//
// This leads to a function call for a function defined in another translation
// unit, which imposes memory barriers, which reduces the compiler's ability to
// optimize (in addition to the added overhead of call/ret). Additionally, it
// may be harder to reason about branch prediction when we're jumping to
// essentially arbitrarily provided function pointers.
//
// In addition, it is arguable that while virtualization was helpful for
// Equals()/Hash() methods, that it was fundamentally unnecessary for
// Ref()/Unref().
//
// Instead, grpc_slice_refcount provides the same functionality as the C-style
// virtual class, but in a de-virtualized manner - Eq(), Hash(), Ref() and
// Unref() are provided within this header file. Fastpaths for Eq()/Hash()
// (interned and static metadata slices), as well as the Ref() operation, can
// all be inlined without any memory barriers.
//
// It does this by:
// 1. Using grpc_core::RefCount<> (header-only) for Ref/Unref. Two special cases
// need support: No-op ref/unref (eg. static metadata slices) and stream
// slice references (where all the slices share the streamref). This is in
// addition to the normal case of '1 slice, 1 ref'.
// To support these cases, we explicitly track a nullable pointer to the
// underlying RefCount<>. No-op ref/unref is used by checking the pointer for
// null, and doing nothing if it is. Both stream slice refs and 'normal'
// slices use the same path for Ref/Unref (by targeting the non-null
// pointer).
//
// 2. introducing the notion of grpc_slice_refcount::Type. This describes if a
// slice ref is used by a static metadata slice, an interned slice, or other
// slices. We switch on the slice ref type in order to provide fastpaths for
// Equals() and Hash().
//
// In total, this saves us roughly 1-2% latency for unary calls, with smaller
// calls benefitting. The effect is present, but not as useful, for larger calls
// where the cost of sending the data dominates.
struct grpc_slice_refcount {
public:
enum class Type {
STATIC, // Refcount for a static metadata slice.
INTERNED, // Refcount for an interned slice.
REGULAR // Refcount for non-static-metadata, non-interned slices.
};
typedef void (*DestroyerFn)(void*);
grpc_slice_refcount() = default;
explicit grpc_slice_refcount(grpc_slice_refcount* sub) : sub_refcount_(sub) {}
// Regular constructor for grpc_slice_refcount.
//
// Parameters:
// 1. grpc_slice_refcount::Type type
// Whether we are the refcount for a static
// metadata slice, an interned slice, or any other kind of slice.
//
// 2. RefCount* ref
// The pointer to the actual underlying grpc_core::RefCount. Rather than
// performing struct offset computations as in the original implementation to
// get to the refcount, which requires a virtual method, we devirtualize by
// using a nullable pointer to allow a single pair of Ref/Unref methods.
//
// 3. DestroyerFn destroyer_fn
// Called when the refcount goes to 0, with destroyer_arg as parameter.
//
// 4. void* destroyer_arg
// Argument for the virtualized destructor.
//
// 5. grpc_slice_refcount* sub
// Argument used for interned slices.
grpc_slice_refcount(grpc_slice_refcount::Type type, grpc_core::RefCount* ref,
DestroyerFn destroyer_fn, void* destroyer_arg,
grpc_slice_refcount* sub)
: ref_(ref),
ref_type_(type),
sub_refcount_(sub),
dest_fn_(destroyer_fn),
destroy_fn_arg_(destroyer_arg) {}
// Initializer for static refcounts.
grpc_slice_refcount(grpc_slice_refcount* sub, Type type)
: ref_type_(type), sub_refcount_(sub) {}
Type GetType() const { return ref_type_; }
int Eq(const grpc_slice& a, const grpc_slice& b);
uint32_t Hash(const grpc_slice& slice);
void Ref() {
if (ref_ == nullptr) return;
ref_->RefNonZero();
}
void Unref() {
if (ref_ == nullptr) return;
if (ref_->Unref()) {
dest_fn_(destroy_fn_arg_);
}
}
grpc_slice_refcount* sub_refcount() const { return sub_refcount_; }
private:
grpc_core::RefCount* ref_ = nullptr;
const Type ref_type_ = Type::REGULAR;
grpc_slice_refcount* sub_refcount_ = this;
DestroyerFn dest_fn_ = nullptr;
void* destroy_fn_arg_ = nullptr;
};
namespace grpc_core {
struct InternedSliceRefcount {
static void Destroy(void* arg) {
auto* rc = static_cast<InternedSliceRefcount*>(arg);
rc->~InternedSliceRefcount();
gpr_free(rc);
}
InternedSliceRefcount(size_t length, uint32_t hash,
InternedSliceRefcount* bucket_next)
: base(grpc_slice_refcount::Type::INTERNED, &refcnt, Destroy, this, &sub),
sub(grpc_slice_refcount::Type::REGULAR, &refcnt, Destroy, this, &sub),
length(length),
hash(hash),
bucket_next(bucket_next) {}
~InternedSliceRefcount();
grpc_slice_refcount base;
grpc_slice_refcount sub;
const size_t length;
RefCount refcnt;
const uint32_t hash;
InternedSliceRefcount* bucket_next;
};
} // namespace grpc_core
inline int grpc_slice_refcount::Eq(const grpc_slice& a, const grpc_slice& b) {
switch (ref_type_) {
case Type::STATIC:
return GRPC_STATIC_METADATA_INDEX(a) == GRPC_STATIC_METADATA_INDEX(b);
case Type::INTERNED:
return a.refcount == b.refcount;
case Type::REGULAR:
break;
}
if (GRPC_SLICE_LENGTH(a) != GRPC_SLICE_LENGTH(b)) return false;
if (GRPC_SLICE_LENGTH(a) == 0) return true;
return 0 == memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
GRPC_SLICE_LENGTH(a));
}
inline uint32_t grpc_slice_refcount::Hash(const grpc_slice& slice) {
switch (ref_type_) {
case Type::STATIC:
return ::grpc_static_metadata_hash_values[GRPC_STATIC_METADATA_INDEX(
slice)];
case Type::INTERNED:
return reinterpret_cast<grpc_core::InternedSliceRefcount*>(slice.refcount)
->hash;
case Type::REGULAR:
break;
}
return gpr_murmur_hash3(GRPC_SLICE_START_PTR(slice), GRPC_SLICE_LENGTH(slice),
g_hash_seed);
}
inline grpc_slice grpc_slice_ref_internal(const grpc_slice& slice) {
if (slice.refcount) {
slice.refcount->vtable->ref(slice.refcount);
slice.refcount->Ref();
}
return slice;
}
inline void grpc_slice_unref_internal(const grpc_slice& slice) {
if (slice.refcount) {
slice.refcount->vtable->unref(slice.refcount);
slice.refcount->Unref();
}
}

@ -133,7 +133,6 @@ void grpc_init(void) {
}
grpc_core::Fork::GlobalInit();
grpc_fork_handlers_auto_register();
gpr_arena_init();
grpc_stats_init();
grpc_slice_intern_init();
grpc_mdctx_global_init();

@ -123,7 +123,7 @@ typedef struct shutdown_tag {
typedef enum {
/* waiting for metadata */
NOT_STARTED,
/* inital metadata read, not flow controlled in yet */
/* initial metadata read, not flow controlled in yet */
PENDING,
/* flow controlled in, on completion queue */
ACTIVATED,

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save